排序(堆排序)
2016-01-09 23:07
330 查看
1、什么是堆
通过上面的图片可以看出,堆其实是一棵完全二叉树。每个结点的值都大于或等于其左右两个子结点,称为大顶堆;每个结点的值小于或等于其左右子结点,称为小顶堆。既然是一个完全二叉树,堆结构自然也是严格遵守二叉树的一些规则:如果按从上至下,由左及右的层次遍历给每个结点编号,从1开始,那么编号为1的结点就是根结点,其左右子结点的编号分别为2i和2i+1。
2、堆排序算法
堆排序(Heap Sort)就是利用堆结构进行排序(假设利用大顶堆),其基本思想是先将待排序的序列构造为一个大顶堆,将其根结点(最大值)提取出来,再将剩下的待排序的子序列重新构造出一个堆,再将新堆的根结点(第二大的值)提取出来。如此反复的重构堆、提取。直到最后一个结点为止。综上所述,只需要解决两个问题,就可以完成堆排序
a、如何将一个无序的序列构造成一个堆?
b、将堆顶提取之后,如何将子序列重构为一个新的堆?
3、C语言实现
#include<stdio.h> /*交换两个数的值*/ void swap(int *a,int *b) { int temp=*a; *a=*b; *b=temp; } /*大顶堆的重构*/ void HeapAdjust(int *arr,int i,int n) { int temp,j; temp=arr[i]; for(j=i*2; j<=n; j*=2)/*从当前关键字的左右子结点向下筛选*/ { if(j<n&&arr[j]<arr[j+1]) ++j;/*记录较大值的下标*/ if(temp>=arr[j]) break;/*当寻找到合适的插入位置,停止筛选*/ arr[i]=arr[j]; i=j; } arr[i]=temp;/*插入关键字*/ } /*堆排序*/ void HeapSort(int *arr,int n) { int i; for(i=n/2; i>0; i--)/*将待排序的序列构建为一个堆*/ HeapAdjust(arr,i,n); for(i=n; i>1; i--) { swap(arr+1,arr+i);/*将堆顶元素与当前未排序的子序列中的最后一个元素交换*/ HeapAdjust(arr,1,i-1);/*交换后,将未排序的子序列重构为一个合法的堆*/ } } int main() { int arr[]= {-1,50,20,30,40,10,80,70,90,60}; int i; HeapSort(arr,9); for(i=1; i<=9; i++) printf("%d ",arr[i]); }
4、堆排序的复杂度分析
堆排序的运行时间主要消耗在初始化堆与堆重构时的反复筛选这一个过程。总体来说,堆排序的时间复杂度是O(nlogn),由于堆排序并不在意最初始的记录状态,所以无论是最好情况,最坏情况还是一般情况其时间复杂度都是O(nlogn)。空间复杂度上,它也只是利用一个临时的变量,所以其空间复杂度是O(1)。可以看出,在堆重构的过程,数据之间的比较和交换不是线性,可以这也是一个种不稳定的排序。堆排序并不适用于数量较少的序列。相关文章推荐
- 内部类详解(很详细)
- 1075. PAT Judge (25)【排序】——PAT (Advanced Level) Practise
- ImitateLogin新增插件机制以及又一个社交网站的支持
- 使用OpenCV获取图像中某一点的像素值和修改某一点的像素值
- Linux用户组与用户组基本命令
- NFS服务器配置及实验过程
- hdu 2560 buildings
- php rsa 非对称加密
- CentOS关闭防火墙
- block,inline和inline-block概念和区别
- 貌似是xp sp3解决usb键盘卡顿的问题
- js正则表达式大全(4)
- 下拉菜单得经典写法html5
- Codeforces Round #338 (Div. 2) E. Hexagons 找规律
- linux 命令mvstat的学习
- ubuntu14 make menuconfig 出错
- 54.Maximum Subarray(动态规划)
- C语言中memset函数详解
- 数组的首地址和数组的第一个元素的首地址和数组做函数参数的退化问题
- HBase 总结之 Java API 介绍