Through the source code, I find SGI STL pop_heap() have three steps:
- put the root value into the last;
- percolate down;
- percolate up.
so pop an element at least require logN(tree's height) swap.
I wonder if it can be reduce to two steps:
- swap the root value and the last value;
- 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;
}
__pop_heap()does not do what the comments say (so something is off). Anyway I think thepop_heap()algorithm is pretty much optimized to the max as it comes directly fromTAOCP by Knuth. – Loki Astari Oct 5 '12 at 3:16swap root value and the last value– Loki Astari Oct 5 '12 at 6:09