在c++中只重新堆一个元素

Reheaping only one element in c++

本文关键字:新堆一 元素 c++      更新时间:2023-10-16

我有一个在vectormake_heap上构建的堆。如果我只改变一个(现有的)元素的值,是否有O(log n)的方法来重新堆积,或者我必须再次调用make_heap ?

给定一个知道已经是堆的向量,如果您决定更改堆中隐藏的插槽中的单个项,则将堆最小程度地重新填充到有效堆状态的步骤包括以下步骤:

  1. 将修改后的元素与堆中最后一个元素交换。
  2. 对从末尾插入的元素执行"下推"操作。这涉及到与它的两个子元素中最大的元素重复交换,直到没有子元素剩余或没有交换发生。注意:不要包括序列中的最后一个元素,它仍然是你从#1修改的元素。
  3. 执行最后一次push_heap(vec.begin(), vec.end())。这会将修改后的元素堆积到正确的位置。

乍一看可能很复杂,但除了#2中的步骤之外,这里没有什么特别的。其余的只是您可能熟悉的常规堆操作。我希望这是有意义的。

样例代码

这是一个可能的实现。显然,您的需求可能会有所不同。我只是把这些放在一起,所以我希望它至少有一点指导意义:

#include <iostream>
#include <algorithm>
#include <iterator>
#include <vector>
using namespace std;
int main()
{
    // intialize random generator
    srand((unsigned)time(0));
    // will hold our heap
    vector<int> vec;
    for (int i=0;i<20;vec.push_back(++i));
    random_shuffle(vec.begin(), vec.end());
    cout << "Rand: ";
    copy(vec.begin(), vec.end(), ostream_iterator<int>(cout, " "));
    cout << endl;
    // make a maxheap
    less<int> cmp;
    make_heap(vec.begin(), vec.end(), cmp);
    // dump content to stdout
    cout << "Heap: ";
    copy(vec.begin(), vec.end(), ostream_iterator<int>(cout, " "));
    cout << endl;
    // pick an item in the heap to modify, for our purposes, vec[1]
    vector<int>::iterator it = vec.begin()+1;
    *it *=2;
    // swap with the last element, then push-down the swapped-in element
    //  until we find its rightful home.
    iter_swap(it, vec.end()-1);
    while (distance(it, vec.end()) > 1)
    {
        // leave if no more children
        size_t i = distance(vec.begin(), it);
        if (2*i+1 >= vec.size()-1)
            break;
        // have one child. might have two
        vector<int>::iterator itChild = vec.begin() + 2*i+1;
        if (itChild+1 < vec.end()-1)
        {
            if (cmp(*itChild, *(itChild+1)))
                itChild = itChild+1;
        }
        // no need to swap; we're done.
        if (!cmp(*it, *itChild))
            break;
        // dump "before" picture
        cout << " beg: ";
        copy(vec.begin(), vec.end(), ostream_iterator<int>(cout, " "));
        cout << endl;
        // swap values and move to swapped child.
        iter_swap(it, itChild);
        it = itChild;
        // dump "after" picture
        cout << " end: ";
        copy(vec.begin(), vec.end(), ostream_iterator<int>(cout, " "));
        cout << endl;
    }
    // now push_heap our new value, which is still hanging out
    //  at the end where we left it.
    push_heap(vec.begin(), vec.end(), cmp);
    // final dump        
    cout << "Last: ";
    copy(vec.begin(), vec.end(), ostream_iterator<int>(cout, " "));
    cout << endl;
    // verify make_heap likes what we made (should be the same).
    make_heap(vec.begin(), vec.end(), cmp);
    cout << "Heap: ";
    copy(vec.begin(), vec.end(), ostream_iterator<int>(cout, " "));
    cout << endl;    
    return EXIT_SUCCESS;
}

Rand: 15 14 8 5 1 17 10 13 3 20 11 19 6 4 9 2 18 7 12 16 
Heap: 20 18 19 17 16 15 10 13 12 14 11 8 6 4 9 2 5 3 7 1 
 beg: 20 1 19 17 16 15 10 13 12 14 11 8 6 4 9 2 5 3 7 36 
 end: 20 17 19 1 16 15 10 13 12 14 11 8 6 4 9 2 5 3 7 36 
 beg: 20 17 19 1 16 15 10 13 12 14 11 8 6 4 9 2 5 3 7 36 
 end: 20 17 19 13 16 15 10 1 12 14 11 8 6 4 9 2 5 3 7 36 
 beg: 20 17 19 13 16 15 10 1 12 14 11 8 6 4 9 2 5 3 7 36 
 end: 20 17 19 13 16 15 10 5 12 14 11 8 6 4 9 2 1 3 7 36 
Last: 36 20 19 13 17 15 10 5 12 16 11 8 6 4 9 2 1 3 7 14 
Heap: 36 20 19 13 17 15 10 5 12 16 11 8 6 4 9 2 1 3 7 14