几种排序总结(上)——堆排序
2012-10-17 17:17
197 查看
堆排序
这几天看了算法导论的排序部分,作一下总结。堆排序的优点
1)最坏情况下o(nlgn)的时间复杂度2)就地排序,不用辅助数组
几种操作(以最大堆为例)
1.保持堆性质
这是主要操作,对于节点A[i],前提是以LEFT(i)和RIGHT(i)为根的子树已经是一个排列好的堆,因此如果A[i]比他的子节点要小,对A[i]进行判断递归下沉。在最坏的情况下,对于一棵有n个节点的树,使根结点下沉至树的底部,需要比较lgn次,因此时间复杂度为o(lgn),若对应高度为h,则为o(h)
2.建堆
对于堆中的所有叶子节点来说,他们的父节点可以使用保持堆性质进行建堆,因为叶子节点本身就可以看作一棵排列好的堆。此时叶子节点以及他们的父节点都已经满足堆特性,至底向上对每个剩下的非叶子节点逐一调用保持堆性质操作直至到达根结点,建堆完成。
由于在一棵有n个节点的树中,高度为h至多有(n/2^(h+1))(取上界)个节点,对高度为h的节点使用保持堆特性算法的时间复杂度为o(h),因此有
而且
所以建堆的紧确时间复杂度为o(n)
3.堆排序
使用堆进行排序,其实就在建好的堆中取出堆顶的元素,然后将堆中最后一个元素放入堆顶部,再调用保持堆特性操作得到。将堆中元素全部取出后,就可以得到有序的排列。时间复杂度分析,第一步首先建堆需要用时o(n),第二步对大小为n的堆,取出元素放入数组尾部用时o(1),重新进行保持堆特性为o(lgn),因此o(n)+o(nlgn),总体时间时间复杂度为o(nlgn)
由于从堆顶取出元素后,会将堆中的最后一个元素放入堆顶,因此会打乱了原来数组中元素的顺序,所以堆排序是不稳定的。
4.优先级队列
优先级队列建立在堆的基础上,主要有返回最大元素/返回最大元素并取出/将第i个元素优先级增长为key/将元素x插入到优先级队列这几个操作。对于返回最大元素,直接返回最大堆堆顶即可。对于返回并取出最大元素,在返回后将最后一个堆元素放入堆顶,使堆大小减一并调用保持堆特性操作即可。对于将i元素优先级增长为key,不断比较i元素与他的父节点如果大于父节点则交换即可。对于插入元素,可以使堆大小加一,令最后一个元素为无穷小,再调用增长key操作即可。这些操作都可以在o(lgn)时间内完成。
实现代码如下:
#include<stdio.h> #include<algorithm> using namespace std; int a[100]; //保持堆特性操作 void max_heapify(int *a, int i, int len){ int l=2*i; int r=2*i+1; int largest=i; if(l<=len){ if(a[l]>a[i]) largest=l; else largest=i; } if(r<=len){ if(a[r]>a[largest]) largest=r; } if(largest!=i){ swap(a[i],a[largest]); max_heapify(a,largest,len); } } //建堆 void build_max_heap(int *a, int len){ for(int i=len/2; i>=1; i--){ max_heapify(a,i,len); } } //堆排序 void heapsort(int *a,int len){ build_max_heap(a,len); int heapsize=len; for(int i=len; i>=2; i--){ swap(a[1],a[len]); len--; max_heapify(a,1,len); } } //优先队列中返回最大元素 int heap_maximum(int *a){ return a[1]; } //优先队列中返回并去掉最大元素 int heap_extract_max(int *a,int &len){ int max = a[1]; a[1]=a[len]; len--; max_heapify(a,1,len); return max; } //将第i个元素的值增加为key void heap_increase_key(int *a,int i,int key){ if(key>a[i]){ a[i]=key; while(i>1&&a[i/2]<a[i]){ swap(a[i/2],a[i]); i=i/2; } } } //在优先队列中插入元素 void max_heap_insert(int *a,int key,int &len){ len++; a[len]=-99999999; heap_increase_key(a,len,key); } int main(){ int len=0; scanf("%d",&len); for(int j=1; j<=len; j++){ scanf("%d",&a[j]); } build_max_heap(a,len); // heapsort(a,len); // for(int i=1; i<=len; i++){ // if(i!=len) // printf("%d ",a[i]); // else // printf("%d\n",a[i]); // } max_heap_insert(a,4,len); for(int k=1; k<=len; k++){ if(k!=len) printf("%d ",a[k]); else printf("%d\n",a[k]); } printf("%d\n",heap_maximum(a)); printf("%d\n",heap_extract_max(a,len)); for(int l=1; l<=len; l++){ if(l!=len) printf("%d ",a[l]); else printf("%d\n",a[l]); } heap_increase_key(a,2,10); for(int m=1; m<=len; m++){ if(m!=len) printf("%d ",a[m]); else printf("%d\n",a[m]); } return 0; }
相关文章推荐
- Objective C中数组排序几种情况的总结
- 总结:几种常见的内部排序方法
- 七大内部排序算法总结(插入排序、希尔排序、冒泡排序、简单选择排序、快速排序、归并排序、堆排序)
- 七大内部排序算法总结(插入排序、希尔排序、冒泡排序、简单选择排序、快速排序、归并排序、堆排序)
- 各种排序总结(三)堆排序
- 基础的几种排序算法的总结 及其 解释排序的超棒效果图
- 【朝花夕拾之排序算法总结】 快速排序,堆排序总结
- Objective C中数组排序几种情况的总结
- Objective C中数组排序几种情况的总结
- 排序总结JS版(冒泡排序、简单选择排序、快速插入排序、希尔排序、堆排序、快速排序)
- Objective C中数组排序几种情况的总结
- 几种内部排序算法总结!(冒泡排序、快速排序、直接插入排序、拆半插入排序、简单选择排序)
- 七大内部排序算法总结(插入排序、希尔排序、冒泡排序、简单选择排序、快速排序、归并排序、堆排序)
- 给出几种排序总结
- 20、Objective C中数组排序几种情况的总结
- 几种冒泡(起泡)排序的总结
- (一)几种排序算法的学习总结(选择排序与插入排序)
- 【C#基础知识】之结构、数组及常用的几种排序方法总结
- 几种常用的排序算法的分析及java实现(希尔排序,堆排序,归并排序,快速排序,选择排序,插入排序,冒泡排序)
- 面试珠玑 快速排序、希尔排序、插入排序、选择排序、归并排序、堆排序总结