仅重新编译c ++中的一个元素

时间:2013-03-23 22:54:55

标签: c++ stl heap complexity-theory

我有一个基于vectormake_heap构建的堆。如果我改变一个(现有)元素的值,是否有O(log n)重新排序方式,或者我是否必须再次调用make_heap

1 个答案:

答案 0 :(得分:3)

如果您知道的向量已经是一个堆,如果您决定更改隐藏在堆中的插槽中的单个项目,则将堆最小化重新填充到有效堆状态的步骤涉及到以下内容:

  1. 将修改后的元素与堆中的最后一个元素交换。
  2. 从末尾开始使用交换元素执行“下推”。这涉及重复交换元素与其两个孩子中最大的一个,重复直到没有孩子离开或没有交换发生。注意:不要包括序列中的最后一个元素,它仍然是#1的修改元素。
  3. 执行最终push_heap(vec.begin(), vec.end())。这会将修改后的元素堆积到正确的位置。
  4. 起初看起来似乎很复杂,但除了#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