排序系列算法——堆排序
2016-01-18 20:25
204 查看
堆:大根堆与小根堆
堆排序是建立在堆基础上的排序方法,首先了解一下什么是堆。
常用的堆一般有两种,大根堆和小根堆。堆可以看做是一棵二叉树,其父节点的值总是大于(大根堆)或者小于(小根堆)子节点的值。举一个例子:
图1 不满足堆的条件 图2大根堆 图3 小根堆
图1不是堆,因为不满足父节点的值大于或者小于子节点的值;
图2是大根堆,根节点是最大值,父节点都大于或等于子节点的值;
图3是小根堆,根节点是最小值,父节点都小于或等于子节点的值。
堆排序
下面以大根堆为例讲解堆排序:
大根堆有一个很好的性质,根节点的数值总是大于其他所有节点的数值,利用这个性质,可以实现排序的工作。堆排序的步骤可以描述如下:
1.构建大根堆。首先我们的原始数组一般情况下是不满足堆的条件,既然我们要可用大根段的性质进行排序,第一步当然是对原始数组进行处理,构建大根堆。
2.根节点数据处理以及大根堆重构。构建了大根堆之后,根节点的数据是最大值,将该数值取出,对剩下的元素重构大根堆,这时根节点是剩下元素的最大值,取出。只要不断重复上述的操作,不断取出未排序元素的最大值,直到未排序的元素只剩一个,就完成了排序工作。
说得有点抽象,直接用一个实际的例子说明堆排序的工作步骤:
对一个无序的序列A={5,4,17,13,15,12,10 }按从小到大进行排序,序列的下标分别为{1,2,3,4,5,6,7},A[i]表示下标为i的元素。
第一步:对无序的数组构造大根堆
大根堆的根节点是整个序列的最大值。
第二步:
将A[1]与A[7]互换,此时A[7]为序列的最大值,A[7]已经排序完毕,剩余的元素A[1]~A[6]形成新的未排序序列,由于此时序列不是大根堆,需要重构大根堆。
第三步:
将A[1]与A[6]互换,此时A[6]为序列的最大值,A[6]已经排序完毕,剩余的元素A[1]~A[5]形成新的未排序序列,由于此时序列不是大根堆,需要重构大根堆。
第四步:
将A[1]与A[5]互换,此时A[5]为序列的最大值,A[5]已经排序完毕,剩余的元素A[1]~A[4]形成新的未排序序列,由于此时序列不是大根堆,需要重构大根堆。
第五步:
将A[1]与A[4]互换,此时A[4]为序列的最大值,A[4]已经排序完毕,剩余的元素A[1]~A[3]形成新的未排序序列,由于此时序列不是大根堆,需要重构大根堆。
第六步:
将A[1]与A[3]互换,此时A[3]为序列的最大值,A[3]已经排序完毕,由于此时未排序的序列只剩下两个元素,而且A[0]>A[1],将A[0]与A[1]互换即可得到最终的已排序序列。
C++程序实现
从上述的排序过程可知,堆排序主要有两个过程,大根堆的构建与重构:
1、大根堆的重构
如何实现大根堆的重构?如果一个原有的数组满足大根堆的性质,而只有其中一个元素改变从而破坏了大根堆的性质,那么可以从该元素出发,不断”逐级下降“,让子节点小于等于父子节点,满足大根堆的性质。以一个实例说明重构的过程:
堆排序的过程中,每一次改变的只有根节点的元素,因此只需要从根节点出发,进行如上图的操作即可实现大根堆的重构。C++代码如下:
1、 构建大根堆。
要构建大根堆,只需要遍历所有非叶子节点元素,使其所有的叶子节点均不大于足该节点元素即可。构建大根堆自低向上对数组进行遍历,如果发现父节点的值小于子节点的值,则将父节点的值与子节点的最大值进行交换,保证父节点的数据总是大于子节点的数据。如果发生了数据的交换,有可能令子节点不满足大根堆条件,需要进行会输重构大根堆。以一个实际的例子说明构建大根堆的过程:
C++代码如下:
全部源代码:
堆排序是建立在堆基础上的排序方法,首先了解一下什么是堆。
常用的堆一般有两种,大根堆和小根堆。堆可以看做是一棵二叉树,其父节点的值总是大于(大根堆)或者小于(小根堆)子节点的值。举一个例子:
图1 不满足堆的条件 图2大根堆 图3 小根堆
图1不是堆,因为不满足父节点的值大于或者小于子节点的值;
图2是大根堆,根节点是最大值,父节点都大于或等于子节点的值;
图3是小根堆,根节点是最小值,父节点都小于或等于子节点的值。
堆排序
下面以大根堆为例讲解堆排序:
大根堆有一个很好的性质,根节点的数值总是大于其他所有节点的数值,利用这个性质,可以实现排序的工作。堆排序的步骤可以描述如下:
1.构建大根堆。首先我们的原始数组一般情况下是不满足堆的条件,既然我们要可用大根段的性质进行排序,第一步当然是对原始数组进行处理,构建大根堆。
2.根节点数据处理以及大根堆重构。构建了大根堆之后,根节点的数据是最大值,将该数值取出,对剩下的元素重构大根堆,这时根节点是剩下元素的最大值,取出。只要不断重复上述的操作,不断取出未排序元素的最大值,直到未排序的元素只剩一个,就完成了排序工作。
说得有点抽象,直接用一个实际的例子说明堆排序的工作步骤:
对一个无序的序列A={5,4,17,13,15,12,10 }按从小到大进行排序,序列的下标分别为{1,2,3,4,5,6,7},A[i]表示下标为i的元素。
第一步:对无序的数组构造大根堆
大根堆的根节点是整个序列的最大值。
第二步:
将A[1]与A[7]互换,此时A[7]为序列的最大值,A[7]已经排序完毕,剩余的元素A[1]~A[6]形成新的未排序序列,由于此时序列不是大根堆,需要重构大根堆。
第三步:
将A[1]与A[6]互换,此时A[6]为序列的最大值,A[6]已经排序完毕,剩余的元素A[1]~A[5]形成新的未排序序列,由于此时序列不是大根堆,需要重构大根堆。
第四步:
将A[1]与A[5]互换,此时A[5]为序列的最大值,A[5]已经排序完毕,剩余的元素A[1]~A[4]形成新的未排序序列,由于此时序列不是大根堆,需要重构大根堆。
第五步:
将A[1]与A[4]互换,此时A[4]为序列的最大值,A[4]已经排序完毕,剩余的元素A[1]~A[3]形成新的未排序序列,由于此时序列不是大根堆,需要重构大根堆。
第六步:
将A[1]与A[3]互换,此时A[3]为序列的最大值,A[3]已经排序完毕,由于此时未排序的序列只剩下两个元素,而且A[0]>A[1],将A[0]与A[1]互换即可得到最终的已排序序列。
C++程序实现
从上述的排序过程可知,堆排序主要有两个过程,大根堆的构建与重构:
1、大根堆的重构
如何实现大根堆的重构?如果一个原有的数组满足大根堆的性质,而只有其中一个元素改变从而破坏了大根堆的性质,那么可以从该元素出发,不断”逐级下降“,让子节点小于等于父子节点,满足大根堆的性质。以一个实例说明重构的过程:
堆排序的过程中,每一次改变的只有根节点的元素,因此只需要从根节点出发,进行如上图的操作即可实现大根堆的重构。C++代码如下:
void ReBuildMaxHeap(int *array,int arraylength,int startIndex){ int index=0; //int j=0; int max=0; while((2*startIndex+1)<arraylength){ index = startIndex; max = array[index]; if(max<(array[2*startIndex+1])){ max=array[2*startIndex+1]; index=2*startIndex+1; } if(2*startIndex+2<arraylength&&max<array[2*startIndex+2]){ max=array[2*startIndex+2]; index=2*startIndex+2; } if(index==startIndex){ break; } swap(array,index,startIndex); startIndex = index; } }
1、 构建大根堆。
要构建大根堆,只需要遍历所有非叶子节点元素,使其所有的叶子节点均不大于足该节点元素即可。构建大根堆自低向上对数组进行遍历,如果发现父节点的值小于子节点的值,则将父节点的值与子节点的最大值进行交换,保证父节点的数据总是大于子节点的数据。如果发生了数据的交换,有可能令子节点不满足大根堆条件,需要进行会输重构大根堆。以一个实际的例子说明构建大根堆的过程:
C++代码如下:
void createHeap(int *array,int length){ int max=0; int index=0; for(int i=floor(length/2)-1;i>=0;i--){ index = i; max = array[i]; if(max<array[2*i+1]){ index=2*i+1; max = array[2*i+1]; } if(2*i+2<length&&max<array[2*i+2]){ index = 2*i+2; max = array[2*i+2]; } if(index!=i){ swap(array,index,i); ReBuildMaxValue(array,length,index); } } }
全部源代码:
#include "stdafx.h" #include <iostream> using namespace std; //两个文位置的数据交换 void swap(int *array,int num1,int num2){ int temp = *(array+num1); *(array+num1) = *(array+num2); *(array+num2) = temp; } //重构大根堆 void ReBuildMaxValue(int *array,int arraylength,int startIndex){ int index=0; //int j=0; int max=0; while((2*startIndex+1)<arraylength){ index = startIndex; max = array[index]; if(max<(array[2*startIndex+1])){ max=array[2*startIndex+1]; index=2*startIndex+1; } if(2*startIndex+2<arraylength&&max<array[2*startIndex+2]){ max=array[2*startIndex+2]; index=2*startIndex+2; } if(index==startIndex){ break; } swap(array,index,startIndex); startIndex = index; } } //构建大根堆 void createHeap(int *array,int length){ int max=0; int index=0; for(int i=floor(length/2)-1;i>=0;i--){ index = i; max = array[i]; if(max<array[2*i+1]){ index=2*i+1; max = array[2*i+1]; } if(2*i+2<length&&max<array[2*i+2]){ index = 2*i+2; max = array[2*i+2]; } if(index!=i){ swap(array,index,i); ReBuildMaxValue(array,length,index); } } } //堆排序 void heapSort(int *array,int arraylength){ createHeap(array,10); for(int i=arraylength-1;i>0;i--){ swap(array,i,0); ReBuildMaxValue(array,i,0); } } int main(int argc, _TCHAR* argv[]) { int values[10]={5,4,17,13,15,12,10,7,11,9}; heapSort(values,10); for(int i=0;i<10;i++){ cout<<*(values+i)<<endl; } return 0; }
相关文章推荐
- 不等值标量子查询改写
- python request第三方库介绍
- JavaWeb学习总结(三)——Tomcat服务器学习和使用(二)
- Django rest framework 使用自定义认证方式
- 《剑指offer》替换空格
- 待解决问题
- JavaWeb学习总结(二)——Tomcat服务器学习和使用(一)
- DoEvents 方法使用小结
- Python Singleton
- 1月18日 - 23种设计模式简介
- java设计模式 略版
- The flow of the app to create the Surface
- 【python】一维二维插值
- 路径名导致的异常:javax.imageio.IIOException: Can't read input file!
- Python中optionParser模块的使用方法[转]
- PHP中VC6、VC9、TS、NTS版本的区别与用法详解
- (无码)ARC(自动引用计数)
- Android工程目录结构及基本常用框架
- JavaWeb学习总结(一)——JavaWeb开发入门
- SparkR:数据科学家的新利器