1.小根堆
若根节点存在左子女则根节点的值小于左子女的值;若根节点存在右子女则根节点的值小于右子女的值。
2.大根堆
若根节点存在左子女则根节点的值大于左子女的值;若根节点存在右子女则根节点的值大于右子女的值。
3.结论
(1)堆是一棵完全二叉树(如果公有h层,那么1~h-1层均满,在h层连续缺失若干个右叶子)。
(2)小根堆的根节点的值是最小值,大根堆的根节点的值是最大值。
(3)堆适合于采用顺序存储。
4.堆的插入算法
将一个数据元素插入到堆中,使之依然成为一个堆。
算法描述:先将结点插入到堆的尾部,再将该结点逐层向上调整,直到依然构成一个堆,调整方法是看每个子树是否符合大(小)根堆的特点,不符合的话则调整叶子和根的位置。
5.堆的删除算法
堆在删除元素时,只可以删除根节点。
算法描述:将根节点删除后用堆尾结点进行填补,调整二叉树,使之依然成为一个堆。
6.堆排序(大根堆,小根堆类似)
其基本思想为(大根堆):
1)将初始待排序关键字序列(R1,R2....Rn)构建成大顶堆,此堆为初始的无序区,构建的过程是每个非叶子结点都经过一次调整,调整顺序为从底层至顶层(调整过程中含有递归),这样调整下来这个二叉树整体上就是一个大根堆(或小根堆)了;
2)将堆顶元素R[1]与最后一个元素R[n]交换,此时得到新的无序区(R1,R2,......Rn-1)和新的有序区(Rn),且满足R[1,2...n-1]<=R[n];
3)由于交换后新的堆顶R[1]可能违反堆的性质,因此需要对当前无序区(R1,R2,......Rn-1)调整为新堆,然后再次将R[1]与无序区最后一个元素交换,得到新的无序区(R1,R2....Rn-2)和新的有序区(Rn-1,Rn)。不断重复此过程直到有序区的元素个数为n-1,则整个排序过程完成。
堆排序其实也是一种选择排序,是一种树形选择排序。只不过直接选择排序中,为了从R[1...n]中选择最大记录,需比较n-1次,然后从R[1...n-2]中选择最大记录需比较n-2次。事实上这n-2次比较中有很多已经在前面的n-1次比较中已经做过,而树形选择排序恰好利用树形的特点保存了部分前面的比较结果,因此可以减少比较次数。对于n个关键字序列,最坏情况下每个节点需比较log2(n)次,因此其最坏情况下时间复杂度为nlog2(n)。堆排序为不稳定排序,不适合记录较少的排序。
关于log2(n)的理解:根据堆排序的过程,每次将大根堆根节点的值跟最后一个叶子的值进行交换,那如果最后的叶子结点正好是最小的数,那么这个叶子结点就会一层层的被放到子树最终放到叶子结点的位子(不是前面的叶子结点的位置了),这样的话这个叶子结点经过的层数就刚好为log2(n)。然而其他没有交换的二叉树的分支,因为以前都是大根堆,所以大根堆的性质还是没有变化,这一点对理解程序至关重要。
在创建的过程:
先是一个无序的数组,然后从非叶子节点开始进行调整,比较他的左右孩子,如果有比较大的替换为根节点,然后再向下比较替换了后的孩子节点,
等到完成到root节点后创建完成
输出的过程:
将顶点元素输出,一般将其和最后一个节点交换位置(注意这里堆的长度应该-1),因为别的非叶子节点仍然是满足要求的,所以只需要检查root节点是否满足要求,并进行相应的更新操作
构建大根堆,同时进行输出排序
- #include <string>
- #include <map>
- #include <iostream>
- #include <sstream>
- using namespace std;
-
- void PercDown(int A[],int i,int N)
- {
- int child = 0;
- int Tmp;
- for (Tmp = A[i]; (i*2+1)<N; i = child)
- {
- child = i*2+1;
- if (child != N-1 && A[child+1]>A[child])
- {
- child++;
- }
- if (Tmp < A[child])
- {
- A[i] = A[child];
- }
- else
- break;
- }
- A[i] = Tmp;
- }
- void main()
- {
- int A[9] = {3,8,2,7,9,26,28,54,20};
- int N = 9;
- int i;
- for (i = N/2;i >=0; i--)
- {
- PercDown(A,i,N);
- }
- for (i = N-1;i > 0; i--)
- {
- swap(A[0],A[i]);
- PercDown(A,0,i);
- }
- i = 0;
- }
类似于大根堆,完成小根堆的创建和输出
- #include <string>
- #include <map>
- #include <iostream>
- #include <sstream>
- using namespace std;
-
- void PercDown(int A[],int i,int N)
- {
- int child = 0;
- int tmp= A[i];
- for (; (i*2+1) < N; i = child)
- {
- child = 2*i+1;
- if ((child < (N-1)) && (A[child] > A[child+1]))
- {
- child++;
- }
- if (tmp > A[child])
- {
- A[i] = A[child];
- }
- else
- {
- break;
- }
- }
- A[i] = tmp;
- }
- void main()
- {
- int A[9] = {3,8,2,7,9,26,28,54,20};
- int N = 9;
- int i;
- for (i = N/2;i >=0; i--)
- {
- PercDown(A,i,N);
- }
- for (i = N-1;i > 0; i--)
- {
- swap(A[0],A[i]);
- PercDown(A,0,i);
- }
- i = 0;
- }
还有网上一些别的解法,大同小异:
-
- #include <stdio.h>
-
-
-
- void heap_ajust(int *a, int i, int size)
- {
- int lchild = 2*i+1;
- int rchild = 2*i +2;
- int max = i;
- int temp;
- if(i <= (size-1)/2)
- {
- if(lchild<size && a[lchild]>a[max])
- {
- max = lchild;
- }
- if(rchild<size && a[rchild]>a[max])
- {
- max = rchild;
- }
- if(max != i)
- {
- temp = a[i];
- a[i] = a[max];
- a[max] = temp;
- heap_ajust(a, max, size);
-
- }
- }
- }
-
- void build_bheap(int *a, int size)
- {
- int i;
- for(i=(size-1)/2; i >= 0; i--)
- {
- heap_ajust(a, i, size);
- }
- }
-
- void heap_sort(int *a, int size)
- {
- int i;
- int temp;
-
- build_bheap(a, size);
- for(i=size; i >= 1; i--)
- {
- temp = a[0];
- a[0] = a[i-1];
- a[i-1] = temp;
- heap_ajust(a, 0, i-1);
- }
- }
-
- int main(int argc, char *argv[])
- {
- int a[]={0,16,20,3,11,17,8};
- int size = sizeof(a)/sizeof(int);
- int i;
-
- printf("size = %d\n", size);
- heap_sort(a, size);
- printf("Sort over:");
- for(i=0;i < size; i++)
- printf("%d ", a[i]);
- printf("\n");
-
- return 0;
- }
源代码:(python实现)
def heap_sort(ary) :
n = len(ary)
first = int(n/2-1)
for start in range(first,-1,-1) :
max_heapify(ary,start,n-1)
for end in range(n-1,0,-1):
ary[end],ary[0] = ary[0],ary[end]
max_heapify(ary,0,end-1)
return ary
def max_heapify(ary,start,end):
root = start
while True :
child = root*2 +1
if child > end : break
if child+1 <= end and ary[child] < ary[child+1] :
child = child+1
if ary[root] < ary[child] :
ary[root],ary[child] = ary[child],ary[root]
root = child
else :
break |
原文地址:
http://wuchong.me/blog/2014/02/09/algorithm-sort-summary/
http://blog.csdn.net/xietingcandice/article/details/43412911