C语言模拟实现堆排序

news2024/11/23 21:33:15

堆排序是一种效率比较高的排序方法,时间复杂度O(n\log n)

堆分为大堆和小堆,如果想要拍升序我们需要建立大堆,而如果想要拍降序则需要建立小堆,在使用堆排序前需要先建立一个堆,如果不会建立可以看我前面写的C语言模拟实现堆的代码。

堆是一个完全二叉树,因此一个数组就是一个完全二叉树。

一、堆的建立

我们可以先写一个图中的数组,然后将其变成一个堆。运行代码如下:

typedef int HPDataType;
typedef struct Heap
{
	HPDataType* a;  //用来表示堆的数组
	int capacity;
	int size;
}Heap;

void  Test01()
{
	Heap hp;
	HeapInit(&hp);  //初始化一个堆
	int arr[] = { 8,5,3,4,8,21,5,4,68,24 };
	int  i = 0;
	int sz = sizeof(arr) / sizeof(int);
	for (i = 0; i < sz; i++)
	{
		HeapPush(&hp, arr[i]);  //将数组arr中的元素一个个插入到堆中的数组中
                                  然后构建成一个堆
	}
	for (i = 0; i < sz; i++)
	{
		arr[i] = hp.a[i];//再将堆中的元素重新把数组的元素覆盖,
                           arr数组中的元素便构成堆
	}
	HeapDestory(&hp);
}

代码运行后的结果如图 ,在逻辑结构上的表示如图:我们可以清楚的看到这是一个小堆。

上述的方法可行,但过于麻烦。

1.向上调整算法构建堆

我们可以直接在原数组arr中使用向上调整算法构建堆。向上调整算法的代码如下 :

void AdjustUp(HPDataType* a, int child)  //构建小堆
{
	assert(a);
	int parent = (child - 1) / 2;
	while (child > 0)
	{
		if (a[child] < a[parent])  //如果孩子小于父亲,内容就互换
		{
			Swap(&a[child], &a[parent]);
			child = parent;
			parent = (child - 1) / 2;
		}
		else
		{
			break;
		}
	}
}

在没有排序前,数组arr的逻辑结构如图: ,在这里我们要构建的是小堆,因此父结点的值小于等于子结点的值。向上调整我们要从上往下看,先看第一个节点8,忽略掉其他的节点,由于只有一个节点,因此它自己构成一个堆。然后看第一个节点和第二个节点,第二个节点5小于8,因此向上调整,数字5和8的位置互换,如图再看第一个节点和第三个节点,数字5大于数字3,因此3和5的位置需要互换,如图:这样前三个节点变构成一个小堆,然后依次往下构建,直到结束。在这里我们只需要比较父结点和子结点的大小,兄弟结点之间没有要求。我们可以看到一个节点就是一个小堆,因此我们只需要从第二个结点开始比较。

由于在物理结构上是一个数组,因此父结点与子结点之间的关系是:parent = (child - 1) / 2、

leftchild = parent * 2 + 1、 rightchild = parent * 2 + 2

代码实现如图:

void  Test01()
{
	Heap hp;
	HeapInit(&hp);
	int arr[] = { 8,5,3,4,8,21,5,4,68,24 };
	int  i = 0;
	int sz = sizeof(arr) / sizeof(int);
	for (i = 1; i < sz; i++)
	{
		AdjustUp(arr, i);
	}
	HeapDestory(&hp);
}

代码运行后结果如图: ,我们可以看出这也是个小堆。

2.向下调整算法构建堆

向下调整算法如下:

void AdjustDown(HPDataType* a, int n, int parent)  //n是数组的大小
{
	assert(a);
	int child = parent * 2 + 1; // 假设左孩子小于右孩子
	while (child < n)
	{
		if (child + 1 < n && a[child] > a[child + 1]) //child+1 < n保证右孩子存在
		{
			child++;
		}  //运行到此处,变量child存储的是最小孩子的位置
		if (a[parent] > a[child])
		{
			Swap(&a[parent], &a[child]);
			parent = child;
			child = parent * 2 + 1;
		}
		else
		{
			break;
		}
	}
}

向下调整算法,我们要从下往上看,如图 由于21,5,4,68,24这些结点没有孩子,因此不需要向下调整,故向下调整算法我们要从最后一个节点的父结点(即非叶子结点的最后一个)开始向下调。由于在数组上有n个空间,因此最后一个结点的位置为n-1,故它的父结点的位置是(n-1-1)/2,故我们要从结点24的父结点8开始向下调。由于结点24大于结点8,因此8不需要向下调整。然后看结点4,结点4的孩子分别是4和68,由于两个孩子中,结点4要小于68,且与父结点相等,因此父结点4也不需要向下调整。依次向上遍历,直到结束。代码如下:

void  Test01()
{
	Heap hp;
	HeapInit(&hp);
	int arr[] = { 8,5,3,4,8,21,5,4,68,24 };
	int  i = 0;
	int sz = sizeof(arr) / sizeof(int);
	for (i = (sz - 2) / 2; i >= 0; --i)
	{
		AdjustDown(arr, sz, i);
	}
	HeapDestory(&hp);
}

运行结果如图 ,我们可以得到一个小堆。

注:运行结果不唯一

二、排序的实现

由于在上述代码中,我们构建的是一个小堆,因此我们要排降序。

上面构建的小堆如图:

 我们排降序的方法是首先把根结点和最后一个结点的位置互换,其次忽略掉最后一个节点(即最小的数字),最后将互换后的根结点向下调整重新构建成堆,重复上述操作便可以排成降序。

小堆的数组形式如图:

运行代码:

void  Test01()
{
	Heap hp;
	HeapInit(&hp);
	int arr[] = { 8,5,3,4,8,21,5,4,68,24 };
	int  i = 0;
	int sz = sizeof(arr) / sizeof(int);
	for (i = (sz - 2) / 2; i >= 0; --i)
	{
		AdjustDown(arr, sz, i);
	}
	int end = sz - 1;//最后一个元素的位置
	while (end > 0)
	{
		Swap(&arr[0], &arr[end]);
		end--;
		AdjustDown(arr, end, 0);
	}
	HeapDestory(&hp);
}

运行结构如图 :

这样便实现堆排序

 

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2230806.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

HCIA笔记整合

第一部分&#xff1a; OSI七层模型 应用层&#xff1a;人机交互 抽象语言--------编码 表示层&#xff1a;编码------二进制 会话层&#xff1a;提供会话号 传输层&#xff1a;TCP/UDP 分段&#xff08;收到MTU值的限制&#xff09; MTU&#xff1a;最大传输单元&#xff…

html简易流程图

效果图 使用htmlcssjs&#xff0c;无图片&#xff0c;没用Canvas demo: <!DOCTYPE html> <html> <head><link href"draw.css" rel"stylesheet" /><script src"draw.js" type"text/javascript"></…

新手BUG:在声明了返回值的函数中不写返回值

本文对两个分别以int和string为返回值类型的函数进行分析&#xff0c;说明了在有返回值的函数中不写返回值会产生的问题。然后给出在编译阶段检查出这样的问题的办法。 一、背景 在软件测试环节发现&#xff0c;函数会在返回之前coredump。经过排查发现&#xff0c;在这个会…

单个相机矫正畸变

1、通过标定助手获取到内参外参&#xff0c;外参在此无效&#xff0c;只用到了内参 2、然后通过halcon算子进行矫正 参考&#xff1a;超人视觉

【骑士放置——最大独立集】

题目 思路 最大独立集n-最小点覆盖n-最大边匹配 代码 #include <bits/stdc.h> using namespace std; #define x first #define y second typedef pair<int, int> PII; const int N 110; int dx[8] {-2, -1, 1, 2, 2, 1, -1, -2}; int dy[8] {1, 2, 2, 1, -1, …

【每日题解】3226. 使两个整数相等的位更改次数

给你两个正整数 n 和 k。 你可以选择 n 的 二进制表示 中任意一个值为 1 的位&#xff0c;并将其改为 0。 返回使得 n 等于 k 所需要的更改次数。如果无法实现&#xff0c;返回 -1。 示例 1&#xff1a; 输入&#xff1a; n 13, k 4 输出&#xff1a; 2 解释&#xff1a…

使用Docker Swarm进行集群管理

&#x1f493; 博客主页&#xff1a;瑕疵的CSDN主页 &#x1f4dd; Gitee主页&#xff1a;瑕疵的gitee主页 ⏩ 文章专栏&#xff1a;《热点资讯》 使用Docker Swarm进行集群管理 引言 Docker Swarm 简介 安装 Docker Ubuntu CentOS 初始化 Swarm 集群 加入 Worker 节点 验证集…

SPA和SSR

单页面应用程序(SPA) 单页面应用(SPA)全称是:Single-page application, SPA应用是在客户端呈现的(术语称:CRS)。 SPA应用默认只返回一个空HTML页面&#xff0c;如:body只有<div id"app"></div>而整个应用程序的内容都是通过JavaScript动态加载&#xf…

初始JavaEE篇——多线程(4):wait、notify,饿汉模式,懒汉模式,指令重排序

找往期文章包括但不限于本期文章中不懂的知识点&#xff1a; 个人主页&#xff1a;我要学编程(ಥ_ಥ)-CSDN博客 所属专栏&#xff1a;JavaEE 目录 wait、notify 方法 多线程练习 单例模式 饿汉模式 懒汉模式 指令重排序 wait、notify 方法 wait 和 我们前面学习的sleep…

MySQL-基础汇总

MySQL-基础汇总 数据库对于任何一个从事后台开发的人说都是永远躲不掉的&#xff0c;任何系统或程序离开了数据的支持都变的毫无意义。而管理数据的工具——数据库就显得尤为重要。本章节我们的核心就是 MySQL&#xff0c;相信很多小伙伴跟我一样&#xff0c;也沉浸在增、删、…

【AD】1-2 AD24软件的中英文版本切换

1.如图设置软件后&#xff0c;关闭软件重新打开。如果想要切换回英文&#xff0c;将③勾选去掉&#xff0c;关闭软件重新在打开即可。

CSS、Less、Scss

CSS、Less和SCSS都是用于描述网页外观的样式表语言&#xff0c;但它们各自具有不同的特点和功能。以下是对这三者的详细阐述及区别对比&#xff1a; 详细阐述 CSS&#xff08;Cascading Style Sheets&#xff09; 定义&#xff1a;CSS是一种用来表现HTML或XML等文件样式的计算机…

【Python项目管理】“无法创建虚拟环境”报错原因及解决方法

一、问题说明 笔者最近在做一个python项目&#xff08;使用pycharm IDE&#xff09;&#xff0c;在添加python解释器时&#xff0c;提示无法创建虚拟环境&#xff08;Unable to create virtual environment&#xff09;&#xff0c;如下2图所示&#xff1a; 【添加python解释…

【实践】某央企研究院如何打造IT监控告警平台?

01客户简介&#xff1a; 案例客户为某央企下属研究院。 02痛点分析&#xff1a; 随着信创国产化持续推进&#xff0c;案例客户已完成部分IT核心系统的替代&#xff0c;部署了一系列国产软硬件设施&#xff0c;如Kylinv10操作系统、融智通网络设备等。由于信创生态不够成熟&a…

qt QBrush详解

1、概述 QBrush是Qt框架中的一个基本图形对象类&#xff0c;它主要用于定义图形的填充模式。QBrush可以用于填充如矩形、椭圆形、多边形等形状&#xff0c;也可以用于绘制背景等。通过QBrush&#xff0c;可以设置填充的颜色、样式&#xff08;如实心、渐变、纹理等&#xff09…

0-1规划的求解

实验类型&#xff1a;◆验证性实验 ◇综合性实验 ◇设计性实验 实验目的&#xff1a;学会使用Matlab编程实现求解0-1规划。 实验内容&#xff1a;1.学习使用Matlab定义子函数的命令function&#xff1b; 2.编程求解0-1型整数规划的枚举法或隐枚举法。 例1&#xff1a;求…

禾川HCQ1控制器程序编译报错如何解决

1、第一次打开用户程序 2、提示库未安装 3、安装库文件 4、脉冲轴库未安装 5、没有错误 去禾川自动化官网,把可以安装的包和库都安装下,程序编译就没有错误了。 6、下载相关包文件

C++进阶-->AVL树的实现

1. AVL树的介绍 1、AVL树的名字来源于他的发明者G. M. Adelson-Velsky和E. M. Landis两个前苏联的科学家&#xff0c;他们名字首元素组成。 2、AVL树就是我们前面二叉搜索树实现的时候提到的平衡二叉搜索树即二叉搜索树的左右孩子都是AVL树&#xff0c;即左右子树的高度差的绝…

【网络安全】|nessus使用

1、扫描结果分析&#xff1a; Sev&#xff1a;漏洞的严重性级别 CVSS&#xff1a;量化漏洞严重性的标准&#xff0c;通过计算得出一个分数&#xff0c;分数越高表示漏洞越严重。 VPR&#xff1a;基于风险的评分系统&#xff0c;帮助组织优先处理风险最高的漏洞。 EPSS&#xf…

P2-5【C语言基本数据类型、运算符和表达式】第五节-知识要点:格式输出函数printf()

讲解视频&#xff1a; P2-5【C语言基本数据类型、运算符和表达式】第五节-知识要点&#xff1a;格式输出函数printf() 知识要点&#xff1a;格式输出函数printf()。 一、任务分析 已知三角形三边a&#xff0c;b&#xff0c;c的值&#xff0c;求三角形的面积。要求输出a&#…