【问题标题】:Why my AVL Tree sorting algorithm is taking longer than insertion sort?为什么我的 AVL 树排序算法比插入排序花费更长的时间?
【发布时间】:2017-04-21 16:43:20
【问题描述】:

我正在研究 AVL 树排序算法,我想我终于弄明白了,感谢大家的帮助,直到我意识到它的运行时间比插入排序的运行时间要长得多,这不应该是正确的。我正在使用随机生成的数字的未排序数组(或更确切地说是向量)。我将在下面提供一些统计数据和代码。

AVL

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

}

N = 30,000

身高 = 17

执行的迭代次数 = ~1,730,000

排序运行时间 = 38 秒

插入排序

for (int i = 0; i < 30000; i++)
    {
        first++;
        cout << first << " first level iterations" << endl;
        time_t now = time(0);
        cout << now - begin << " seconds" << endl;
        int tmp = dataSet[i];
        int j;
        for (j = i; i > 0 && tmp < dataSet[j - 1]; j--)
        {
            dataSet[j] = dataSet[j - 1];
        }
        dataSet[j] = tmp;
    }
}

N = 30,000

迭代次数 = 30,000

排序运行时间 = 4 秒

这不可能是正确的,所以我希望也许你们都可以帮助弄清楚发生了什么?据我所知,我的所有代码都已正确实现,但我仍将包括下面的相关部分,以防我遗漏了什么。

源代码

    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;
    node* grandChild = child->rightChild;

    // perform the rotation
    child->rightChild = p;
    p->leftChild = grandChild;

    // update the height for the nodes
    p->height = max(height(p->leftChild), height(p->rightChild)) + 1;
    child->height = max(height(child->leftChild), height(child->rightChild)) + 1;

    // return new root
    return child;
}
node* leftRotate(node* p) // function to left rotate a tree rooted at p
{
    node* child = p->rightChild;
    node* grandChild = child->leftChild;

    // perform the rotation
    child->leftChild = p;
    p->rightChild = grandChild;

    // update heights
    p->height = max(height(p->leftChild), height(p->rightChild)) + 1;

    // 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*& n, int element)
{
    // perform the normal BST insertion
    if(n == NULL) // if the tree is empty
        return(newNode(element));
    if(element< n->data)
    {
        n->leftChild = insert(n->leftChild, element);
    }
    else
    {
        n->rightChild = insert(n->rightChild, element);
    }

    // update the height for this node
    n->height = 1 + max(height(n->leftChild), height(n->rightChild));

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

    // the tree is unbalanced, there are 4 different types of rotation to make
    // Single Right Rotation (Left Left Case)
    if(balance > 1 && element < n->leftChild->data)
    {
        return rightRotate(n);
    }
    // Single Left Rotation (Right Right Case)
    if(balance < -1 && element > n->rightChild->data)
    {
        return leftRotate(n);
    }
    // Left Right Rotation
    if(balance > 1 && element > n->leftChild->data)
    {
        n->leftChild = leftRotate(n->leftChild);
        return rightRotate(n);
    }
    // Right Left Rotation
    if(balance < -1 && element < n->rightChild->data)
    {
        n->rightChild = rightRotate(n->rightChild);
        return leftRotate(n);
    }
    // cout << "Height: " << n->height << endl;
    // return the unmodified root pointer in the case that the tree does not become unbalanced
    return n;
}

【问题讨论】:

  • 由于插入排序非常简单,而 AVL 树则不然,即使在尝试任何事情之前,也有理由怀疑 AVL 排序具有更高的常数因子。
  • @harold top of that 他在循环中间调用 height(root),这增加了更多的常数因子。
  • 我不确定我是否理解您的意思。你能详细说明一下吗?

标签: c++ algorithm sorting binary-search-tree avl-tree


【解决方案1】:

“调试”此类问题的最佳方法是use a performance profiler tool,但是在这种情况下,我想我可以给你一个很好的假设:

总而言之,您的比较并不“公平”。

如何“解决”这个问题?:

  • 尝试使用内存管理库,例如Boost.Pool

例如,如果您事先知道您的树将有多少个节点,您可以在算法开始时一次分配所有需要的节点,并用它们创建一个节点池(如果您使用 Boost this应该比每次调用标准的new 操作符快很多,一个接一个)。

每次您需要一个新节点时,您都​​会从池中取出它。然后,您可以从不需要额外内存分配的角度“比较”算法。

【讨论】:

  • 等等,你是说我的算法可能没有任何问题?另外,我究竟要分析它的性能是为了什么?是分配还是 CPU 使用率?还是别的什么?
  • “等等,你是说我的算法可能没有任何问题?”是的,这就是我的假设。
  • “我要分析它的性能究竟是为了什么?是分配还是 CPU 使用率?” CPU 使用率,您想查看 CPU 大部分执行时间在代码中的哪个位置。我的猜测是它将是 Node 类的构造函数或类似的东西。
  • 我将如何创建一个节点池,每次我从中拉出一个节点时,它的大小都会缩小?
  • 难道不是 node* pool[],因为你必须在声明数组之前声明数据类型?
猜你喜欢
  • 2015-09-13
  • 2018-08-30
  • 1970-01-01
  • 2020-11-04
  • 1970-01-01
  • 2016-02-18
  • 1970-01-01
  • 2016-11-23
  • 1970-01-01
相关资源
最近更新 更多