堆排序时间复杂度:O(NlogN).二叉堆:是完全二叉树。将其结点存入数组的话,任意一非叶结点位置存在以下的两种关系
1、k[i]<=k[2*i+1] && k[i]<=k[2*i+2] (小顶堆) 小顶堆堆顶关键字肯定是所有关键字中最小的
2、k[i]>=k[2*i+1] && k[i]>=k[2*i+2] (大顶堆) 大顶堆堆顶关键字肯定是所有关键字中最大的
堆排序的思想:
1、将初始待排序关键字序列(x1,x2,x3,...,Xn)构成大顶堆,此堆为初始的无序区;
2、将堆顶元素x1与最后一个元素xn交换,此时得到新的无序区(x1,x2,x3,..,Xn-1)和新的有序区(Xn) 且 Xn最大
3、由于交换后新的堆顶元素可能违反堆的性质,因此需要对当前无序区重新调整为堆,然后依次再将x1与Xn-1交换,如此重复直到有序区的个数为n-1。
1 #include<iostream>
2 #include<algorithm>
3 using namespace std;
4 //调整堆 a[]={16,7,3,20,17,8}
5 //上溯算法,将新的结点与父结点比较,如果其键值大于父结点,交换位置。如此一直上溯,直到不需要对换或到根结点为止
6 void HeapAdjust(int *a,int i,int size)
7 {
8 int lchild=2*i+1;
9 int rchild=2*i+2;
10 int max=i;
11 if(lchild<=size-1&&a[lchild]>a[max])
12 max=lchild;
13 if(rchild<=size-1&&a[rchild]>a[max])
14 max=rchild;
15 If(max!=i)
16 {
17 swap(a[i],a[max]);
18 HeapAdjust(a,max,size); //避免调整之后以max为父节点的子树不是堆
19 }
20
21 }
22 //建立堆
23 void BuildHeap(int *a,int size)
24 {
25
26 int i;
27 for(i=size/2-1;i>=0;i--)
28 {
29 HeapAdjust(a,i,size);
30
31 }
32
33 }
34
35
36 void HeapSort(int *a,int size)
37 {
38 int i;
39 BuildHeap(a,size);
40 for(i=size-1;i>=0;i--)
41 {
42 swap(a[0],a[i]);
43 HeapAdjust(a,0,i);
44 }
45 }
堆排序是不稳定的排序算法,稳定的排序算法通俗地讲就是能保证排序前2个相等的数其在序列的前后位置顺序和排序后它们两个的前后位置顺序相同。在简单形式化一下,如果Ai = Aj,Ai原来在位置前,排序后Ai还是要在Aj位置前,平均时间复杂度和最差时间复杂度都是O(NlogN),空间复杂度为O(1)