堆排序的C++代码实现
堆排序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++代码实现的更多相关文章
- 算法与数据结构(十四) 堆排序 (Swift 3.0版)
上篇博客主要讲了冒泡排序.插入排序.希尔排序以及选择排序.本篇博客就来讲一下堆排序(Heap Sort).看到堆排序这个名字我们就应该知道这种排序方式的特点,就是利用堆来讲我们的序列进行排序.&quo ...
- Java常见排序算法之堆排序
在学习算法的过程中,我们难免会接触很多和排序相关的算法.总而言之,对于任何编程人员来说,基本的排序算法是必须要掌握的. 从今天开始,我们将要进行基本的排序算法的讲解.Are you ready?Let ...
- 高速排序,归并排序,堆排序python实现
高速排序的时间复杂度最好情况下为O(n*logn),最坏情况下为O(n^2),平均情况下为O(n*logn),是不稳定的排序 归并排序的时间复杂度最好情况下为O(n*logn),最坏情况下为O(n*l ...
- PAT1098【插入排序+堆排序】
简单插入排序: 简单插入排序的核心思想: 把一条这么个难看的序列默认分为两个排好序的和未排好序的两个部分: 所以一开始排好序的只有一个a[0](好看的只有一个),难看的有N(数组长度)-1个a[1,n ...
- 常见内部排序算法对比分析及C++ 实现代码
内部排序是指在排序期间数据元素全部存放在内存的排序.外部排序是指在排序期间全部元素的个数过多,不能同时存放在内存,必须根据排序过程的要求,不断在内存和外存之间移动的排序.本次主要介绍常见的内部排序算法 ...
- 排序陷阱 List.Sort Linq.OrderBy
部分内容摘自:http://www.th7.cn/Program/net/201511/692766.shtml C#框架里面主要提供了两种排序方式:Array.Sort Linq.Orderby. ...
- Poj2002 Squares
题意描述:有一堆平面散点集,任取四个点,求能组成正方形的不同组合方式有多少.相同的四个点,不同顺序构成的正方形视为同一正方形. 思路变迁: 1.最简单的方法,直接暴力搜索,即依次取四个顶点,根据其坐标 ...
- Python实现八大排序算法(转载)+ 桶排序(原创)
插入排序 核心思想 代码实现 希尔排序 核心思想 代码实现 冒泡排序 核心思想 代码实现 快速排序 核心思想 代码实现 直接选择排序 核心思想 代码实现 堆排序 核心思想 代码实现 归并排序 核心思想 ...
- Linux内存管理与C存储空间
ELF文件 在学习之前我们先看看ELF文件. ELF分为三种类型:.o 可重定位文件(relocalble file),可执行文件以及共享库(shared library),三种格式基本上从结构上是一 ...
随机推荐
- bzoj千题计划216:bzoj1499: [NOI2005]瑰丽华尔兹
http://www.lydsy.com/JudgeOnline/problem.php?id=1499 预处理从每个位置向每个方向最多能走几步 dp[k][i][j] 第k个时间段后,钢琴到位置(i ...
- ie6下的line-height属性
line-height这个属性是被ie6所支持的. 当是当一个父级元素内的子元素,包含了文字,且文字和img,input,label,span这些内联元素连接在一起的时候,你对父级元素设置line-h ...
- Chrome插件LiveStyle结合Sublime Text3编辑器实现高效可视化开发
LiveStyle是Chrome中提高开发效率的一款CSS编辑器插件.利用LiveStyle和Sublime Text3编辑器结合可实现可视化开发,一次配置,简单易用! 本文由前端交流QQ群管理员—— ...
- 20155339 2016-2017-2 《Java程序设计》第8周学习总结
20155339 2016-2017-2 <Java程序设计>第8周学习总结 教材学习内容总结 第十四章NIO与NIO2 NIO使用频道来衔接数据节点,在处理数据时,NIO可以让你设定缓冲 ...
- sqlserver2008R2数据库自动备份脚本
CREATE proc [dbo].[usp_autoBackupDB] @dbname sysname=null --要备份的数据库名,不指定即为全部备份 ,)='d:\' --备份目录路径 ,)= ...
- 通俗理解决策树中的熵&条件熵&信息增益
参考通俗理解决策树算法中的信息增益 说到决策树就要知道如下概念: 熵:表示一个随机变量的复杂性或者不确定性. 假如双十一我要剁手买一件衣服,但是我一直犹豫着要不要买,我决定买这件事的不确定性(熵)为2 ...
- Java反射--基于ParameterizedType实现泛型类,参数化类型
一.引子: 项目中使用Gson的反序列化将json转化成具体的对象,具体方法是: package com.google.gson;下的反序列化方法 public <T> T fromJso ...
- 八、vue使用element-ui组件
element-ui组件 1.引入element import Vue from 'vue'; import ElementUI from 'element-ui'; import 'element- ...
- IPsec工具之ipsec-tools
Linux从2.6内核开始自带IPsec模块,配合IPsec-Tools,可以实现Linux的IPsec功能. IPsec-Tools包含4个模块 libipsec:PF_KEY实现库 setkey: ...
- java虚拟机规范(se8)——java虚拟机结构(二)
2.5 运行时数据区域 java虚拟机定义了多个用于程序执行期间的运行时数据区域.这些数据区域中一些随着java虚拟机的启动而创建,随着虚拟机的退出而销毁.其他的数据区域时和线程相关的.线程相关数据区 ...