1.Sift-up函数 假定对于某个i>1 A[i]的键值大于父亲节点的键值 此时A[i]的辈分就高了 也就是需要向上调整A[i] 让原来A[i]的父亲下来当儿子
int Siftup(int *A,int i) { int temp=A[i]; while(i>=2&&temp>A[i/2]) { A[i]=A[i/2]; i=i/2; } A[i]=temp; }
该过程类似于 插入排序 为每一个A[i]确定合适位置 其余的往后移
2.Sift-down函数 假定对于某个父亲节点i A[i]的键值小于了孩子节点的键值 此时就需要向下调整这个父亲节点,降低它的辈分
int Siftdown(int *A,int i,int length) { int temp=A[i]; int j; while(2*i<=length) { if(2*i+1<=length&&A[2*i+1]>A[2*i]) j=2*i+1; else j=2*i; if(temp<A[j]) A[i]=A[j]; else break; i=j; } A[i]=temp; }
解释:1.函数参数有三个 分别是数组A 要调整的节点i 数组A的大小
2.while循环条件是 该节点非叶节点,也就是有子节点,也就是该节点有左子树
3.Insert插入函数
int Insert(int* A,int x,int* length) { (*length)++ A[*length]=x; Siftup(A,*length); }
4.Delete删除函数
int Delete(int* A,int i,int *length) { int x=A[i]; int y=A[*length]; (*length)--; A[i]=y;//用y替换它 if(y>x) Siftup(A,i); else Siftdown(A,i,*length); }
思路是用 堆中最后一个元素替换要删除的节点i ,替换之后产生的结果是,节点i处可能不再符合堆的定义,而除了节点i以外仍旧为堆。因此,此时需要调整,调整的情况有两种,如果y大于x,那么需要向上调整,看看是否辈分会提高;如果y小于x,那么需要向下调整,看看是否会降低辈分。
5.创建堆
int Makeheap(int* A,int length) { for(int i=length/2;i>=1;i--) { Siftdown(A,i,length); } }
创建堆的过程,是从第一个非叶子节点,向下调整。 如果令C(n)表示该算法的元素比较次数,则比较次数范围是在[n-1,4n) 也就是 sitar(n)的时间内完成了堆的创建。
6.堆排序
int HeapSort(int *A,int length) { Makeheap(A,length); for(int i=length;i>=2;i--) { int temp; temp=A[i]; A[i]=A[1]; A[1]=temp; length=length-1; Siftdown(A,1,length); }
该过程首先建堆,此时A【1】即为最大值,与最后一个元素交换,即确定了最大元素的值;然后该元素就不用再管它了;因为咱们是与第一个元素进行了交换,所以第一个元素可能不再符合堆的定义,而其它节点仍旧符合堆的定义,所以,我们采用Siftdown调整A【1】使其仍然为堆;调整为堆后的A【1】又变成了新的堆的最大值,再重复上述操作:交换、调整A【1】使其仍然为堆……
使用makeheap是在sitar(n)范围内的算法,for循环一共进行了 length-1次,每次for循环内部都会进行Siftdown操作,Siftdown操作是O(logn)级别的。因此,该算法时间复杂度为O(nlogn)