前言

堆排序我是看了好半天别人的博客才有了理解,然后又费了九牛二虎之力才把代码写出来,我发现我的基础真的很差劲啊……不过自己选的路一定要坚持走下去。
我试着把我的理解描述出来,如有不妥之处希望大家可以指点出来

算法说明

堆排序,是基于堆的排序。 堆也就是二叉树的一种(完全二叉树),首先要确定堆的定义,才可以学会堆算法的逻辑;

OK,我们知道堆的定义前得先确定啥是完全二叉树。

二叉树就是树状结构是这样的,如图:

通常二叉树都会存放在数组中,那么将上图的完全二叉树放在数组中就是int[] arrayData = {1,2,3,17,19,36,7,25,100}

然后还有一个前置知识要知道,就是如何计算左子孩子的索引和右子孩子的索引。

还是以上图来举例子,3,36,7这三个数中, 3就是父节点,36 和 7就是子节点。  然后左子节点和右子节点的计算公式是i*2+1 和 i*2+2  。 替换到我举的例子中就是,数字3在数组中的索引是2,那么根据公式所述,左子节点的数组索引是2*2+1=5,右子节点的数组索引是2*2+2=6。 大家可以对一下数字36和数字7的数组索引和我们计算出来的是否一致。

还有,父节点的索引公式是 (i-1)/2。 大家可以代入一下上面的数组求一下值

OK,下面我们可以看一下堆的定义了。

堆的定义是这样的:

如图,堆分两种,一种是“小顶堆”,另一种是“大顶堆“。

小顶堆:就是顶点是最小值,并且父节点小于等于左子节点和右子节点(子节点公式上边有说)

大顶堆:就是顶点是最大值,并且父节点大于等于左子节点呼右子节点(子节点公式上边有说)

OK,现在说一下堆排序的逻辑。 堆排序是有两步:

第一步:建立堆。 我们需要把无序数组调整成堆结构(也就是让无序数组满足上图的条件)

大概过程,如图:

如图如所,我们要建立的是小顶堆,所以父节点一定是大小子节点的。

那么从97这个数字开始,是才有子节点的。  如果按公式来算,就是索引第(i/2)-1个数字是第一个有子节点的数字。

比较完数字97,把小的数字与97对换,然后再比较数字65与65子节点大小,然后再比较数字38与38子节点大小,最终比较最顶节点与子节点。

OK,有一个槽点要注意,请大家看第四图和第五图,当比较顶节点和子节点时,13与49换了位置,这时发现换位置后的49与49子节点是不满足堆的关联,所以49与27也要做一下互换的。   大家有个印象就行,具体逻辑还是请看下边的代码(17行至20行)

第二步:进行堆排序。

因为堆其实就是一个数组,所以如果我们的堆是完全从小到大,或者从大到小存储数据,那么数组同样也就是升序,或者降序了。

以下代码第24行至31行是进行堆排序。

我们可以看到我们之前代码建立好的堆是小顶堆,也就是最小值是在顶点。

第26行到28行,做的就是把第一个节点与最后一个节点数字互换,这时,最小值就在最后边了。

然后执行第30行的代码,因为上边把节点数字做了互换,这时堆就变成了无序数组,那么需要重新建立堆啦,需要把第一个节点至(最后一个节点-1)进行重建堆。

重建堆后,最小的数字又会放到第一他节点啦

接着执行第26行到28行,把第一个节点与(最后一个节点-1)数字互换,这时,最小值就在(最后一个节点-1)了。

然后执行第30行代码,继续重新建立堆。。。。如此类推,数字将会进行降序。

代码

使用JAVA

/*
* 堆排序
*/
public class HeadSort {
public static void main(String[] args) {
int[] arrayData = { 5, 9, 6, 7, 4, 1, 2, 3, 8 };
HeadSortMethod(arrayData);
for (int integer : arrayData) {
System.out.print(integer);
System.out.print(" ");
}
} public static void HeadSortMethod(int[] arrayData) {
// 第一步,将无序数组,建成一个堆。
//System.out.println("开始建堆");
for (int i = arrayData.length / 2 - 1; i >= 0; i--) {
// 第一个有孩子节点的节点,索引是arrayData.length/2-1 。 这个就不证明了(暂时还不会),大家测试一下就知道结果了
HeadAjust(arrayData, i, arrayData.length);
}
//System.out.println("开始排序");
// 第二步,进行排序
// 对堆进行递归,来建立排好序的堆。
int temp;
for (int i = arrayData.length-1; i > 0; i--) {
temp = arrayData[0];
arrayData[0] = arrayData[i];
arrayData[i] = temp; HeadAjust(arrayData, 0, i - 1);
}
} /*
* 对于指定数组的序列,进行堆化调整 也就是将无序数组调整成堆。
*/
public static void HeadAjust(int[] arrayData, int beginIndex, int endIndex) {
int minNum = arrayData[beginIndex]; // i=beginIndex*2+1代表是左子节点
// i=i*2+1代表下一个左子节点
for (int i = beginIndex * 2 + 1; i <= endIndex; i = i * 2 + 1) {
//System.out.println(i);
// 先比较左子节点和右子节点, i存储小值的索引
if (i < endIndex && arrayData[i] > arrayData[i + 1]) {
i++;
} if (arrayData[i] > minNum) {
break;
} arrayData[beginIndex] = arrayData[i];
beginIndex = i;
} arrayData[beginIndex] = minNum;
}
}

执行结果:

9 8 7 6 5 4 3 2 1

  

时间复杂度:O(nlog2n)   参考这里http://blog.csdn.net/liliuteng/article/details/8496050, 说实在的,这个证明过程我还是看不太懂……数学基础不太好,过后需要再学习一下数学了。

空间复杂度:O(1)

学习资料

http://blog.csdn.net/clam_clam/article/details/6799763   本次总结大部分图是从这里来的…实在是懒着画了,抱歉抱歉

http://www.cnblogs.com/mengdd/archive/2012/11/30/2796845.html

http://blog.csdn.net/morewindows/article/details/6709644/

Hark的数据结构与算法练习之堆排序的更多相关文章

  1. Hark的数据结构与算法练习之锦标赛排序

    算法说明 锦标赛排序是选择排序的一种. 实际上堆排序是锦标赛排序的优化版本,它们时间复杂度都是O(nlog2n),不同之处是堆排序的空间复杂度(O(1))远远低于锦标赛的空间复杂度(O(2n-1)) ...

  2. Hark的数据结构与算法练习之若领图排序ProxymapSort

    算法说明 若领图排序是分布排序的一种. 个人理解,若领图排序算是桶排序+计数排序的变异版,桶排序计数排序理解了,那么若领图排序理解起来就会比较容易.区别其实就是存储中间值的方式做了调整…… 话说,这个 ...

  3. Hark的数据结构与算法练习之珠排序

    ---恢复内容开始--- 算法说明 珠排序是分布排序的一种. 说实在的,这个排序看起来特别的巧妙,同时也特别好理解,不过不太容易写成代码,哈哈. 这里其实分析的特别好了,我就不画蛇添足啦.  大家看一 ...

  4. Hark的数据结构与算法练习之鸽巢排序

    算法说明 鸽巢排序是分布排序的一种,我理解其实鸽巢就是计数排序的简化版,不同之处就是鸽巢是不稳定的,计数排序是稳定的. 逻辑很简单,就是先找出待排数组的最大值maxNum,然后实例一个maxNum+1 ...

  5. Hark的数据结构与算法练习之圈排序

    算法说明 圈排序是选择排序的一种.其实感觉和快排有一点点像,但根本不同之处就是丫的移动的是当前数字,而不像快排一样移动的是其它数字.根据比较移动到不需要移动时,就代表一圈结束.最终要进行n-1圈的比较 ...

  6. Hark的数据结构与算法练习之梳排序

    算法说明梳排序是交换排序的一种,它其实也是改自冒泡排序,不同之处是冒泡排序的比较步长恒定为1,而梳排序的比较步长是变化的. 步长需要循环以数组长度除以1.3,到最后大于等于1即可. 光说可能比较抽象, ...

  7. Hark的数据结构与算法练习之地精(侏儒)排序

    算法说明 地精排序是交换排序的一种,它是冒泡排序的一种改良,我感觉和鸡尾酒排序挺像的. 不同之处是鸡尾酒排序是从小到大,然后再从大到小切换着排序的.而地精排序是上来先从小到大排序,碰到交换到再从大到小 ...

  8. Hark的数据结构与算法练习之Bogo排序

    算法说明 Bogo排序是交换排序的一种,它是一种随机排序,也是一种没有使用意义的排序,同样也是一种我觉得很好玩的排序. 举个形象的例子,你手头有一副乱序的扑克牌,然后往天上不停的扔,那么有一定机率会变 ...

  9. Hark的数据结构与算法练习之臭皮匠排序

    算法说明 个人感觉是没有意义的算法,只是用来作为学术研究.或者说开拓一下思维. 从wikipedia copy来的一句解释的话:Stooge排序是一种低效的递归排序算法,甚至慢于冒泡排序.在<算 ...

随机推荐

  1. mysql 查询技巧

    查出来的结果每一行显示一条,中间以*号分隔. select * from tableName limit 10 \G mysql 随机取数据 SELECT * FROM table_name ORDE ...

  2. Sublime text 3 中文文件名显示方框怎么解决?

    如图,中文文件名打开全是乱码,内容倒是装了converttoutf8没什么太大的问题. -------------------------------------------------------- ...

  3. POJ 1191 棋盘分割

    棋盘分割 Time Limit: 1000MS Memory Limit: 10000K Total Submissions: 11213 Accepted: 3951 Description 将一个 ...

  4. HDOJ 1848 Fibonacci again and again

    Fibonacci again and again Time Limit: 1000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Jav ...

  5. Model backing a DB Context has changed; Consider Code First Migrations

    Model增加一个字段,数据库对应的也手动添加了字段但是运行时报错 The model backing the 'TopLogDbContext' context has changed since ...

  6. We are 歪果仁带你灰

    We are 歪果仁带你灰 我叫赖彦谕 不爱什么诗和远方 只爱饭桌上的一菜一肉一杯酒 真的很希望有一天我可以成为那个对待学习像对待美食一样的人类 让自己沉浸在美食和知识的海洋中无法自拔 我也对未来的软 ...

  7. 解决win8下chrome浏览器打开提示没有注册类的方法

    今天又把win8装回来了,继续装了个chrome浏览器,但是发现只能从安装的文件打开,从快捷方式或者快速启动栏都会提示没有注册类.找到一种解决的办法是删除注册表中的相关键值,具体如下: 1.打开注册表 ...

  8. ubuntu 修改保存报错E37:No write since last change(add ! to override)的解决方法

    报错信息如下: E37: No write since last change (add ! to override) 解决办法是: 在修改完后,将命令 :q 改成 :wq 即可.

  9. linux下查看文件夹的大小

    du -sh du -sh dir_name/ du -sm * | sort -n //统计当前目录大小 并安大小排序 转自:http://www.jb51.net/LINUXjishu/77450 ...

  10. 《ASP.NET MVC4 WEB编程》学习笔记------Model模型绑定

    本文转载自haiziguo Asp.net mvc中的模型绑定,或许大家经常用,但是具体说他是怎么一回事,可能还是会有些陌生,那么,本文就带你理解模型绑定.为了理解模型绑定,本文会先给出其定义,然后对 ...