堆排序
1、什么是堆?
堆实际上是一棵完全二叉树,任何一个父节点都大于其左右两个子树(如果有子树的话)。完全二叉树的性质还包括了父节点与直接子节点的关系。Index(父)=[Index(子)-1]/2
最大堆:Key[i]>=Key[2i+1]&&key>=key[2i+2];堆顶关键字最大。
最小堆:Key[i]<=key[2i+1]&&Key[i]<=key[2i+2];对顶关键字最小。
2.堆排序的思想
利用大顶堆(小顶堆)堆顶记录的是最大关键字(最小关键字)这一特性,使得每次从无序中选择最大记录(最小记录)变得简单。
下面举例说明,用最大堆为例:
给定一个整形数组a[]={16,7,3,20,17,8},对其进行堆排序。
首先根据该数组元素构建一个完全二叉树,得到(旁边的数字为下标)
然后需要构造初始堆,则从最后一个非叶节点(下标为2的8不用调整,满足最大堆的条件)开始调整,调整过程如下:
20和16交换后导致16不满足堆的性质,因此需继续调整,这也是堆的下调过程。
这样就得到了初始堆。
即每次调整都是从父节点、左孩子节点、右孩子节点三者中选择最大者跟父节点进行交换,交换之后可能造成被交换的孩子节点不满足堆的性质,因此每次交换之后要继续对被交换的孩子节点进行调整。有了初始堆之后就可以进行排序了。
排序过程:
1、 取出堆顶元素
2、 堆顶 用最后一位元素代替堆,堆的大小减一,然后下调堆顶元素。
3、 重复1、2。
C++:
#include<iostream>
namespace mySort
{
//下调函数,请仔细阅读,即可理解。
void AdjustDown(int *data, int r, int j)
{
int child = 2 * r + 1;
int temp = data[r];
while (child <= j)
{
if ((child<j) &&(data[child + 1]>data[child]))
child++;
if (temp >= data[child])
break;
data[(child - 1) / 2] =data[child];
child = child * 2 + 1;
}
data[(child - 1) / 2] = temp;
}
void heapSort(int * data, int n)
{
for (int i = (n - 2) / 2; i >= 0;--i)
mySort:: AdjustDown(data,i, n-1);
for (int i = n - 1; i > 0; --i)
{
std::swap(data[0], data[i]);
mySort::AdjustDown(data, 0,i-1);
}
}
};
int main()
{
int a[] = { 3, 1 };
int len = sizeof(a) / sizeof(int);
mySort::heapSort(a,len);
return 0;
}
总结:
从上述过程可知,是一种树形选择排序。对于n个关键字序列,最坏情况下每个节点需比较log2(n)次,因此其最坏情况下时间复杂度为n*(log(n))。堆排序为不稳定排序,不适合记录较少的排序。

浙公网安备 33010602011771号