排序系列算法——堆排序

堆:大根堆与小根堆

堆排序是建立在堆基础上的排序方法,首先了解一下什么是堆。

常用的堆一般有两种,大根堆和小根堆。堆可以看做是一棵二叉树,其父节点的值总是大于(大根堆)或者小于(小根堆)子节点的值。举一个例子:

                图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 void ReBuildMaxHeap(int *array,int arraylength,int startIndex){
 2     int index=0;
 3     //int j=0;
 4     int max=0;
 5     while((2*startIndex+1)<arraylength){
 6         index = startIndex;
 7         max = array[index];
 8         if(max<(array[2*startIndex+1])){
 9             max=array[2*startIndex+1];
10             index=2*startIndex+1;
11         }
12         if(2*startIndex+2<arraylength&&max<array[2*startIndex+2]){
13             max=array[2*startIndex+2];
14             index=2*startIndex+2;
15         }
16         if(index==startIndex){
17             break;
18         }
19         swap(array,index,startIndex);
20         startIndex = index;
21     }
22 }

1、  构建大根堆。

  要构建大根堆,只需要遍历所有非叶子节点元素,使其所有的叶子节点均不大于足该节点元素即可。构建大根堆自低向上对数组进行遍历,如果发现父节点的值小于子节点的值,则将父节点的值与子节点的最大值进行交换,保证父节点的数据总是大于子节点的数据。如果发生了数据的交换,有可能令子节点不满足大根堆条件,需要进行会输重构大根堆。以一个实际的例子说明构建大根堆的过程:

C++代码如下:

 1 void createHeap(int *array,int length){
 2     int max=0;
 3     int index=0;
 4     for(int i=floor(length/2)-1;i>=0;i--){
 5         index = i;
 6         max = array[i];
 7         if(max<array[2*i+1]){
 8             index=2*i+1;
 9             max = array[2*i+1];
10         }
11         if(2*i+2<length&&max<array[2*i+2]){
12             index = 2*i+2;
13             max = array[2*i+2];
14         }
15         if(index!=i){
16             swap(array,index,i);
17             ReBuildMaxValue(array,length,index);
18         }
19     }
20 }

全部源代码:

 1 #include "stdafx.h"
 2 #include <iostream>
 3 using namespace std;
 4
 5 //两个文位置的数据交换
 6 void swap(int *array,int num1,int num2){
 7     int temp = *(array+num1);
 8     *(array+num1) = *(array+num2);
 9     *(array+num2) = temp;
10 }
11
12 //重构大根堆
13 void ReBuildMaxValue(int *array,int arraylength,int startIndex){
14     int index=0;
15     //int j=0;
16     int max=0;
17     while((2*startIndex+1)<arraylength){
18         index = startIndex;
19         max = array[index];
20         if(max<(array[2*startIndex+1])){
21             max=array[2*startIndex+1];
22             index=2*startIndex+1;
23         }
24         if(2*startIndex+2<arraylength&&max<array[2*startIndex+2]){
25             max=array[2*startIndex+2];
26             index=2*startIndex+2;
27         }
28         if(index==startIndex){
29             break;
30         }
31         swap(array,index,startIndex);
32         startIndex = index;
33     }
34 }
35
36 //构建大根堆
37 void createHeap(int *array,int length){
38     int max=0;
39     int index=0;
40     for(int i=floor(length/2)-1;i>=0;i--){
41         index = i;
42         max = array[i];
43         if(max<array[2*i+1]){
44             index=2*i+1;
45             max = array[2*i+1];
46         }
47         if(2*i+2<length&&max<array[2*i+2]){
48             index = 2*i+2;
49             max = array[2*i+2];
50         }
51         if(index!=i){
52             swap(array,index,i);
53             ReBuildMaxValue(array,length,index);
54         }
55     }
56 }
57
58 //堆排序
59 void heapSort(int *array,int arraylength){
60     createHeap(array,10);
61     for(int i=arraylength-1;i>0;i--){
62         swap(array,i,0);
63         ReBuildMaxValue(array,i,0);
64     }
65 }
66
67 int main(int argc, _TCHAR* argv[])
68 {
69     int values[10]={5,4,17,13,15,12,10,7,11,9};
70     heapSort(values,10);
71     for(int i=0;i<10;i++){
72         cout<<*(values+i)<<endl;
73     }
74     return 0;
75 }
时间: 2024-10-06 08:07:13

排序系列算法——堆排序的相关文章

排序系列算法——插入排序

1. 原理 插入排序是顾名思义是将未进行排序的元素不断插入到已排序序列中的排序方法.如下图所示: 插入排序说白点就是在以排序的序列中找到未排序元素的位置,并将元素插入行程新的已排序序列的过程. 2.排序过程及算法设计 排序过程 以一个实际的例子为例: 设有序列{7,9,6,12,15,11},使用插入排序对上述的序列按从小到大进行排序,排序的过程可描述如下: 算法设计 插入排序是将元素插入已排序序列的过程,排序过程需要将元素与已排序的序列元素进行对比,采用从后往前的对比顺序,不断向前移动,直到不

排序系列算法——冒泡排序

冒泡排序 什么是冒泡排序 如果大家平常有即系观察水泡付出谁面的情况就可以发现水泡从下往上是逐渐增大的,升到即将浮出水面的时候往往是水泡最大的时候,如下图所示. 冒泡排序的原理跟这个情况很类似,让子序列中的最大元素不断沉底,达到排序的目的.说白了,冒泡排序一共经过N-1次遍历,其中第i次遍历前N-i个元素(第i+1到N个元素已经排序完毕),将第i大的元素移动到N-i的位置 . 冒泡排序的过程可描述如下: 令A表示进行排序的数组,N表示A的长度,A[i]表示数组A第i+1个元素,i=1,1,2,3.

[算法学习笔记]排序算法——堆排序

堆排序 堆排序(heapsort)也是一种相对高效的排序方法,堆排序的时间复杂度为O(n lgn),同时堆排序使用了一种名为堆的数据结构进行管理. 二叉堆 二叉堆是一种特殊的堆,二叉堆是完全二叉树或者是近似完全二叉树.二叉堆满足堆特性:父节点的键值总是保持固定的序关系于任何一个子节点的键值,且每个节点的左子树和右子树都是一个二叉堆. 如上图显示,(a)是一个二叉堆(最大堆), (b)是这个二叉堆在数组中的存储形式. 通过给个一个节点的下标i, 很容易计算出其父节点,左右子节点的的下标,为了方便,

经典排序算法 - 堆排序Heap sort

经典排序算法 - 堆排序Heap sort 堆排序有点小复杂,分成三块 第一块,什么是堆,什么是最大堆 第二块,怎么将堆调整为最大堆,这部分是重点 第三块,堆排序介绍 第一块,什么是堆,什么是最大堆 什么是堆 这里的堆(二叉堆),指得不是堆栈的那个堆,而是一种数据结构. 堆可以视为一棵完全的二叉树,完全二叉树的一个"优秀"的性质是,除了最底层之外,每一层都是满的,这使得堆可以利用数组来表示,每一个结点对应数组中的一个元素. 数组与堆之间的关系 二叉堆一般分为两种:最大堆和最小堆. 什么

Java排序算法 - 堆排序的代码

把内容过程中比较重要的一些内容片段做个备份,如下的资料是关于Java排序算法 - 堆排序的内容. import java.util.Arrays; public class HeapSort { int a[]={49,38,65,97,76,13,27,49,78,34,12,64,5,4,62,99,98,54,56,17,18,23,34,15,35,25,53,51}; public HeapSort(){ heapSort(a); } public void heapSort(int[

15. 蛤蟆的数据结构进阶十五排序实现之堆排序

15. 蛤蟆的数据结构进阶十五排序实现之堆排序 本篇名言:"谁要是游戏人生 ,他就一事无成 ; 谁不能主宰自己 ,永远是一个奴隶.--歌德" 继续来看下堆排序. 欢迎转载,转载请标明出处:http://blog.csdn.net/notbaron/article/details/47733553 1.  堆排序 堆排序(Heapsort)是指利用堆积树(堆)这种数据结构所设计的一种排序算法,它是选择排序的一种.可以利用数组的特点快速定位指定索引的元素.堆分为大根堆和小根堆,是完全二叉树

图文并茂排序与算法

图文并茂排序与算法总结 转载请注明出处:http://www.cnblogs.com/Joanna-Yan/p/5094764.html 总结下常用的排序算法,方便以后查阅. 常见排序算法:冒泡排序.选择排序.插入排序.壳(shell)排序.合并排序.快速排序.堆排序. 要选择合适的算法,需考虑的因素:执行时间.存储空间和编程工作. 1.选择排序 具有二次方程增长阶,近适用于小列表排序. 通过列表反复扫描,每次扫描选择一项,然后将这一项移动到列表中正确的位置. 选择排序总比较次数=(n-1)+(

基本排序系列之计数排序

简述计数排序 看了好多别人写的计数排序,看了好久都没看懂,弄了好久最后发现这么简单居然花了几个小时,所以在这里写上,希望和我一样的初学者不会再绕弯路. 一.简述计数排序的思想: 设被排序的数组为A,排序后存储到B,C为临时数组.所谓计数,首先是通过一个数组C[i]计算大小等于i的元素个数,此过程只需要一次循环遍历就可以:在此基础上,计算小于或者等于i的元素个数,也是一重循环就完成.下一步是关键:逆序循环,从length[A]到1,将A[i]放到B中第C[A[i]]个位置上.原理是:C[A[i]]

基本排序系列之基数排序

基数排序 一.基数排序是一种非比较型整数排序算法,其原理是将整数按位数切割成不同的数字,然后按每个位数分别比较. 其实现原理:将所有待比较数值(正整数)统一为同样的数位长度,数位较短的数前面补零.然后,从最低位开始,依次进行一次排序.这样从最低位排序一直到最高位排序完成以后, 数列就变成一个有序序列. 二.具体操作:此排序的真正实现是通过队列的装置,先进先出的原理,通过把个位,十位,百位,等其他进制也一样,放到不同的队列中(俗称桶)再按照先进先出的原理得到新的序列,在通过百位将其重新入桶回收等操