14-堆排序

2023-11-06

堆(Heap)是一种常见的数据结构,常用于存储数据,其本质上是一棵完全二叉树。下面我们来看看如何用数组实现堆结构及其相关功能。

堆的定义

首先来看一下堆的存储结构:堆可以看成是一颗完全二叉树。首先什么是二叉树?借助百度中的解释:

二叉树(binary tree)是指树中节点的度不大于2的有序树,它是一种最简单且最重要的树。二叉树的递归定义为:二叉树是一棵空树,或者是一棵由一个根节点和两棵互不相交的,分别称作根的左子树和右子树组成的非空树;左子树和右子树又同样都是二叉树。

总结起来,二叉树可以看成是下面这种数据结构,每一个节点只有左右两个儿子。

而完全二叉树是在二叉树的基础上满足:所有节点都是非空的,最后一层节点的排布是从左到右排布的。而堆是差不多满足这些条件的完全二叉树,其中堆中又以小根堆最出名。小根堆在之前的基础上满足:根节点的数值是所有节点数值里面最小的、每一个节点的数值都是小于它的左右儿子的数值。

堆结构及操作原理

在代码中,我们计划用一个一维数组来实现这个堆,我们首先给堆每一个节点标上号:

那么我们的一维数组,下标为1的元素存的就是节点1,节点1的左儿子和右儿子分别占据下标为2和下标为3的位置,也就是说,对于某个节点x,它的左儿子位于数组的2x位置,它的右儿子位于数组的2x+1的位置。所以上面的堆在一个一维数组中存储方式如下:

堆有很多操作,但是堆的操作总结起来都可以通过按一定顺序反复调用两个函数来实现,这两个函数是down和up函数,它们的参数都是节点序号,其中down函数对应于将一个节点往树的下方调整,up函数对应于将一个节点往上调整。

down函数是将当前节点于其左儿子和右儿子节点的数值进行对比,哪个儿子的数值小就与当前节点换位置:

up函数是将当前节点与其父节点进行对比,一旦当前节点比父节点要小,那么就将当前节点与其父节点进行调换:

利用这两个函数,我们可以实现堆的几乎所有常见的操作,不过在此之前,我们还需要引入一个变量idx,并且创建一个一维数组heap,它表示我们的数组当前使用到的下标的位置,也表示最后一个节点的序号。

1、往堆中插入一个数:我们可以令heap数组的当前下标idx加一,将新数据赋予给新位置。但是这还不够,因为插入到新数不一定是最大的(刚插入的数都是在树的最下层),所以还需要将新的节点往上调,即调用up函数。

heap[++idx]=x;
up(x);

2、在堆中删除一个数:在堆中删除一个数我们的思路是先令这个数和heap数组的最末尾的数进行交换,然后再将末尾的数据删除。为什么要这么做?因为我们要删除的数一般位于数组的中间,删除数组中间的数一般比较麻烦(需要整体移动数组后边的元素)。所以我们采用迂回的方式,先将当前要删掉的数据调整到数组末尾(也就是当前的idx下标的地方)然后再将idx--就可以实现删除了!但是这样相当于将一个不确定的数移到了中间,我们也不确定是需要将其向上调?还是向上调?所以索性就两个操作都写上,需要哪个用哪个。

heap[n]=heap[idx];
idx--;
up[n];
down[n];

Down和Up函数代码

既然Down函数和Up函数如此重要,下面我们来看看如何实现这两个函数。首先是Down函数:

void Down(int x)
{
	int t = x;
	if (2 * x <= idx && heap[2*x]<heap[t])t = 2 * x;
	if (2 * x + 1 <= idx && heap[2 * x + 1] < heap[t])t = 2 * x + 1;
	if (x != t)
	{
		swap(&heap[x], &heap[t]);
	    my__Down(t);
	}
}

Down函数主要是由两个判断,它们分别对应父节点对左儿子和右儿子的比较,首先是确定是否有左儿子和右儿子,即对应的下标x,2x和2x+1都比当前值idx小于或等于。其次才对比左右儿子和父节点的大小,变量t记录的是三个节点中数值最小的那个节点的下标。如果对比出来最小的下标不是父节点(x!=t),那么需要将父节点和最小的节点进行数值交换,最后继续递归这个过程,直至父节点就是最小的节点或者是最后一层。 

然后就是Up函数的代码,相较于Down函数,Up函数就是子节点与其父节点进行数值对比:

void Up(int x)
{
	while (x / 2 && heap[x / 2] > heap[x])
	{
		my_swap(&heap[x / 2], &heap[x]);
		x = x / 2;
	}
}

同样也需要多次进行比较(while循环往上走),想要获取一个点的父节点下标,只需要将其下标除以二即可(由于是int类型,余数自动省略)。其它就是对比以及判断x/2是否为0,即是否为根节点。

初始化

说了这么多,最后还需要看如何对堆进行初始化。首先我们需要准备一个一维数组:

int main()
{
	int n = 0;
	cin >> n;
	idx = n;
	for (int i = 0; i < n; i++)
		cin >> heap[i];
	return 0;
}

然后就是初始化这个一维数组成为一个堆,这里采用一个巧妙地方法,先上代码:

for (int i = idx / 2; i != 0; i--)
    Down(i);

这个代码地意思是从倒数第二层开始,将本层的节点从左到右都Down一遍,将大的元素往下调,小的元素往上调,这样就可以逐层向上获取一个堆。

 

所以总的代码如下:

#include<iostream>

using namespace std;

const int N = 100;
int heap[N];
int idx;

void my_swap(int* x, int* y)
{
	int p = *x;
	*x = *y;
	*y = p;

}


void Down(int x)
{
	int t = x;
	if (2 * x <= idx && heap[2*x]<heap[t])t = 2 * x;
	if (2 * x + 1 <= idx && heap[2 * x + 1] < heap[t])t = 2 * x + 1;
	if (x != t)
	{
		my_swap(&heap[x], &heap[t]);
		Down(t);
	}
}

void Up(int x)
{
	while (x / 2 && heap[x / 2] > heap[x])
	{
		my_swap(&heap[x / 2], &heap[x]);
		x = x / 2;
	}
}

int main()
{
	int n = 0;
	cin >> n;
	idx = n;
	for (int i = 0; i < n; i++)
		cin >> heap[i];
	for (int i = n / 2; i != 0; i--)
		Down(i);
	return 0;
}

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

14-堆排序 的相关文章

随机推荐

  • 一文带你了解 MQTT 协议(连接 ONE-NET平台)

    MQTT 协议连接 ONE NET 详解 写在前面 本文采用 网络调试助手 发送MQTT协议报文 16进制 连接 ONE NET 平台 采用的 为 MQTT v3 1 1 标准协议 带你直接 学会 MQTT 协议 一 ONE NET 端创建
  • Ubuntu20.04安装vscode打开出现花屏

    目录 前言 出现原因 解决方法 探索 最终方案 前言 最近在Ubuntu20 04安装vscode打开后出现了花屏的情况 在网上查找各种方法后终于解决 在这里记录一下 希望对大家有所帮助 出现原因 出现这样的问题是因为vscode开了GPU
  • idea中创建git分支

    1 使用idea打开项目 点击项目右下方的分支按钮 2 选择New Branch 3 输入分支名称后 create即可 4 提交和推送 注意 如果没有修改代码 就不需要提交 只需推送即可创建分支
  • 数据结构--双链表的c/c++实现(超详细注释/实验报告)

    数据结构 双链表的c c 实现 超详细注释 实验报告 知识小回顾 如果希望从表中快速确定某一个结点的前去 其中一个解决方法就是在单链表的每个结点再增加一个指向其前去的指针域prior 这样形成的链表中就有两条方向不同的链 称之为双向链表 D
  • 100天精通Python(数据分析篇)——第57天:Pandas读写Excel(read_excel、to_excel参数说明+代码实战)

    文章目录 1 read excel 读取Excel文件 io sheet name header names index col usecols squeeze skiprows 2 to excel 写入Excel文件 excel wri
  • Unity Android 真机调试 + 夜神模拟器调试 + ADB Logcat

    备注 调试前需要先检测java和SDK的环境变量是否OK 在CMD中输入java和adb检测 官方文档 https docs unity3d com Manual AttachingMonoDevelopDebuggerToAnAndroi
  • Python+unittest+requests+HTMLTestRunner 完整的接口自动化测试框架搭建过程实战

    目录 前言 第一讲 框架结构简解 第二讲 测试接口服务 第三讲 配置文件读取 第四讲 读取Excel中的case 第五讲 发送requests请求 第六讲 参数动态化 第七讲 使用unittest断言 第八讲 HTMLTestRunner源
  • spring事件发布

    最近一个需求 接口监控异常 需要进行一连串逻辑处理 又新加需要给运维人员发短信 异步处理 不能影响源代码逻辑 因此用到事件发布器 在事件驱动中有三个比较重要的组件 Event 发布的事件对象 EventPublisher 事件发布对象 Ev
  • 姓名 抽奖 ppt 模板_PPT中制作姓名滚动抽奖小动画

    想看视频教程的直接拉到文章尾部观看 本次教程教大家如何简单制作姓名滚动抽奖的小动画 效果如下 进入幻灯片播放界面后 在页面任意位置单击鼠标即可开始抽奖 再单击一次鼠标暂停 再单击一次鼠标还可以重新开始 下面来看一下如何制作 制作过程中主要使
  • k8s之Ingress篇七层代理

    Ingress介绍 Ingress官网定义 Ingress可以把进入到集群内部的请求转发到集群中的一些服务上 从而可以把服务映射到集群外部 Ingress 能把集群内Service 配置成外网能够访问的 URL 流量负载均衡 提供基于域名访
  • Unity 连接WebSocket(ws://)服务器

    Unity 连接ws 不用任何插件 忙活了一天终于搞定了 一直连接不上 原来是没有添加header 代码比较简单 直接贴出来普度众生 using System using System Net WebSockets using System
  • 爬虫学习心得

    在python环境中对小说进行爬取 一般需要安装爬虫所需的第三方库 目前我所使用的为BS4和Requests BS4库安装 Beautiful Soup 简称 BS4 其中 4 表示版本号 是一个 Python 第三方库 它可以从 HTML
  • 图解通信原理与案例分析-13:无线对讲机案例--频率调制实现语音点对点无线通信

    前言 在 无线调幅广播案例 中 拆解了通过幅度调制AM实现点对多点广播通信的基本原理 本文 将通过无线对讲机的案例 拆解了通过频率调制FM实现点对多点广播通信的基本原理 本文的重点在 1 频率调制与解调的基本原理 2 频率调制与幅度调制的本
  • nvm常用命令有哪些?nvm如何切换node版本?nvm如何下载node?nvm安装包

    之前公司有很多老项目 需要切换node低版本才能正常使用 但是还有使用node高版本新项目 总不能每次更换项目就卸载重装对应版本的node 所以就使用了nvm来管理node版本 每次使用时 nvm命令就记得很清楚 可是长时间不使用 就会有点
  • Java方法的重载

    方法的重载 函数名相同 形式参数不同 方法重载的规则 1 方法名称必须相同 2 参数列表必须不同 个数 或者 参数类型 或者 排列顺序 3 方法的返回类型可以相同也可以不相同 4 仅仅返回类型不同不足以成为方法的重载 方法名称相同时 编译器
  • C++实践之Qt学习(五):Qt设计器介绍、信号和槽机制

    文章目录 Qt设计器 对象树 信号和槽 信号和槽机制 设计器上添加信号与槽 方式1 方式2 Qt设计器 分为几个区域 控件 部件区 界面编辑区 动作编辑 信号槽编辑区 对象区 对象属性区 部件区又分为几类 Layouts 布局 Spacer
  • 图像综合处理小设计实验—opencv背景分割,硬币检测

    图像综合处理小设计 opencv背景分割 硬币检测 一 机器视觉图像的目标与背景的分割与提取 1 主要要求 对输入图像可以达到目标和背景的分割 建议方法 1 将已知图像进行消噪处理 2 对彩色图像进行目标和背景分析 3 通过阈值法将图像进行
  • 【Vue2.0源码学习】模板编译篇-模板解析(代码生成阶段)

    文章目录 1 前言 2 如何根据AST生成render函数 3 回归源码 3 1 元素节点 3 2 文本节点 3 3 注释节点 4 总结 1 前言 经过前几篇文章 我们把用户所写的模板字符串先经过解析阶段解析生成对应的抽象语法树AST 接着
  • VMware Workstation 17 Pro的下载&&安装&&使用

    目录 一 下载 二 安装 三 检查网络连接 方式一 简便版 方式二 麻烦版 四 使用 创建虚拟机 使用命令 快照的使用 拍摄快照 恢复快照 克隆虚拟机 移除虚拟机 一 下载 下载地址 Windows 虚拟机 Workstation Pro
  • 14-堆排序

    堆 Heap 是一种常见的数据结构 常用于存储数据 其本质上是一棵完全二叉树 下面我们来看看如何用数组实现堆结构及其相关功能 堆的定义 首先来看一下堆的存储结构 堆可以看成是一颗完全二叉树 首先什么是二叉树 借助百度中的解释 二叉树 bin