堆排序算法原理:
1.堆排序说明:堆排序(Heapsort)是指利用堆积树(堆)这种数据结构所设计的一种排序算法,它是选择排序的一种。可以利用数组的特点快速定位指定的索引元素。堆分为大根堆和小根堆,是完全二叉树。大根堆要求每个节点的值都不大于其父节点的值。在数组的非降序排序中,使用的就是大根堆,因为根据大根堆的要求可知,最大的值一定是在堆顶。
2.算法描述:(建堆 -》调整堆 -》堆排序)
①将初始待排序关键字序列(R1 R2 R3 R4.......Rn)构建成大顶堆,次堆为初始的无序区(只满足大顶堆的要求)
②将堆顶元素R[1]和最后一个元素R[N]进行交换,此时得到新的无序区(R1R2R3..Rn)和新的有序区R[N],且满足有序区域的数据都是大于无序区中的
③由于交换后新的堆顶R[1]可能违反大根堆的性质,因此需要将无序区(R1 R2....Rn-1)调整为新堆,然后再次将R[1]和无序区最后一个元素交换,得到新的无序区(R1 R2 R3.. Rn-2)和新的有序区。不断重复此过程,直至整个排序完成。
动图演示
代码解析:
/*.............................
filename : heapsort.c
create time :2018-10-7
E-mail :1564676944@qq.com
.............................*/
#include<assert.h>
#include<iostream>
using namespace std;
void swap(int* a,int* b)
{
int temp = *a;
*a = *b;
*b = temp;
}
void FilerDown(int* arr,int start,int end)
{
assert(arr != NULL);
int i = start;
int j = 2*i +1;
int tmp = arr[i];
while(j<=end)
{
if(j+1<=end && arr[j+1]>arr[j])
{
j += 1;
}
if(tmp < arr[j])
{
arr[i] = arr[j];
i = j;
j = j*2+1;
}
else
break;
}
arr[i] = tmp;
}
void make_heap(int* arr,int len)
{
assert(arr != NULL);
int end = len - 1;
int pos = (end -1)/2;
while(pos >= 0)
{
FilerDown(arr,pos,end);
--pos;
}
}
void heap_sort(int* arr,int len)
{
assert(arr != NULL);
int end = len -1;
make_heap(arr,len);
for(int i = end;i>0;--i)
{
swap(&arr[0],&arr[i]);
FilerDown(arr,0,i-1);
}
}
void print(int* arr,int len)
{
for(int i = 0;i < len;++i)
{
cout<<arr[i]<<" ";
}
cout<<endl;
}
int main()
{
int arr[] = {12,56,34,59,78,9,99,15,46,32,56};
int len = sizeof(arr)/sizeof(arr[0]);
heap_sort(arr,len);
print(arr,len);
return 0;
}
效率分析:
堆排序和直接选择排序相反:在任何时间堆排序中无序区域总是在有序区域之前,且有序区域是在原向量的尾部有后往前逐步扩大至整个向量。
堆排序的时间,主要是在建立初始堆,和反复重建堆这两部分的时间开销构成,平均时间复杂度O(N*logN)(最坏最优都是)。
由于建立初始堆所需要的比较次数较多,所以堆排序不适宜于记录数较小的文件。空间复杂度为O(1)
算法稳定性:
它是不稳定的排序方法。会发生跳跃性的交换。