简体   繁体   English

AVL树实现C ++

[英]AVL Tree implementation c++

So I've posted about this recently, but I'm still at a loss for what is going wrong. 因此,我最近发布了有关此内容的信息,但是对于出了什么问题,我仍然感到茫然。 Specifically, I can't seem to figure out what's causing my AVL Tree to take so long to sort. 具体来说,我似乎无法弄清楚是什么原因导致我的AVL树需要很长时间才能排序。 I read in a file of 500,000 random, unsorted numbers to sort by using a vector in a for loop to feed the tree the numbers one at a time. 我读了一个500,000个随机,未排序的数字文件,通过在for循环中使用矢量对树进行一次排序来对它们进行排序。 Now, I've also tested using a normal BST, as someone mentioned that having to create so many nodes one at a time might be why it's taking so long, but that completed in only 5 seconds, with only 12,164 nodes skipped due to being duplicates. 现在,我还使用普通的BST进行了测试,因为有人提到一次必须创建一个如此多的节点可能是为什么它花这么长时间的原因,但它仅用5秒钟就完成了,而由于重复。 My AVL Tree is taking upwards of 3 hours just to sort half the list, so something must be going wrong. 我的AVL树需要花费3个小时以上的时间才能将列表排序一半,所以一定有问题。 Can anyone figure out what it is? 谁能知道它是什么? As far as I know, the rebalancing and insertion logic is correct, because whenever I ran a bunch of test cases on it they all came out fine. 据我所知,重新平衡和插入逻辑是正确的,因为每当我在上面运行一堆测试用例时,它们都表现良好。 I can't seem to track down where the problem is. 我似乎无法找到问题所在。 Here's my full code for anyone that wants to check it out. 这是我的完整代码,适合任何想签出的人。 Main is kind of a mess right now because of all the stuff I've included for testing purposes (like the tracking loop), but most of that will be gone in the final version. 由于我出于测试目的包括了所有内容(例如跟踪循环),因此Main现在有点混乱,但是大部分内容将在最终版本中消失。

EDIT: 编辑:

This question has been answered. 这个问题已经回答。

#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;
}

There are many problems with this code. 这段代码有很多问题。

  1. while(eof) is wrong . while(eof)是错误的
  2. The main loop expects exactly 100000 elements. 主循环期望恰好有100000个元素。
  3. All key comparisons are exact ( < , > ). 所有键比较都是精确的( <> )。 There are no rotations performed when a duplicate element is inserted. 插入重复元素时,不会执行任何旋转。 Thus a tree of identical elements will not be balanced at all. 因此,相同元素的树根本不会被平衡。
  4. The height of an empty tree is hardcoded to -1, but the height of a single-node three is initially set to 1, thus violating the invariant height(node) = 1+max(height(node->leftChild))+height(node->rightChild)) . 空树的高度被硬编码为-1,但是单节点3的高度最初设置为1,从而违反不变的height(node) = 1+max(height(node->leftChild))+height(node->rightChild))
  5. height traverses the entire tree every time it is called, thus making insertion O(n) . 每次调用height遍历整棵树,从而使插入为O(n)

So, it seems to me that the reason that it was taking so long was because of too many recursive calls all over the place. 因此,在我看来,之所以花了这么长时间是因为到处都有太多的递归调用。 This modified code has less recursive calls and thus bogs down the CPU with less stacks to have to process. 此修改后的代码具有较少的递归调用,因此使CPU陷入困境,需要处理的堆栈更少。 At least, that's what I'm getting out of this. 至少,这就是我要摆脱的。

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