一. 堆排序
1. 堆:类似于完全二叉树,有a1,a2,a3, ... an,个元素,且第 2*i+1 和 2*i+2 位置的关键字都小于或大于第 i 位置的关键字。
2. 大根堆与小根堆
大根堆:堆中的所有元素都满足第 2*i+1 和 2*i+2 位置的关键字都小于第 i 位置的关键字。
小根堆:堆中的所有元素都满足第 2*i+1 和 2*i+2 位置的关键字都大于第 i 位置的关键字。
3. 堆排序:利用堆积树(堆)这种数据结构所设计的一种排序算法,它是选择排序的一种。可以利用数组的特点快速定位指定索引的元素。在数组的非降序排序中,需要使用的就是大根堆,因为根据大根堆的要求可知,最大的值一定在堆顶。
二. 原理
1. 用大根堆排序的基本思想
三. 代码实现 -- 大根堆排序
#include
using namespace std;
//一次堆调整 -- 大根堆
static heap(int* arr, int start, int end)
{
int parent = start;
int tmp = arr[parent];
for(int i=parent*2+1; i<=end; i=i*2+1)
{
if(i+1 <= end && arr[i] < arr[i+1])
{
i++;
}
if(tmp < arr[i])
{
arr[parent] = arr[i];
parent = i;
}
else
{
break;
}
}
arr[parent] = tmp;
}
//堆排序 -- 大根堆
void heapSort(int* arr, int len)
{
if(arr == NULL || len <= 0)
{
return;
}
//建立大根堆
for(int i=(len-1-1)/2; i>=0; i--)
{
heap(arr,i,len-1);
}
//一次堆调整
for(int i=0; i<len-1; i++)
{
int tmp = arr[0];
arr[0] = arr[len-1-i];
arr[len-1-i] = tmp;
heap(arr,0,len-1-1-i);
}
}
四. 时间复杂度和空间复杂度及稳定性
1. 时间复杂度
首先建立大根堆时,需要从(len-1-1)/2处不断调整,整个是线性的过程时间复杂度为O(n),然后对len-1个数据进行一次堆调整,直至无序区只剩下一个数据,这个过程的时间复杂度为O((n-1)*lgn),所以整个排序过程总的算下来为O(n*lgn)。
2. 空间复杂度
纵观整个排序过程除了局部临时变量外,未借用其它额外的空间,所以空间复杂度为O(1)。
3. 稳定性
无论是代码还是例图我们都可以看出,堆排序过程中是2*i+1 或 2*i+2 位置的关键字与 i 处的进行交换,这种跳跃式的数据交换使得此排序不稳定。