簡體   English   中英

AVL樹實現C ++

[英]AVL Tree implementation c++

因此,我最近發布了有關此內容的信息,但是對於出了什么問題,我仍然感到茫然。 具體來說,我似乎無法弄清楚是什么原因導致我的AVL樹需要很長時間才能排序。 我讀了一個500,000個隨機,未排序的數字文件,通過在for循環中使用矢量對樹進行一次排序來對它們進行排序。 現在,我還使用普通的BST進行了測試,因為有人提到一次必須創建一個如此多的節點可能是為什么它花這么長時間的原因,但它僅用5秒鍾就完成了,而由於重復。 我的AVL樹需要花費3個小時以上的時間才能將列表排序一半,所以一定有問題。 誰能知道它是什么? 據我所知,重新平衡和插入邏輯是正確的,因為每當我在上面運行一堆測試用例時,它們都表現良好。 我似乎無法找到問題所在。 這是我的完整代碼,適合任何想簽出的人。 由於我出於測試目的包括了所有內容(例如跟蹤循環),因此Main現在有點混亂,但是大部分內容將在最終版本中消失。

編輯:

這個問題已經回答。

#include <iostream>
#include<iomanip>
#include <time.h>
#include <vector>
#include <fstream>
using namespace std;

vector<int> numbers;

struct node
{
public:
    int data, height;
    node *leftChild, *rightChild;
};

node* root = NULL;

int findMin(node *p) // finds the smallest node in the tree
{
    while (p->leftChild != NULL)
        p = p->leftChild;
    return p->data;
}
int findMax(node *p) // finds the largest node in the tree
{
    while(p->rightChild != NULL)
        p = p->rightChild;
    return p->data;
}
int max(int a, int b) // gets the max of two integers
{
    if(a > b)
        return a;
    else
        return b;
}
int height(node *p) // gets the height of the tree
{
    if(p == NULL)
        return -1;
    else
    {
        p->height = max(height(p->leftChild), height(p->rightChild)) + 1;
    }
    return p->height;
}
node* newNode(int element) // helper function to return a new node with empty subtrees
{
    node* newPtr = new node;
    newPtr->data = element;
    newPtr->leftChild = NULL;
    newPtr->rightChild = NULL;
    newPtr->height = 1;
    return newPtr;
}
node* rightRotate(node* p) // function to right rotate a tree rooted at p
{
    node* child = p->leftChild; // rotate the tree
    p->leftChild = child->rightChild;
    child->rightChild = p;

    // update the height for the nodes
    p->height = height(p);
    child->height = height(child);
    // return new root
    return child;

}
node* leftRotate(node* p) // function to left rotate a tree rooted at p
{
    node* child = p->rightChild; // perform the rotation
    p->rightChild = child->leftChild;
    child->leftChild = p;

    // update the heights for the nodes
    p->height = height(p);
    child->height = height(child);

    // return new root
    return child;
}

int getBalance(node *p)
{
    if(p == NULL)
        return 0;
    else
        return height(p->leftChild) - height(p->rightChild);
}
// recursive version of BST insert to insert the element in a sub tree rooted with root
// which returns new root of subtree
node* insert(node*& p, int element)
{
    // perform the normal BST insertion
    if(p == NULL) // if the tree is empty
        return(newNode(element));
    if(element < p->data)
    {
        p->leftChild = insert(p->leftChild, element);
    }
    else
    {
        p->rightChild = insert(p->rightChild, element);
    }

    // update the height for this node
    p->height = height(p);

    // get the balance factor to see if the tree is unbalanced
    int balance = getBalance(p);

    // the tree is unbalanced, there are 4 different types of rotation to make

    // Single Right Rotation (Left Left Case)
    if(balance > 1 && element < p->leftChild->data)
    {
        return rightRotate(p);
    }
    // Single Left Rotation (Right Right Case)
    if(balance < -1 && element > p->rightChild->data)
    {
        return leftRotate(p);
    }
    // Left Right Rotation (double left rotation)
    if(balance > 1 && element > p->leftChild->data)
    {
        p->leftChild = leftRotate(p->leftChild);
        return rightRotate(p);
    }
    // Right Left Rotation
    if(balance < -1 && element < p->rightChild->data)
    {
        p->rightChild = rightRotate(p->rightChild);
        return leftRotate(p);
    }
    // cout << "Height: " << n->height << endl;
    // return the unmodified root pointer in the case that the tree does not become unbalanced
    return p;
}
void inorder(node *p)
{
    if(p != NULL)
    {
        inorder(p->leftChild);
        cout << p->data << ", ";
        inorder(p->rightChild);
    }
}
void preorder(node *p)
{
    if(p != NULL)
    {
        cout << p->data << ", ";
        preorder(p->leftChild);
        preorder(p->rightChild);
    }
}

void print(node* root)
{
    /*cout << "Min Value: " << findMin(root) << endl;
    cout << "Max Value: " << findMax(root) << endl;
    cout << "Pre Order: ";
    preorder(root); */
    cout << endl << "Inorder: ";
    inorder(root);
    cout << endl << endl << endl << endl;

}

void read()
{
    int num;
    ifstream file_save("data.txt");
    if(file_save.is_open())
    {
        while(!file_save.eof())
        {
            file_save >> num;
            numbers.push_back(num);
        }
        file_save.close();
    }
    else
    {
        cout << "Error in opening file!!" << endl;
    }
}

int main()
{
    double duration;
    time_t begin = time(0);

    read();
    int x = 0;
    int track = 0;
    for (std::vector<int>::const_iterator i = numbers.begin(); i != numbers.begin() + 100000; ++i)
    {
        root = insert(root, numbers[x]);
        x++;
        track++;
        if( (track % 10000) == 0)
        {
            cout << track << " iterations" << endl;
            time_t now = time(0);
            cout << now - begin << " seconds" << endl;
        }

    }
    time_t end = time(0);
    duration = end - begin;
    // print(root);
    cout << "The algorithm took " << duration << " seconds to complete." << endl;
    return 0;
}

這段代碼有很多問題。

  1. while(eof)是錯誤的
  2. 主循環期望恰好有100000個元素。
  3. 所有鍵比較都是精確的( <> )。 插入重復元素時,不會執行任何旋轉。 因此,相同元素的樹根本不會被平衡。
  4. 空樹的高度被硬編碼為-1,但是單節點3的高度最初設置為1,從而違反不變的height(node) = 1+max(height(node->leftChild))+height(node->rightChild))
  5. 每次調用height遍歷整棵樹,從而使插入為O(n)

因此,在我看來,之所以花了這么長時間是因為到處都有太多的遞歸調用。 此修改后的代碼具有較少的遞歸調用,因此使CPU陷入困境,需要處理的堆棧更少。 至少,這就是我要擺脫的。

void newHeight(node* p)
{
    double leftHeight = height(p->leftChild);
    double rightHeight = height(p->rightChild);
    if(leftHeight > rightHeight)
        p->height = leftHeight;
    else
        p->height = rightHeight;
}

node* rotateright(node* p) // the right rotation round p
{
    node* q = p->leftChild;
    p->leftChild = q->rightChild;
    q->rightChild = p;
    newHeight(p);
    newHeight(q);
    return q;
}

node* rotateleft(node* q) // the left rotation round q
{
    node* p = q->rightChild;
    q->rightChild = p->leftChild;
    p->leftChild = q;
    newHeight(q);
    newHeight(p);
    return p;
}

node* rebalance(node* p) // p node balance
{
    newHeight(p);
    if( getBalance(p)==2 )
    {
        if( getBalance(p->rightChild) < 0 )
            p->rightChild = rotateright(p->rightChild);
        return rotateleft(p);
    }
    if (getBalance(p)==-2 )
    {
        if( getBalance(p->leftChild) > 0  )
            p->leftChild = rotateleft(p->leftChild);
        return rotateright(p);
    }
    return p; // no balance needed
}

node* insert(node* p, int element) // k key insertion in the tree with p root
{
    if(!p) return newNode(element);
    if(element < p->data)
        p->leftChild = insert(p->leftChild, element);
    else
        p->rightChild = insert(p->rightChild, element);
    return rebalance(p);
}

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM