二叉树的顺序存储——堆——初识堆排序

news2025/1/10 11:59:27

前面我们学过可以把完全二叉树存入到顺序表中,然后利用完全二叉树的情缘关系,就可以通过数组下标来联系。
在这里插入图片描述
但是并不是把二叉树存入到数组中就是堆了,要看原原来的二叉树是否满足:所有的父都小于等于子,或者所有的父都大于等于子——既小堆大堆
在这里插入图片描述
现在我们用代码来实现数据存入到顺序表中,并且是小堆
首先需要创建一个顺序表的结构体
在这里插入图片描述
然后初始化

void HeapInit(Heap* php)//初始化
{
	assert(php);
	php->a = NULL;
	php->capacity = php->size = 0;
}

放入数据
首先要用指针开辟一块空间并判断是否需要扩容,然后把数据尾插进去

void HeapPush(Heap* php, HpDatatype x)//放入数据
{
	assert(php);
	//扩容
	if (php->capacity == php->size)
	{
		int newcapacity = php->capacity == 0 ? 4 : php->capacity * 2;
		HpDatatype* tmp = (HpDatatype*)realloc(php->a, sizeof(HpDatatype)*newcapacity);
		if (tmp == NULL)
		{
			perror("realloc fail");
			exit(-1);
		}
		php->a = tmp;
		php->capacity = newcapacity;
	}
	php->a[php->size] = x;
	php->size++;
	Adjust(php->a, php->size - 1);//调整
}

但是因为这个数组要满足小堆,所以尾插进去的数还需要进一步的调整
在这里插入图片描述
那么这里的代码是如何实现的呢
在这里插入图片描述

到这里的时候我们没插入一个数据就都可以把数据从新调整为一个堆,那么我们为什么要把数据按照堆的方式存储呢?
现在我们来写一个堆数据删除的代码就能感受到堆的作用:
在这里插入图片描述

void AdiustDown(HpDatatype* a, int n, int parent)
{
	int child = parent * 2 + 1;//先假设和根交换的是他的左儿子
	while (child<n)//当child=parent*2+1已经超出了数组的范围,那么就说明他下面已经没有儿子了,此时也是结束循环
	{
		if (child+1<n && a[child + 1] < a[child])//如果假设错误,那么就换成右儿子,但是这里要注意的child+1(右儿子)存在
		{
			child++;
		}
		if (a[child] < a[parent])//判断是否需要换
		{
			Swap(&a[child], &a[parent]);//交换
			//尾下一次循环做准备
			parent = child;
			child = parent * 2 + 1;
		}
		else//如果不用换就直接跳出循环
		{
			break;
		}
	}
}

void HeapPop(Heap* php)//删除根
{
	assert(php);
	assert(php->size>0);
	Swap(&php->a[0], &php->a[php->size - 1]);//交换
	php->size--;//尾删
	//向下调整
	 AdiustDown(php->a, php->size, 0);


}

有了这个删根代码,我们在加上取根代码,和判空代码,便可实现数据的排序打印


HpDatatype  HeapTop(Heap* php)//返回根值
{
	assert(php);
	assert(php->size > 0);

	return php->a[0];
}

bool HeapEmpty(Heap* php)//判空
{
	assert(php);
	return php->size==0;
}
while (!HeapEmpty(&st))
	{
		printf("%d ", HeapTop(&st));//打印顶值
			HeapPop(&st);
	}

在这里插入图片描述

如果把上面插入数据和删除根向下调整的判断语句的小于改成大于那么就实现了打印出来的数据时从大到小的排序
在这里插入图片描述

这里就体现出了堆的魅力,当一组数据时以堆的形式储存的,那么他在排序的时候的时间复杂度就是
O(logN2),而之前我们学习的冒泡排序的时间复杂度是O(N2),显然堆的排序时间复杂度更低

但是这里平不是用堆来排序的实际用法,因为如果给我们一个数组,进行排序,我们是要实际改变数组里面值的位置,并不是像这里这样pop一次然后取根打印出来,即使我们每次用取出来的根值去覆盖原来的数组,那么我们要用这样的堆就需要写上面所以的建立堆的数据结构代码,显然是太麻烦了。

那么我们是否可以:
在这里插入图片描述
把给的数组变成堆的时候我们就要进行排序,因为这里并没有上面写的数据结构的堆,所以我们无法取根然后再打印,——之前也说了这种方法是不会把原本的数组改变成有有序的,

所以之下要讲的才是如何在把一个数组已经变成堆的情况下进行排序:

降序排序-——恰恰是把数组变成大堆,升序排序恰恰是把数组变成小堆
为什么要这样呢?

在这里插入图片描述
升序代码:

#include<stdio.h>
#include<stdlib.h>
#include<assert.h>
#include<stdbool.h>

void Swap(int* child, int* parent)//交换
{
	int temp = *child;
	*child = *parent;
	*parent = temp;
}

Adjust(int* a, int child)//向上调整形成堆
{
	int parent = (child - 1) / 2;
	while (child > 0)
	{
		if (a[parent] < a[child])
		{
			Swap(&a[parent], &a[child]);
			child = parent;
			parent = (parent - 1) / 2;
		}
		else
		{
			break;
		}
	}
}

AdiustDown(int* a, int n, int parent)//向下调整
{
	int child = parent * 2 + 1;
	while (child<n)
	{
		if (child + 1 < n && a[child + 1] > a[child])
		{
			child++;
		}
		if (a[child] > a[parent])
		{
			Swap(&a[child],&a[parent]);
			parent = child;
			child = parent * 2 + 1;
		}
		else
		{
			break;
		}
		
	}
}
int main()
{
int arr[] = { 90,56,3,46,1,2,89 };
int n = sizeof(arr) / sizeof(int);
for (int i = 1; i < n; i++)
{
	Adjust(arr, i);//调整
}
int end = n - 1;//最后一个数的下标
while (end > 0)
{
	Swap(&arr[0], &arr[end]);
	//向下调整
	AdiustDown(arr, end, 0);
	end--;
}



for (int j = 0; j < n; j++)
{
	printf("%d ", arr[j]);
}

return 0;
}

在这里插入图片描述

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

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

相关文章

十二、【漏洞复现】Rails任意文件读取(CVE-2019-5418)

十二、【漏洞复现】Rails任意文件读取(CVE-2019-5418&#xff09; 12.1、漏洞原理 Ruby on Rails是一个使用 Ruby 语言写的开源 Web 应用框架&#xff0c;它是严格按照 MVC 结构开发的。它努力使自身保持简单&#xff0c;来使实际的应用开发时的代码更少&#xff0c;使用最少…

JavaScript系列从入门到精通系列第十三篇:JavaScript中基本数据类型和引用数据类型,创建对象的两种方式

一&#xff1a;基本数据类型与引用数据类型 基本数据类型&#xff1a;String Number Boolean Null Undefined 引用数据类型&#xff1a;Object 我们的内存分成了两大块&#xff0c;一是栈内存二是堆内存。变量都是保存到栈内存中&#xff0c;var a 123; a和123都在栈空间&…

互联网Java工程师面试题·ZooKeeper 篇·第一弹

目录 1. ZooKeeper 面试题&#xff1f; 2. ZooKeeper 提供了什么&#xff1f; 3. Zookeeper 文件系统 4. ZAB 协议&#xff1f; 5. 四种类型的数据节点 Znode 6. Zookeeper Watcher 机制 -- 数据变更通知 7. 客户端注册 Watcher 实现 8. 服务端处理 Watcher 实现 9. 客…

Redis最常见的5种应用场景

Redis作为当今最流行的内存数据库&#xff0c;已经成为服务端加速的必备工具之一。对于Redis为什么那么快&#xff1f;以及Redis采用单线程&#xff0c;但为什么反而获得更高的性能的疑问&#xff0c;在之前的Redis为什么那么快&#xff1f;一文中&#xff0c;已经有所介绍。 …

TCP端口崩溃,msg:socket(): Too many open files

一、现象 linux系统中运行了一个TCP服务器&#xff0c;该服务器监听的TCP端口为10000。但是长时间运行时发现该端口会崩溃&#xff0c;TCP客户端连接该端口会失败&#xff1a; 可以看到进行三次握手时&#xff0c;TCP客户端向该TCP服务器的10000端口发送了SYN报文&#xff0c;…

Qt 综合练习小项目--反金币(1/2)

目录 1 项目简介 2 项目基本配置 2.1 创建项目 2.2 添加资源 3 主场景 3.1 设置游戏主场景配置 3.2 设置背景图片 3.3 创建开始按钮 3.4 开始按钮跳跃特效实现 3.5 创建选择关卡场景 3.6 点击开始按钮进入选择关卡场景 1 项目简介 翻金币项目是一款经典的益智类游戏…

开发过程教学——交友小程序

交友小程序 1. 我的基本信息2. 我的人脉2.1 我的关注2.2 我的粉丝 3. 我的视频4. 我的相册 特别注意&#xff1a;由于小程序分包限制2M以内&#xff0c;所以要注意图片和视频的处理。 1. 我的基本信息 数据库表&#xff1a; 我的基本信息我的登录退出记录我的登录状态&#x…

roarctf_2019_easy_pwn

roarctf_2019_easy_pwn Arch: amd64-64-little RELRO: Full RELRO Stack: Canary found NX: NX enabled PIE: PIE enabled64位&#xff0c;保护全开 __int64 ADD() {__int64 result; // raxint i; // [rsp4h] [rbp-1Ch]int v2; // [rsp8h] [rbp-18h]int…

数学建模Matlab之基础操作

作者由于后续课程也要学习Matlab&#xff0c;并且之前也进行了一些数学建模的练习&#xff08;虽然是论文手&#xff09;&#xff0c;所以花了几天零碎时间学习Matlab的基础操作&#xff0c;特此整理。 基本运算 a55 %加法&#xff0c;同理减法 b2^3 %立方 c5*2 %乘法 x 1; …

93、Redis 之 使用连接池管理Redis6.0以上的连接 及 消息的订阅与发布

★ 使用连接池管理Redis连接 从Redis 6.0开始&#xff0c;Redis可支持使用多线程来接收、处理客户端命令&#xff0c;因此应用程序可使用连接池来管理Redis连接。 上一章讲的是创建单个连接来操作redis数据库&#xff0c;这次使用连接池来操作redis数据库 Lettuce连接池 支持…

Flutter笔记:手写并发布一个人机滑动验证码插件

Flutter笔记 手写一个人机滑块验证码 作者&#xff1a;李俊才 &#xff08;jcLee95&#xff09;&#xff1a;https://blog.csdn.net/qq_28550263 邮箱 &#xff1a;291148484163.com 本文地址&#xff1a;https://blog.csdn.net/qq_28550263/article/details/133529459 写 Flut…

【深蓝学院】手写VIO第4章--基于滑动窗口算法的 VIO 系统:可观性和 一致性--作业

0. 内容 T1. 参考SLAM14讲P247直接可写&#xff0c;注意 ξ 1 , ξ 2 \xi_1,\xi_2 ξ1​,ξ2​之间有约束&#xff08;关系&#xff09;。 套用舒尔补公式&#xff1a; marg掉 ξ 1 \xi_1 ξ1​之后&#xff0c;信息被传递到 L 1 和 L 2 L_1和L_2 L1​和L2​之间了。 T2. …

同学苹果ios的ipa文件应用企业代签选择签名商看看这篇文章你再去吧

同学我们要知道随着互联网的发展&#xff0c;苹果应用市场的火爆&#xff0c;越来越多的开发者加入到苹果应用开发行业中来。同时&#xff0c;苹果应用市场上的应用也在不断增多&#xff0c;用户数量也在不断增加&#xff0c;苹果应用代签是指通过第三方公司为开发者的应用进行…

谋道翻译逆向

文章目录 前文crypto模块分析完整代码结尾 前文 本文章中所有内容仅供学习交流&#xff0c;严禁用于商业用途和非法用途&#xff0c;否则由此产生的一切后果均与作者无关&#xff0c;若有侵权&#xff0c;请联系我立即删除&#xff01; crypto模块 Crypto是加密的简称&#…

nodejs+vue校园跑腿系统elementui

购物车品结算,管理个人中心&#xff0c;订单管理&#xff0c;接单处理&#xff0c;商品维护&#xff0c;用户管理&#xff0c;系统管理等功育食5&#xff09;要求系统运行可靠、性能稳定、界面友好、使用方便。 第三章 系统分析 10 3.1需求分析 10 3.2可行性分析 10 3.2.1技术…

Lagrange插值法实验:求拉格朗日插值多项式和对应x的近似值matlab实现(内附代码)

一、实验要求 已知函数表&#xff1a; 求出Lagrange 插值多项式&#xff0c;并计算x1.2处的y的近似值。 二、MATLAB代码 求解多项式&#xff1a; X input(请输入横坐标向量X:\nX); % 获取用户输入的横坐标向量 Y input(请输入纵坐标向量Y:\nY); % 获取用户输入的纵坐标…

MySQL-MVCC(Multi-Version Concurrency Control)

MySQL-MVCC&#xff08;Multi-Version Concurrency Control&#xff09; MVCC&#xff08;多版本并发控制&#xff09;&#xff1a;为了解决数据库并发读写和数据一致性的问题&#xff0c;是一种思想&#xff0c;可以有多种实现方式。 核心思想&#xff1a;写入时创建行的新版…

基于 Netty + RXTX 的无协议 COM 通讯案例实现

参考 Netty集成串口RXTX编程&#xff0c;为什么过时了&#xff1f; Java版本 java version "1.8.0_231" Java(TM) SE Runtime Environment (build 1.8.0_231-b11) Java HotSpot(TM) 64-Bit Server VM (build 25.231-b11, mixed mode) RXTX版本 # 官网 http://rx…

第 4 章 串(图书关键字索引表实现)

1. 背景说明 需要从书目文件中获取其关键字及对应的书号索引 bookInfo.txt 005 Computer Data Structures 010 Introduction to Data Structures 023 Fundamentals of Data Structures 034 The Design and Analysis of Computer Algorithms 050 Introduction to Numerical Anal…

STM32复习笔记(六):STM32远程升级BootLoader相关

目录 Preface&#xff1a; &#xff08;一&#xff09;STM32上电启动流程 &#xff08;二&#xff09;BootLoader相关 &#xff08;三&#xff09;Clion配置 Preface&#xff1a; 有关STM32的BootLoader主要还是参考了许多大佬的文章&#xff0c;这里只是简单地列举一下&am…