思路
- 堆排分两步,第一步是建立堆,第二步是进行堆排序。
- 堆的一些基本概念:
- 堆的逻辑表现方式是一颗完全二叉树。用一个数组保存元素,第一个数代表根节点,index为0。尾元素的index为
n
n
n,表示最后一个叶子节点。
- 对于任何一个非根节点的元素,若其index为
i
i
i,可知道其父节点和左右孩子节点的index。父节点的为
(
i
−
1
)
/
2
(i-1)/2
(i−1)/2,左孩子的为
2
i
+
1
2i + 1
2i+1,右孩子的为
2
i
+
2
2i+2
2i+2。
- 因为进行下滤操作的节点必须要有孩子节点,最后一个叶子节点的父节点为
(
n
−
1
)
/
2
(n-1)/2
(n−1)/2
- 建立堆的顺序是,从最后一个叶子节点的父节点开始,对前面所有的节点进行一次下滤操作。
- 堆排序:建立一个大根堆,保证堆的首元素是最大值,每次将首元素和尾元素交换位置,再将数组的大小缩小1,然后对首元素进行下滤。循环上述过程,直到堆中只剩下一个元素。
代码
#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;
void swap( int& a, int& b ) {
int temp = a;
a = b;
b = temp;
return;
}
void percolateDown( vector<int>& nums, int endIndex, int index ) {
int lastDad = ( endIndex - 1 ) >> 1;
while ( index <= lastDad ) {
int lChild = 2 * index + 1;
int rChild = lChild + 1;
int maxChild = 0;
if ( rChild > endIndex )
maxChild = lChild;
else
maxChild = nums[lChild] > nums[rChild] ? lChild : rChild;
if ( nums[index] < nums[maxChild] ) {
swap( nums[index], nums[maxChild] );
index = maxChild;
}
else break;
}
return;
}
void buildHeap( vector<int> &nums ){
int index = ( nums.size() - 2 ) >> 1;
while ( index >= 0 ) {
percolateDown( nums, nums.size() - 1, index );
--index;
}
return;
}
void heapSortCore( vector<int>& nums ) {
int endIndex = nums.size() - 1;
while ( endIndex > 0 ) {
swap( nums[0], nums[endIndex] );
--endIndex;
percolateDown( nums, endIndex, 0 );
}
}
void heapSort( vector<int>& nums ) {
buildHeap( nums );
heapSortCore( nums );
return;
}
int main() {
vector<int> input = { 2, 1, 6, 3, 9, 7, 4, 8, 5 };
heapSort( input );
for ( auto& n : input )
cout << n << " ";
return 0;
}