堆排序C++实现

堆排序的具体思路可以查看《算法导论》这本书,一下只提供笔者的C++实现代码,并且将笔者在编写程序的过程当中所遇到的一些细节问题拿出来作一番解释,希望能够对对堆排序有一个透彻的理解。

1、构造一个维护堆性质(最大堆)的函数

这里需要做一个假设:对于数组中下标为i的节点其左子树和右子树都是保持最大堆性质的堆。在假设成立的前提上,经过这一个维护函数维护过的堆才能够保证是一个最大堆。函数的C++实现代码如下:

 //假定对某一个节点i其左,右子树都是都是最大堆,但是对于节点i和它的左右子节点则可能破坏最大堆的性质,我们来写一个函数对这
//情况下的堆来进行维护使整体的堆满足最大堆性质
void MaxHeapify(int* a,int i,int low,int high)//输入为要被排序的数组和根节点,数组a当中被维护的那一部分的下标low,high
{
int l = left(i);//计算下标为i的节点的左子节点
int r = right(i);//计算下标为i的节点的右子节点
int largest;//保存i,l,r(即i和它的左右子节点)之间的最大数的下标
int temp;//交互数组中的数所使用的临时变量
//找到三个数当中最大的那个数,将最大的那个数和i进行互换
if (l<=high && a[l]>a[i])
{
largest = l;
}
else{
largest = i;
} if (r<=high && a[r]>a[largest])
{
largest = r;
}
if (largest != i)
{
temp = a[i];
a[i] = a[largest];
a[largest] = temp;
MaxHeapify(a, largest,low,high);//交换有可能破坏子树的最大堆性质,所以对所交换的那个子节点进行一次维护,而未交换的那个子节点,根据我们的假设,是保持着最大堆性质的。
}
}

代码中还有一个细节需要注意:

 //定义两个有参宏来寻找数组中的数之间的关系
#define left(x) 2*x+1;//获得左节点在数组中的下标
#define right(x) 2*(x+1);//获得右节点在数组中的下标

《算法导论》一书当中的数组都是以1作为起始下标的,所以书中计算左右节点的下标的公式分别为:2*i,2*i+1。但是在C++的程序当中数组都是从0开始的所以我们的计算方式也要进行修改。

建堆函数

这个函数负责将数组中元素的位置进行更改保证数组能够构造成为一个最大堆,实现如下:

//将数组建立为一个最大堆
//调整数组当中数的位置将其处理为一个最大堆
void BuildMaxHeap(int* a,int length)
{
for (int i = length / 2-1; i >= ; i--)
{
MaxHeapify(a, i, , length - );
}
}

其中MaxHeapify函数为在上文中创建的函数。有一个细节的位置和《算法导论》上面的不一样,i=length/2-1,这也是因为数组的起始下标为0所导致的。可以这样理解此处的减1,相当于在以1为起始的数组当中找到这个点之后,对数组整体进行向后位移一个单位就可以得到现在这个点的下标了。

在本节后面的习题当中有提到这么一个问题:为什么是从length/2-1递减到0,而不是从0开始递增到length/2-1呢?从length/2-1递减到0就意味着,从最后的一个非叶节点开始“从小到大”地进行维护,保证每一个点的子树都是最大堆,可以确保最大堆的性质,而如果从0递增到length/2-1则无法保证堆的性质,可以看如下反例:

对数组{14,10,8,16,7}从0递增到length/2-1的堆创建过程如下图所示:

可见无法保证最大堆性质。

堆排序函数

实现程序如下:

 //堆排序函数
void HeapSort(int a[],int length)
{
int temp;
BuildMaxHeap(a,length);
for (int i = length - ; i >= ; i--)
{
//交换根节点和数组的最后一个节点
temp = a[i];
a[i] = a[];
a[] = temp;
MaxHeapify(a, , , i-);//维护从下标为i-1到0的子数组
}
}

在缩减被排列数组这一思路上面我采用的方法是在函数当中输入被排序数组的下标范围。

堆排序的C++代码实现的更多相关文章

  1. 算法与数据结构(十四) 堆排序 (Swift 3.0版)

    上篇博客主要讲了冒泡排序.插入排序.希尔排序以及选择排序.本篇博客就来讲一下堆排序(Heap Sort).看到堆排序这个名字我们就应该知道这种排序方式的特点,就是利用堆来讲我们的序列进行排序.&quo ...

  2. Java常见排序算法之堆排序

    在学习算法的过程中,我们难免会接触很多和排序相关的算法.总而言之,对于任何编程人员来说,基本的排序算法是必须要掌握的. 从今天开始,我们将要进行基本的排序算法的讲解.Are you ready?Let ...

  3. 高速排序,归并排序,堆排序python实现

    高速排序的时间复杂度最好情况下为O(n*logn),最坏情况下为O(n^2),平均情况下为O(n*logn),是不稳定的排序 归并排序的时间复杂度最好情况下为O(n*logn),最坏情况下为O(n*l ...

  4. PAT1098【插入排序+堆排序】

    简单插入排序: 简单插入排序的核心思想: 把一条这么个难看的序列默认分为两个排好序的和未排好序的两个部分: 所以一开始排好序的只有一个a[0](好看的只有一个),难看的有N(数组长度)-1个a[1,n ...

  5. 常见内部排序算法对比分析及C++ 实现代码

    内部排序是指在排序期间数据元素全部存放在内存的排序.外部排序是指在排序期间全部元素的个数过多,不能同时存放在内存,必须根据排序过程的要求,不断在内存和外存之间移动的排序.本次主要介绍常见的内部排序算法 ...

  6. 排序陷阱 List.Sort Linq.OrderBy

    部分内容摘自:http://www.th7.cn/Program/net/201511/692766.shtml C#框架里面主要提供了两种排序方式:Array.Sort Linq.Orderby. ...

  7. Poj2002 Squares

    题意描述:有一堆平面散点集,任取四个点,求能组成正方形的不同组合方式有多少.相同的四个点,不同顺序构成的正方形视为同一正方形. 思路变迁: 1.最简单的方法,直接暴力搜索,即依次取四个顶点,根据其坐标 ...

  8. Python实现八大排序算法(转载)+ 桶排序(原创)

    插入排序 核心思想 代码实现 希尔排序 核心思想 代码实现 冒泡排序 核心思想 代码实现 快速排序 核心思想 代码实现 直接选择排序 核心思想 代码实现 堆排序 核心思想 代码实现 归并排序 核心思想 ...

  9. Linux内存管理与C存储空间

    ELF文件 在学习之前我们先看看ELF文件. ELF分为三种类型:.o 可重定位文件(relocalble file),可执行文件以及共享库(shared library),三种格式基本上从结构上是一 ...

随机推荐

  1. Confluence wiki——CentOS6.8搭建详解

    参考资料:http://www.cnblogs.com/jackyyou/p/5534231.html http://www.ilanni.com/?p=11989 公司需要搭建WIKI方便员工将一些 ...

  2. bzoj千题计划261:bzoj3294: [Cqoi2011]放棋子

    http://www.lydsy.com/JudgeOnline/problem.php?id=3294 如果一个颜色的棋子放在了第i行第j列,那这种颜色就会占据第i行第j列,其他颜色不能往这儿放 设 ...

  3. 在Ubuntu14.04 64bit上搭建单机Spark环境,IDE为Intelli IDEA

    在Ubuntu14.04 64bit上搭建单机Spark环境,IDE为Intelli IDEA 一. 环境 Ubuntu14.04 64位    JDK 1.8.0_73    scala-2.10. ...

  4. python中的__new__、__init__和__del__

    __new__.__init__.__del__三个方法用于实例的创建和销毁,在使用python的类中,我们最常用的是__init__方法,通常称为构造方法,__new__方法几乎不会使用,这篇文章是 ...

  5. linux磁盘已满,文件占用情况

    du -sh /data0/* 如上,/data0/* 表示查看data0文件夹下各个目录的磁盘占用情况 df -h 查看总的磁盘占比

  6. netty学习总结(一)

    netty是一个nio框架,将java的nio进行了一个封装,形成了一个高性能,高可用的网络编程框架,很多的框架都是基于netty的,所以学好netty是很有用的,而且netty本身的代码结构设计,以 ...

  7. 【项目部署】部署项目以war包部署和解开以目录部署的区别

    我们都知道最简单的部署web项目的方式是打成war包直接仍在tomcat的webapps目录下,我上个项目也确实是这样做的,可是这给我们后期的维护带来了极大的不便,下面就简单研究一下以war包部署和解 ...

  8. keepalived启动不成功,状态一直是inactive(dead) 的解决办法以及keepalived高版本没有rc.d目录,虚拟VIP无法访问问题

    安装配置教程我就不说了,网上很多,这里只给出我遇到的两个坑: 1 rc.d目录 ,kp在1.4版本之后rc.d要去解压之后的源码包里去找,make之后的目录里面没有了,我使用的是2.0.13最新版本, ...

  9. win10下安装MinGW-w64 - for 32 and 64 bit Windows

    对于不经常使用c语言的同学来说,只需要安装MinGW-w64 - for 32 and 64 bit Windows,就可以使用GCC在命令行对c源码进行编译. 首先打开命令行检查自己是否已经安装了g ...

  10. windows下使用pip安装python模块lxml

    pip install lxml 1 1 会有如下问题:  结果一路解决下去,解决了一个坑还是有一个坑,遂放弃,查找有没有别的解决办法. 亲测使用wheel+pip可以成功安装lxml! wheel本 ...