堆的预备知识

  • 堆是一个完全二叉树。
  • 完全二叉树: 二叉树除开最后一层,其他层结点数都达到最大,最后一层的所有结点都集中在左边(左边结点排列满的情况下,右边才能缺失结点)。
  • 大顶堆:根结点为最大值,每个结点的值大于或等于其孩子结点的值。
  • 小顶堆:根结点为最小值,每个结点的值小于或等于其孩子结点的值。
  • 堆的存储: 堆由数组来实现,相当于对二叉树做层序遍历。如下图:

堆排序算法

现在需要对如上二叉树做升序排序,总共分为三步:

  1. 将初始二叉树转化为大顶堆(heapify)(实质是从第一个非叶子结点开始,从下至上,从右至左,对每一个非叶子结点做shiftDown操作),此时根结点为最大值,将其与最后一个结点交换。
  2. 除开最后一个结点,将其余节点组成的新堆转化为大顶堆(实质上是对根节点做shiftDown操作),此时根结点为次最大值,将其与最后一个结点交换。
  3. 重复步骤2,直到堆中元素个数为1(或其对应数组的长度为1),排序完成。

代码实现

 1 let array = randomArray(1,100);
2 console.log(array);
3 let sortArray = heapSort(array);
4 console.log(sortArray);
5 //输入起始值和终点值,随机数组
6 function randomArray(start,end){
7 var a=[],o={},random,step=end-start;
8 while(a.length<step){
9 random=start+parseInt(Math.random()*step);
10 if(!o["x"+random]){
11 a.push(random);
12 o["x"+random]=1;
13 };
14 };
15 return a;
16 };
17 //交换值
18 function swap(A, i, j) {
19 let temp = A[i];
20 A[i] = A[j];
21 A[j] = temp;
22 }
23
24 // 将 i 结点以下的堆整理为大顶堆,注意这一步实现的基础实际上是:
25 // 假设 结点 i 以下的子堆已经是一个大顶堆,shiftDown函数实现的
26 // 功能是实际上是:找到 结点 i 在包括结点 i 的堆中的正确位置。后面
27 // 将写一个 for 循环,从第一个非叶子结点开始,对每一个非叶子结点
28 // 都执行 shiftDown操作,所以就满足了结点 i 以下的子堆已经是一大
29 //顶堆
30 function shiftDown(A, i, length) {
31 let temp = A[i]; // 当前父节点
32 // j<length 的目的是对结点 i 以下的结点全部做顺序调整
33 for(let j = 2*i+1; j<length; j = 2*j+1) {
34 temp = A[i]; // 将 A[i] 取出,整个过程相当于找到 A[i] 应处于的位置
35 if(j+1 < length && A[j] < A[j+1]) {
36 j++; // 找到两个孩子中较大的一个,再与父节点比较
37 }
38 if(temp < A[j]) {
39 swap(A, i, j) // 如果父节点小于子节点:交换;否则跳出
40 i = j; // 交换后,temp 的下标变为 j
41 } else {
42 break;
43 }
44 }
45 }
46 // 堆排序
47 function heapSort(A) {
48 // 初始化大顶堆,从第一个非叶子结点开始
49 for(let i = Math.floor(A.length/2-1); i>=0; i--) {
50 shiftDown(A, i, A.length);
51 }
52 // 排序,每一次for循环找出一个当前最大值,数组长度减一
53 for(let i = Math.floor(A.length-1); i>0; i--) {
54 swap(A, 0, i); // 根节点与最后一个节点交换
55 shiftDown(A, 0, i); // 从根节点开始调整,并且最后一个结点已经为当
56 // 前最大值,不需要再参与比较,所以第三个参数
57 // 为 i,即比较到最后一个结点前一个即可
58 }
59 return A;
60 }

排序结果

最新文章

  1. Spring整合Redis
  2. 读《编写可维护的JavaScript》第七章总结
  3. windows nslookup、tracert 常用命令
  4. NHibernate系列文章十:NHibernate对象二级缓存下
  5. Sharepoint学习笔记—习题系列--70-573习题解析 -(Q91-Q93)
  6. 如何解决python中urlopen超时问题
  7. SQL2008--行号的得到
  8. [转载]做一个 App 前需要考虑的几件事
  9. js中return、return true、return false的区别
  10. Poj 1269 Intersecting Lines_几何模板
  11. ASP.NET - GridView实现点击编辑列
  12. 免费git服务器以及使用过程中遇到的问题
  13. Linux之例行(任务调度)
  14. 基于 HTML5 WebGL 的 3D 仓储管理系统
  15. CCTV5 前端
  16. boost asio 学习(七) 网络基础 连接器和接收器(TCP示例)
  17. 怎么用pr(Premiere)给视频添加水印
  18. 【noip模拟赛5】细菌
  19. English trip V1 - B 16. Giving Reasons 提供个人信息 Teacher:Lamb Key: Why/Because
  20. rexec/rlogin/rsh介绍

热门文章

  1. Java学习预热
  2. k8s报错解决思路
  3. pytest封神之路第四步 内置和自定义marker
  4. Redis学习(二)redis的特点
  5. 刷题[FBCTF2019]Event
  6. msf学习笔记
  7. 命令执行漏洞攻击&amp;修复建议
  8. Pipelines
  9. #error: Building MFC application with /MD[d] (CRT dll version) requires MFC shared dll version. Please #define _AFXDLL or do not use /MD[d]
  10. 万万没想到!ModelArts与AppCube组CP了