堆排序:
不稳定排序:
9
/ \
8 -----> 大根堆去掉根9
/ \ / \
5 2 1
8
/ \
\ / \
5 2 1
可以发现此时两个7的相对顺序发生了改变
#include <iostream>
#include <vector>
#include <string>
#include <sstream>
using namespace std;
/* high */
/* / \ */
/* / \ */
/* / \ */
/* 2*high 2*high+1 */
/* */
/* */
template<typename T>
void insert(vector<T> &v, T current, int high, int Index_Of_Last_Entry)
{
int low = 2 * high + 1;
while(low <= Index_Of_Last_Entry)
{
if(low + 1 <= Index_Of_Last_Entry && v[low + 1] > v[low])
low++;
if(v[low] < current)
break;
v[high] = v[low];
high = low;
low = 2 * high + 1;
}
v[high] = current;
}
template<typename T>
void build(vector<T> &v, int n)
{
for(int i = n/2-1; i >= 0; i--)
{
T current = v[i];
insert(v, current, i, n - 1);
}
}
template<typename T>
void heap_sort(vector<T> &v, int n){
if(n > 1){
build(v, n);
T current;
int last_unsorted;
for(last_unsorted = n - 1; last_unsorted > 0; last_unsorted--){
current = v[last_unsorted];
v[last_unsorted] = v[0];
insert(v, current, 0, last_unsorted - 1);
}
}
}
template <typename T>
string ConvertToString(T );
int main()
{
vector<int> v;
for(int i = 0; i < 100; i++) v.push_back(i);
heap_sort(v, v.size());
for(int i = 0; i < 100; i++)
cout << v[i] << endl;
return 0;
}
template <typename T>
string ConvertToString(T value) {
stringstream ss;
ss << value;
return ss.str();
}
调整堆(insert)的算法是O(logn),也就是跟树高logn有关。这里的insert方法其实就是自上而下的调整(参考《编程珠玑》堆的章节的siftdown方法)。
建堆的算法(build)最外层循环是O(n)的,每次循环中调用调整堆的算法时每个树的高度都较小,因此在数学上可以证明建堆的算法也是O(n)的。我这里建堆的build方法,是从倒数第二层开始,保证以当前节点i开始的二叉树是一个堆,即[i, n)是一个堆,调整过程使用的还是siftdown的方法。当然建堆还可以从上往下开始,保证[0, i]是一个堆,此时可以使用siftup方法来调整,具体代码可以参见《编程珠玑》。