Tell me more ×
Code Review Stack Exchange is a question and answer site for peer programmer code reviews. It's 100% free, no registration required.

Through the source code, I find SGI STL pop_heap() have three steps:

  1. put the root value into the last;
  2. percolate down;
  3. percolate up.

so pop an element at least require logN(tree's height) swap.

I wonder if it can be reduce to two steps:

  1. swap the root value and the last value;
  2. percolate down.

so pop an element at most require logN(tree's height) swap.

Watch my code and give me your comments. Thank you!

SGI Source Code:

template <class RandomAccessIterator>
inline void pop_heap(RandomAccessIterator first, RandomAccessIterator last) {
    __pop_heap_aux(first, last, value_type(first));
}

template <class RandomAccessIterator, class T>
inline void __pop_heap_aux(RandomAccessIterator first,
    RandomAccessIterator last, T*) {
    __pop_heap(first, last - 1, last - 1, T(*(last - 1)), distance_type(first));
}

template <class RandomAccessIterator, class T, class Distance>
inline void __pop_heap(RandomAccessIterator first, RandomAccessIterator last,
    RandomAccessIterator result, T value, Distance*) {
    *result = *first; // 1. put the root value into the last
    __adjust_heap(first, Distance(0), Distance(last - first), value);
}

template <class RandomAccessIterator, class Distance, class T>
void __adjust_heap(RandomAccessIterator first, Distance holeIndex,
    Distance len, T value) {
    // 2. percolate down
    Distance topIndex = holeIndex;
    Distance secondChild = 2 * holeIndex + 2;
    while (secondChild < len) {
        if (*(first + secondChild) < *(first + (secondChild - 1)))
            secondChild--;
        *(first + holeIndex) = *(first + secondChild);
        holeIndex = secondChild;
        secondChild = 2 * (secondChild + 1);
    }
    if (secondChild == len) {
        *(first + holeIndex) = *(first + (secondChild - 1));
        holeIndex = secondChild - 1;
    }
    // 3. percolate up
    __push_heap(first, holeIndex, topIndex, value);
}

template <class RandomAccessIterator, class Distance, class T>
void __push_heap(RandomAccessIterator first, Distance holeIndex,
    Distance topIndex, T value) {
    Distance parent = (holeIndex - 1) / 2;
    while (holeIndex > topIndex && *(first + parent) < value) {
        *(first + holeIndex) = *(first + parent);
        holeIndex = parent;
        parent = (holeIndex - 1) / 2;
    }    
    *(first + holeIndex) = value;
}

Modified:

template <class RandomAccessIterator>
inline void pop_heap(RandomAccessIterator first, RandomAccessIterator last) {
    __pop_heap_aux(first, last, value_type(first));
}

template <class RandomAccessIterator, class T>
inline void __pop_heap_aux(RandomAccessIterator first,
    RandomAccessIterator last, T*) {
    __pop_heap(first, last - 1, last - 1, T(*(last - 1)), distance_type(first));
}

template <class RandomAccessIterator, class T, class Distance>
inline void __pop_heap(RandomAccessIterator first, RandomAccessIterator last,
    RandomAccessIterator result, T value, Distance*) {
    // 1. swap the root value and the last value
    *result = *first; 
    *first = value;
    __adjust_heap(first, Distance(0), Distance(last - first), value);
}

template <class RandomAccessIterator, class Distance, class T>
void __adjust_heap(RandomAccessIterator first, Distance holeIndex,
    Distance len, T value) {
    // 2. percolate down
    Distance topIndex = holeIndex;
    Distance secondChild = 2 * holeIndex + 2;
    while (secondChild < len) {
        if (*(first + secondChild) < *(first + (secondChild - 1)))
            secondChild--;
        if (*(first + secondChild) > value)              
            *(first + holeIndex) = *(first + secondChild);
        else
            break;
        holeIndex = secondChild;
        secondChild = 2 * (secondChild + 1);
    }
    if (secondChild == len && *(first + secondChild) > value) {
        *(first + holeIndex) = *(first + (secondChild - 1));
        holeIndex = secondChild - 1;
    }
    *(first + holeIndex) = value;
}
share|improve this question
Don't use double underscore in your identifiers: What are the rules about using an underscore in a C++ identifier? – Loki Astari Oct 5 '12 at 2:39
I don't think you have tested this. I am relatively sure it does not work. The code in __pop_heap() does not do what the comments say (so something is off). Anyway I think the pop_heap() algorithm is pretty much optimized to the max as it comes directly from TAOCP by Knuth. – Loki Astari Oct 5 '12 at 3:16
Thank you for your comment. yes, i'm not tested it, but i wrote a heap sort like this and tested well.As you said:"The code in __pop_heap() does not do what the comments say (so something is off)." why? Can you give me a clearly explanation. – newhand_liu Oct 5 '12 at 5:42
It does not: swap root value and the last value – Loki Astari Oct 5 '12 at 6:09

Know someone who can answer? Share a link to this question via email, Google+, Twitter, or Facebook.

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Browse other questions tagged or ask your own question.