堆排序和插入排序(小博学习排序第四天)_一组无序的10个数用插入法构造一个大根堆_wlisonate的博客-程序员宅基地

技术标签: 算法  堆排序  数据结构与算法  插入排序  

1,堆排序

堆排序的算法步骤;

  • 把无序数组构建成一个二叉堆,需要从小到大排序,则构建最大堆;需要从大到小排序,则构建小顶堆。
  • 循环删除堆顶元素,替换到二叉堆的末尾,调整堆产生新的堆顶。

下来我们讲解他的实现过程

构造堆

将无序数组构造成一个大根堆(升序用大根堆,降序就用小根堆)

假设存在以下数组

主要思路:第一次保证0~0位置大根堆结构(废话),第二次保证0~1位置大根堆结构,第三次保证0~2位置大根堆结构...直到保证0~n-1位置大根堆结构(每次新插入的数据都与其父结点进行比较,如果插入的数比父结点大,则与父结点交换,否则一直向上交换,直到小于等于父结点,或者来到了顶端)

插入6的时候,6大于他的父结点3,即arr(1)>arr(0),则交换;此时,保证了0~1位置是大根堆结构,如下图:

                                     (友情提示:待交换的数为蓝色,交换后的数为绿色)

 插入8的时候,8大于其父结点6,即arr(2)>arr(0),则交换;此时,保证了0~2位置是大根堆结构,如下图

插入5的时候,5大于其父结点3,则交换,交换之后,5又发现比8小,所以不交换;此时,保证了0~3位置大根堆结构,如下图 

插入7的时候,7大于其父结点5,则交换,交换之后,7又发现比8小,所以不交换;此时整个数组已经是大根堆结构 

 

2.2 固定最大值再构造堆

此时,我们已经得到一个大根堆,下面将顶端的数与最后一位数交换,然后将剩余的数再构造成一个大根堆

                                    (友情提示:黑色的为固定好的数字,不再参与排序) 

 此时最大数8已经来到末尾,则固定不动,后面只需要对顶端的数据进行操作即可,拿顶端的数与其左右孩子较大的数进行比较,如果顶端的数大于其左右孩子较大的数,则停止,如果顶端的数小于其左右孩子较大的数,则交换,然后继续与下面的孩子进行比较

下图中,5的左右孩子中,左孩子7比右孩子6大,则5与7进行比较,发现5<7,则交换;交换后,发现5已经大于他的左孩子,说明剩余的数已经构成大根堆,后面就是重复固定最大值,然后构造大根堆

如下图:顶端数7与末尾数3进行交换,固定好7,

剩余的数开始构造大根堆 ,然后顶端数与末尾数交换,固定最大值再构造大根堆,重复执行上面的操作,最终会得到有序数组

以上就是他的实现过程现在让我们讲解代码部分

1,首先我们得在数组中建立一个大顶堆或者小顶堆,代码如下面展示

/创造一个大顶堆
void downAdjust(int *a,int index,int length){
  int lchild,rchild;
  //创建左右子树
  lchild=index*2+1;
  rchild=index*2+2;
  //将最初的点定为最大的点
  int max=index;
  //在左右子树中找出比父亲结点大的点
  if(lchild<length&&a[lchild]>a[max]){
    max=lchild;
  }
  if(rchild<length&&a[rchild]>a[max]){
    max=rchild;
  }
  //如果最大的不是指定位置的值,则进行互换
  if(max!=index){
    //将找到的点和max进行互换
    swap(a[max],a[index]);
    //继续进行递归,在以max为根结点的树中找最大值
    downAdjust(a,max,length);
  }
}

2,进行堆排序

void HeapSort(int *a,int length){
  //从他的每个非叶子节点进行调整,原因是在进行大顶堆调整的时候,内部进行创建左右子树
  //所以只需管他所以的非叶子节点
  for(int i=length/2-1;i>=0;i--){
    downAdjust(a,i,length);
  }
  for(int j=length-1;j>0;j--){
    //将最大的值换到最后面
    swap(a[0],a[j]);
    //重新调整大顶堆,这里注意他的长度已经变了,长度一直在减一
    downAdjust(a,0,j);
  }
}

 2,插入排序

/******************* 排序规则 *******************

    每次处理就是将无序数列的第一个元素与有序数列
    的元素从后往前逐个进行比较,找出插入位置,将
    该元素插入到有序数列的合适位置中。

    稳定性:插入排序是稳定的

***********************************************/

插入排序比较简单,相信大家看排序规则就可以看懂,我们直接上代码

void Insert_Sort(int *a,int length){
  int temp=0;
  int index=0;
  for(int i=1;i<length;i++){
    temp=a[i];
    index=i;
    for(int j=i-1;j>=0;j--){
      if(temp<a[j]){
        a[j+1]=a[j];
        index=j;
      }
      else{
        break;
      }
    }
    a[index]=temp;
  }
}

完整代码展示

//小博学习排序第四天
#include<iostream>
#include<algorithm>
using namespace std;
//堆排序是不稳定的排序
//创造一个大顶堆
void downAdjust(int *a,int index,int length){
  int lchild,rchild;
  //创建左右子树
  lchild=index*2+1;
  rchild=index*2+2;
  //将最初的点定为最大的点
  int max=index;
  //在左右子树中找出比父亲结点大的点
  if(lchild<length&&a[lchild]>a[max]){
    max=lchild;
  }
  if(rchild<length&&a[rchild]>a[max]){
    max=rchild;
  }
  //如果最大的不是指定位置的值,则进行互换
  if(max!=index){
    //将找到的点和max进行互换
    swap(a[max],a[index]);
    //继续进行递归,在以max为根结点的树中找最大值
    downAdjust(a,max,length);
  }
}
//开始进行堆排序
void HeapSort(int *a,int length){
  //从他的每个非叶子节点进行调整,原因是在进行大顶堆调整的时候,内部进行创建左右子树
  //所以只需管他所以的非叶子节点
  for(int i=length/2-1;i>=0;i--){
    downAdjust(a,i,length);
  }
  for(int j=length-1;j>0;j--){
    //将最大的值换到最后面
    swap(a[0],a[j]);
    //重新调整大顶堆,这里注意他的长度已经变了,长度一直在减一
    downAdjust(a,0,j);
  }
}
//附加写一个插入排序
/******************* 排序规则 *******************

	每次处理就是将无序数列的第一个元素与有序数列
	的元素从后往前逐个进行比较,找出插入位置,将
	该元素插入到有序数列的合适位置中。

	稳定性:插入排序是稳定的

***********************************************/
void Insert_Sort(int *a,int length){
  int temp=0;
  int index=0;
  for(int i=1;i<length;i++){
    temp=a[i];
    index=i;
    for(int j=i-1;j>=0;j--){
      if(temp<a[j]){
        a[j+1]=a[j];
        index=j;
      }
      else{
        break;
      }
    }
    a[index]=temp;
  }
}
int main(int argc, char const *argv[]) {
  int a1[]={1,3,2,6,5,4,7,8,9};
  int a3[]={1,3,2,6,5,4,7,8,9};
  int length=sizeof(a1)/sizeof(int);
  HeapSort(a1,length);
  for(int i=0;i<length;i++){
    cout<<a1[i]<<" ";
  }
  cout<<endl;
  Insert_Sort(a3,length);
  for(int i=0;i<length;i++){
    cout<<a3[i]<<" ";
  }
  cout<<endl;
  return 0;
}

结果展示

版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://blog.csdn.net/weixin_43271086/article/details/90246051

智能推荐

Windows 2008 R2环境下的Oracle 11G R2 RAC+ASM 虚拟环境安装指南V1.0_Data & safety的博客-程序员宅基地

1 环境规划 如上图所示,实验环境中采用Oracle VM VirtualBox虚拟了两台服务器分别是RAC1和RAC2,它们各有两条网线分别用于公共服务和内部互联;群集使用的共享存储由ISCSI提供的两块磁盘OCR和ASM。软件环境方面,操作系统选择Windows 2008 R2企业版。数据库采用 Oracle 11G R2(11.2.0.1)和win64_11gR2_grid(RAC基础架构软...

NX10.0安装教程_Eva215665的博客-程序员宅基地

资源下载:下载,提取码:4epw步骤1鼠标右击【UG NX10.0(64bit)】选择【解压到 UG NX10.0(64bit)】步骤2打开解压后的文件夹,鼠标右击【NX10.0_JAVA-x64位】选择【以管理员身份运行】。步骤3点击【下一步】步骤4点击【下一步】步骤5点击【下一步】步骤6Java JDK安装大约需要1分钟步骤7Java JDK安装完毕,点击【关闭】步骤8双击打开安装包解压后的【UG NX10.0(64bit)】文件夹中的【激活文件】文件夹步

Facebook大规模时序预测『真』神器—Prophet_chvalrous的博客-程序员宅基地

本文转载自:http://shujuren.org/article/351.html作者:悟乙己概述:作为经统专业看到预测的packages很眼馋。除了之前的forecast包,现在这个prophet功能也很强大。而且! 适合工业界+商业场景的应用。并不喜欢理论分析,能直接上案例的,一般不码字,力求简单粗暴!!同时,本篇内容会同步更新于个人BLOG:http://blog.

【Java演示】什么是链表?数据结构(三)_爱做梦的鱼的博客-程序员宅基地

目录链表:随机存储,顺序访问(读取)前言一、单向链表什么叫随机存储呢?链表的基本操作1. 查找节点2. 更新节点3. 插入节点3.1. 尾部插入3.2. 头部插入3.3. 中间插入4. 删除元素4.1. 尾部删除4.1. 头部删除4.1. 中间删除二、双向链表链表:随机存储,顺序访问(读取)前言本博文的大部分插图来自于《漫画算法——小灰》,也复制了该书部分文字我加了一些自己的总结、代码(...

3配置的笔记本能不能运行博图v15_工控、电气工程师笔记本工作站选择指南_weixin_39559895的博客-程序员宅基地

根据我这几天的研究和探索,今天给大家提供一些合适的笔记本,仅供参考。需要说明几点:1、本篇文章只适合于搞工控设计、电气设计工程师,不适合其他用途。2、这些选项本着耐用、舒适的原则进行选择,所以价格一般偏贵,在10k-17k之间。3、仅代表个人观点,不是权威评测,本篇文章只是进行推荐。4、如果有更好的选择或者我说的有哪些不对的,期望各位同学批评指正。5、介绍顺序根据推荐指数进行排练。切入正题。1、戴...

冒泡排序c语言程序,冒泡排序(C语言实现)_缪华武的博客-程序员宅基地

冒泡排序(C语言实现)导语:C语言的设计目标是提供一种能以简易的方式编译、处理低级存储器、产生少量的机器码以及不需要任何运行环境支持便能运行的编程语言。下面我们来看看冒泡排序(C语言实现),希望对大家有所帮助。冒泡排序是一种简单常用的交换排序方法。集体实现的算法思路:将待排序记录中第一个记录与第二个记录做比较,如果第一个记录大于第二个记录,则交换两个记录的位置,然后继续将第一个记录与第三个记录进行...

随便推点

python二次开发攻略-ABAQUS Python二次开发攻略_weixin_37988176的博客-程序员宅基地

第一部分 引言第1章 Abaqus二次开发简介 121.1 为什么是Python 121.2 Python、FORTRAN与Abaqus 131.3 基于Python二次开发 14第2章 Python能力确认 172.1 测试程序 172.2 程序运行结果 22第3章 脚本的运行与开发环境 233.1 Abaqus中脚本的运行 233.1.1 命令区KCLI(Kernel Command Line...

Linux 系统设置时间和获取时间_time.tv_sec_DOTA2真实玩家的博客-程序员宅基地

手里的智能锁项目 , 做了个菜单,设置时间的功能 , 弄了大半天弄完了,  记录一下方法1设置时间设置时间需要2个结构体,分别是struct tm 和struct timeval还有一个长整型的time_t类型, 总共4个步骤。1.1 把tm类型里的成员(年 月 日 时 分 秒)逐个赋值struct tm { /* * the number of seconds after ...

gis海量资源网盘提供VIP账号无广告高速下载 (更新更多资源)_城通网盘vip账号分享_冷月宫主的博客-程序员宅基地

资源网盘下载地址:http://laoheitan.bego.cc/城通网盘 vip帐号共享   省去 烦人的 广告  多任务同时下载 (打开网盘http://laoheitan.bego.cc/后,登录VIP账号。再获取资源下载的链接后,就可享有无广告,高速下载)VIP账号:(账号

夜光带你走进我擅长的领域:SpringBOOT(7)_springboot 领域_GeniusTeam-夜光的博客-程序员宅基地

夜光序言:你过得太闲,才有时间执着在无意义的事情上,才有时间无病呻吟所谓痛苦。你看那些忙碌的人,他们的时间都花在努力上。正文:缓存支持7.1注解配置与EhCache使用7.1.1pom文件引入 &lt;dependency&gt; &lt;groupId&gt;org.springframework.b...

用F5529控制OLED输出汉字,字符,以及bmp图片_三丰杂货铺的博客-程序员宅基地

基于F5529以及G2553的OLED显示   本文主要是给出F5529以及G2553的工程,然后针对如何使用文件里的函数进行说明。对于OLED的原理不进行细致说明。 OLED的I2C时钟一定要配置准确,不然会无法通信。受到delay的影响要会更改字的大小,8X8的字体比16X16的多一行 F5529的OLED资料: G2553的OLED资料:https...

推荐文章

热门文章

相关标签