经典算法系列三----堆排序
花了些时间好好看了堆排序的内容,代码也敲了,现在来总结一下。
为了说明白点,有些图片我就从网上截取了。
首先是堆的概念。
数据结构中的堆,又叫二叉堆
一般用数组来表示堆得结构,或者说是把堆数组化。举个列子来看:
这样就很清楚的看出了堆的储存结构。
接着就是堆得操作处理了。
首先堆的插入操作:
上代码:
1 void Heap_insert_fix(int a[],int n) 2 { 3 int temp; 4 int i,j; 5 i = n; 6 j = (i - 1) / 2;/*父节点*/ 7 temp = a[i];/*记录插入的数据*/ 8 while(i != 0 && j >= 0) 9 { 10 if(a[j] <= temp) 11 break; 12 a[i] = a[j]; 13 i = j; 14 j = (i - 1) / 2; 15 } 16 a[i] = temp; 17 }
上面代码解析:
先明白这点,
*父节点 i 子节点则为 j = i*2 +1
*子节点 i 父节点则为 j = (i-1) / 2
然后,插入的流程是,每次插入的数据都是在叶子节点,接着调整。直到满足堆得性质为止!
然后是堆的删除操作:
原理:每次删除根节点,就是用叶子节点覆盖根节点
上代码:
1 /* 2 *删除操作 3 *删除根结点,然后调整 4 *从i节点开始,总数有n个 5 */ 6 void Heap_del_fix(int a[],int i,int n) 7 { 8 int j; 9 int temp; 10 temp = a[i]; 11 j = i * 2 + 1;/*子节点*/ 12 while(j < n) 13 { 14 if(a[j] > a[j+1] && j+1 < n) 15 j++; 16 if(a[j] >= temp) 17 break; 18 a[i] = a[j]; 19 i = j; 20 j = i*2 + 1; 21 } 22 a[i] = temp; 23 }
它的调用函数:
1 /* 2 *调用 3 */ 4 void Heap_sub(int a[],int n) 5 { 6 swap(&a[0],&a[n-1]); 7 Heap_del_fix(a,0,n-1); 8 }
有了上面这两个操作的基础,下面我就来写排序操作!
思想:
我们有了删除操作,每次删除根节点,而且我们知道根节点是数组中数值最小的那个值(我这里是小堆模式,大堆相反),这样我们一次次的删除,就形成了一个有序的序列。获取这个序列就是我们想要的堆排序结果。
怎么获取,使用数组,看代码:
1 /* 2 *堆排序 3 */ 4 void Heap_sort(int a[],int n) 5 { 6 int i; 7 for(i=n-1;i>=1;i--) 8 { 9 swap(&a[0],&a[i]); 10 Heap_del_fix(a,0,i); 11 } 12 }
这样倒序便是我们的序列。
至于如何将堆数组化,代码如下:
1 /* 2 *堆化数组 3 */ 4 void create_heap(int a[], int n) 5 { 6 int i; 7 for(i=n/2-1;i>=0;i--)/*将数组转成堆,分开调整*/ 8 { 9 Heap_del_fix(a,i,n); 10 } 11 }
这里的i=n/2-1;我们最好画图来看,这样理解会容易些。这部分我是在纸上实现的,读者可以自己尝试。
对于swap函数,一个比较好的写法如下:
1 void swap(int *i,int *j) 2 { 3 *i = *i ^ *j; 4 *j = *i ^ *j; 5 *i = *i ^ *j; 6 }
异或来交换两个数的写法,不需额外的变量。
整体代码如下:
1 /* 2 *堆排序 3 *丁洋 4 *说明:堆用数组来表示,那么 5 *父节点 i 子节点则为 j = i*2 +1 6 *子节点 i 父节点则为 j = (i-1) / 2 7 * 8 */ 9 #include<stdio.h> 10 #include<stdlib.h> 11 12 void swap(int *i,int *j) 13 { 14 *i = *i ^ *j; 15 *j = *i ^ *j; 16 *i = *i ^ *j; 17 } 18 /* 19 *插入操作 20 *堆尾插入,然后调整 21 */ 22 void Heap_insert_fix(int a[],int n) 23 { 24 int temp; 25 int i,j; 26 i = n; 27 j = (i - 1) / 2;/*父节点*/ 28 temp = a[i];/*记录插入的数据*/ 29 while(i != 0 && j >= 0) 30 { 31 if(a[j] <= temp) 32 break; 33 a[i] = a[j]; 34 i = j; 35 j = (i - 1) / 2; 36 } 37 a[i] = temp; 38 } 39 /* 40 *调用 41 */ 42 void Heap_add(int a[],int n,int Num) 43 { 44 a[n] = Num; 45 Heap_insert_fix(a,n); 46 } 47 48 /* 49 *删除操作 50 *删除根结点,然后调整 51 *从i节点开始,总数有n个 52 */ 53 void Heap_del_fix(int a[],int i,int n) 54 { 55 int j; 56 int temp; 57 temp = a[i]; 58 j = i * 2 + 1;/*子节点*/ 59 while(j < n) 60 { 61 if(a[j] > a[j+1] && j+1 < n) 62 j++; 63 if(a[j] >= temp) 64 break; 65 a[i] = a[j]; 66 i = j; 67 j = i*2 + 1; 68 } 69 a[i] = temp; 70 } 71 /* 72 *调用 73 */ 74 void Heap_sub(int a[],int n) 75 { 76 swap(&a[0],&a[n-1]); 77 Heap_del_fix(a,0,n-1); 78 } 79 80 /* 81 *堆化数组 82 */ 83 void create_heap(int a[], int n) 84 { 85 int i; 86 for(i=n/2-1;i>=0;i--)/*将数组转成堆,分开调整*/ 87 { 88 Heap_del_fix(a,i,n); 89 } 90 } 91 92 /* 93 *堆排序 94 */ 95 void Heap_sort(int a[],int n) 96 { 97 int i; 98 for(i=n-1;i>=1;i--) 99 { 100 swap(&a[0],&a[i]); 101 Heap_del_fix(a,0,i); 102 } 103 } 104 int main() 105 { 106 int i; 107 int a[] = {2,4,8,1}; 108 109 create_heap(a,4); 110 Heap_sort(a,4); 111 for(i=0;i<4;i++) 112 printf("%d ",a[i]); 113 printf("\n"); 114 system("pause"); 115 }
时间复杂度:
由于每次重新恢复堆的时间复杂度为O(logN),共N - 1次重新恢复堆操作,再加上前面建立堆时N / 2次向下调整,每次调整时间复杂度也为O(logN)。二次操作时间相加还是O(N * logN)。故堆排序的时间复杂度为O(N * logN)。STL也实现了堆的相关函数,可以参阅《STL系列之四 heap 堆》
转载于:https://www.cnblogs.com/my-life/p/3489808.html
经典算法系列三----堆排序相关推荐
- 白话经典算法系列之七 堆与堆排序
堆排序与高速排序,归并排序一样都是时间复杂度为O(N*logN)的几种常见排序方法.学习堆排序前,先解说下什么是数据结构中的二叉堆. 二叉堆的定义 二叉堆是全然二叉树或者是近似全然二叉树. 二叉堆满 ...
- 三白话经典算法系列 Shell排序实现
山是包插入的精髓排序排序,这种方法,也被称为窄增量排序.因为DL.Shell至1959提出命名. 该方法的基本思想是:先将整个待排元素序列切割成若干个子序列(由相隔某个"增量"的元 ...
- 白话经典算法系列之——希尔排序的实现
希尔排序的实质就是分组插入排序,该方法又称缩小增量排序,因DL.Shell于1959年提出而得名. 该方法的基本思想是:先将整个待排元素序列分割成若干个子序列(由相隔某个"增量"的 ...
- 机器学习经典算法(三)--指数加权平均
机器学习经典算法(三)–指数加权平均 指数加权平均(Exponentially Weighted Averages)是一些改进梯度下降法重要理论,如上篇博文梯度下降法(2)提到的动量梯度下降法,RMS ...
- 【算法系列 三】 Quene
为什么80%的码农都做不了架构师?>>> 1. 拓扑排序问题(HDU 1285) import java.io.BufferedReader; import java.io.I ...
- 【华为云技术分享】MongoDB经典故障系列三:副本集延迟太高怎么办?
MongoDB副本集延迟太高,数据读取时间过长怎么办?不要慌,菊长教您一个小妙招:在集合创建的时候,就建立好索引,然后按照索引去寻找您所需要的数据.如果觉得比较麻烦,华为云文档数据库服务DDS了解一下 ...
- 白话经典算法系列之中的一个 冒泡排序的三种实现
冒泡排序是很easy理解和实现,,以从小到大排序举例: 设数组长度为N. 1.比較相邻的前后二个数据,假设前面数据大于后面的数据,就将二个数据交换. 2.这样对数组的第0个数据到N-1个数据进行一次遍 ...
- 白话经典算法系列之一 冒泡排序的三种实现
http://blog.csdn.net/morewindows/article/details/6657829 冒泡排序是非常容易理解和实现,,以从小到大排序举例: 设数组长度为N. 1.比较相邻的 ...
- raptor五个数排序流程图_经典算法系列之:选择排序
1.前言 算法,在计算机中的地位,就相当于人类大脑的决策中枢系统,哪怕最简单的算法,其精妙的思维方式,都可以让人开启一扇新的视窗. 算法,它不仅仅只是狭义的用来解决计算机科学领域的问题,更是一种&qu ...
最新文章
- 【Android】Android中判断后台服务是否正在运行
- Centos netperf安装
- Javascript Symbol 隐匿的未来之星
- IOS 2D游戏开发框架 SpriteKit--续(创建敌对精灵)
- Redis Cluster原理初步
- CF476D-Dreamoon and Sets【结论】
- java bufferarray_Java中的ByteBuffer array()方法
- android 原生开发 3d地图 下载_arcgis api 3.x for js 入门开发系列二不同地图服务展示(附源码下载)...
- AWVS扫描器使用入门
- python将json转化为数组_将JSON转换为数组?
- HTML5-单、多选框,按钮
- mrpt在win8.1 64bit + vs2013环境下的安装和编译
- 如何将webp格式转换成png?
- 腾讯的星星海服务器芯片,腾讯云星星海重磅发布两款自研新品 打造软硬一体云计算基础设施...
- 判断已知顺序的三个点是顺时针还是逆时针
- php微云上传,API - 微云
- 笔记本电脑换新硬盘重装系统经验
- C语言从入门到精通第17天(指针和数组联用)
- Linux26期 6月21日
- 原生js获取本地ip地址(自己用)
热门文章
- “3D几何与视觉技术”全球在线研讨会(9月2日到12月16日)
- 内推|百度2020春实习-计算机视觉算法研发工程师-北京
- IoU-aware的目标检测,显著提高定位精度
- python爬虫实战教程分享 或许你可以看一下这篇文章
- 南邮linux期末考试试题,南邮操作系统试卷及答案.doc
- 目标跟踪算法综述:Correlation Filter for UAV-Based Aerial Tracking: A Review and Experimental Evaluation
- php com(),php|luosimao.com文档中心
- 图像分割总体介绍——深度AI科普团队
- 今日头条面试题:生成随机数(根据rand5()生成rand7())
- 一篇关于《1984》读后感