【数据结构】顺序二叉树的实现—以堆的实现为例、堆的调整、堆的创建、堆的插入和删除、堆排序

文章目录

  • 1.堆的概念及结构
  • 2.堆的实现(以大堆为例)
    • 2.1堆的插入
      • 2.1.1堆的向上调整算法
    • 2.2堆的删除
      • 2.2.1堆的向下调整算法
    • 2.3堆的创建
    • 2.4有关建堆的时间复杂度
  • 3.堆排序
  • 4.C语言堆实现源码

1.堆的概念及结构

  堆就是顺序结构二叉树。

  如果有一个关键码的集合K = { K0,K1 ,K2 ,K3…,Kn-1 },把它的所有元素按完全二叉树的顺序存储方式存储在一个一维数组中,并满足:Ki<=K2i+1 且Ki<= K2i+2 (Ki >=K2i+1 且 Ki>=K2i+2 ) i = 0,1,2…,则称为小堆(或大堆)。将根节点最大的堆叫做最大堆或大根堆,根节点最小的堆叫做最小堆或小根堆。

堆有以下性质:
 (1)堆中某个节点的值总是不大于或不小于其父节点的值;
 (2)堆总是一棵完全二叉树。

在这里插入图片描述

  我们在构建堆时,要想象堆的逻辑结构进行操作,但实际堆在计算机中是以数组的方式储存的。
  堆的逻辑结构是一颗树,树上的每个节点都有一个值,根据节点之间的大小关系,堆被分为小根堆和大根堆两种类型。堆的储存结构一般采用数组来实现,数组中的元素的排列顺序是按照完全二叉树的顺序来存储的,即从上到下,从左到右的顺序。

在这里插入图片描述

  对于一个大根堆而言,储存结构中数组的第一个元素即为堆中的最大值,小堆则相反,也就是说逻辑上靠近根节点的实际上也是储存结构中靠前的元素
  由于堆的储存结构是按照完全二叉树的形式存储的,因此在进行堆的插入和删除操作时,可以方便的通过数组来进行操作,无需关注堆的具体逻辑结构,即可实现堆的调整和维护。

2.堆的实现(以大堆为例)

2.1堆的插入

  堆的插入操作需要保证插入新数之后仍然满足堆的性质,即每个节点都大于或等于其子节点。插入操作的具体过程如下:

 (1)将新数插入堆的最后一个位置,保持完全二叉树的形状。

 (2)将新数与其父节点比较,如果新数大于其父节点,则交换它们的位置,直到新数不再大于其父节点或者到达堆的根节点。

在这里插入图片描述

2.1.1堆的向上调整算法

  AdjustUp函数实现了从下向上调整堆的结构,使得满足堆的性质,具体实现过程如下:

(1)从子节点child开始,计算其父节点parent的位置,parent的位置为(child - 1) / 2

(2)如果子节点比父节点的值大,则交换两个节点的值,否则结束调整;

(3)将child和parent向上移动,继续比较和交换它们的值,直到child小于它的父节点或者已达到堆的根部(即parent为0)。

  这个过程也被称为上滤(Percolate Up)操作,用于添加一个新的元素时,将新元素添加到堆的底部,然后执行上滤操作,将新元素放到合适的位置,以满足堆的性质。

void AdjustUp(HPDataType* a, int child)
{
	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;
		}
	}
}

2.2堆的删除

  堆的删除操作需要保证删除后仍然满足堆的性质,即每个节点都大于或等于其子节点。删除操作的具体过程如下:

(1)将堆顶元素与堆中最后一个元素进行交换。

(2)删除堆中最后一个元素。

(3)将新的堆顶元素与其子节点比较,如果新堆顶元素小于其子节点,则将其与子节点中较大的一个交换,直到新的堆顶元素不再小于其子节点或到达堆的底部。
在这里插入图片描述

2.2.1堆的向下调整算法

  这段代码实现了从上向下调整堆的结构,使得满足堆的性质,具体实现过程如下:

(1)从父节点parent开始,计算其左子节点child的位置为parent*2+1

(2)如果父节点的值比其子节点中的较小值还小,则将两个节点的值交换;

(3)将parent向下移动到child的位置,计算新的child的索引;

(4)重复上述2、3步,直到parent比其子节点的值都小或者已经到达堆的底部。

  这个过程也被称为下滤(Percolate Down)操作,用于删除堆顶元素后重新调整堆的结构。

void AdjustDown(HPDataType* 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;
		}
	}
}

2.3堆的创建

  现在我们给出一个数组,逻辑上看做一颗完全二叉树。我们通过从根节点开始的向下调整算法可以把它调整成一个小堆。向下调整算法有一个前提:左右子树必须是一个堆,才能调整。

//这里以小堆为例
int array[] = {27,15,19,18,28,34,65,49,25,37};

在这里插入图片描述

2.4有关建堆的时间复杂度

  因为堆是完全二叉树,而满二叉树也是完全二叉树,此处为了简化使用满二叉树来证明(时间复杂度本来看的就是近似值,多几个节点不影响最终结果):
在这里插入图片描述

  因此:建堆的时间复杂度为O(N)

3.堆排序

  堆排序即利用堆的思想来进行排序,总共分为两个步骤:
(1)建堆(升序:建大堆 降序:建小堆)
(2)利用堆删除思想来进行排序
建堆和堆删除中都用到了向下调整,因此掌握了向下调整,就可以完成堆排序。
在这里插入图片描述
现在只是简单介绍一下,以后我们会对堆排序进行详细的介绍。

4.C语言堆实现源码

Heap.h

#pragma once
#include<stdio.h>
#include<assert.h>
#include<stdlib.h>
#include<stdbool.h>
#include<time.h>

typedef int HPDataType;
typedef struct Heap
{
	HPDataType* a;
	int size;
	int capacity;
}HP;

void HeapPrint(HP* php);
void HeapInit(HP* php);
void HeapDestroy(HP* php);

void HeapPush(HP* php, HPDataType x);
void HeapPop(HP* php);
HPDataType HeapTop(HP* php);
bool HeapEmpty(HP* php);
int HeapSize(HP* php);

void AdjustUp(HPDataType* a, int child);
void AdjustDown(HPDataType* a, int n, int parent);

void Swap(HPDataType* p1, HPDataType* p2);


Heap.c

#include"Heap.h"

void HeapPrint(HP* php)
{
	assert(php);

	if (php->a == NULL)
	{
		printf("该堆为空堆\n");
	}
	else
	{
		printf("该堆中的元素是:");

		for (int i = 0; i < php->size; i++)
		{
			printf("%d ", php->a[i]);
		}

		printf("\n");
	}
}

void HeapInit(HP* php)
{
	assert(php);

	php->a = (HPDataType*)malloc(sizeof(HPDataType) * 4);
	if (php->a == NULL)
	{
		perror("malloc fail");
		return;
	}

	php->size = 0;
	php->capacity = 4;
}

void HeapDestroy(HP* php)
{
	assert(php);

	free(php->a);
	php->capacity = 0;
	php->size = 0;
	php->a = NULL;
}


void Swap(HPDataType* p1, HPDataType* p2)
{
	HPDataType x = *p1;
	*p1 = *p2;
	*p2 = x;
}

void AdjustUp(HPDataType* a, int child)
{
	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;
		}
	}
}

void HeapPush(HP* php, HPDataType x)
{
	assert(php);

	if (php->capacity == php->size)
	{
		HPDataType*tmp = (HPDataType*)realloc(php->a, sizeof(HPDataType) * php->capacity * 2);
		if (tmp == NULL)
		{
			perror("realloc fail");
			return;
		}

		php->a = tmp;
		php->capacity *= 2;
	}

	php->a[php->size] = x;
	php->size++;

	AdjustUp(php->a, php->size - 1);
}

void AdjustDown(HPDataType* 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;
		}
	}
}

void HeapPop(HP* php)
{
	assert(php);
	assert(!HeapEmpty(php));

	Swap(&php->a[0], &php->a[php->size - 1]);
	php->size--;

	AdjustDown(php->a, php->size, 0);
}

HPDataType HeapTop(HP* php)
{
	assert(php);
	return php->a[0];
}

bool HeapEmpty(HP* php)
{
	assert(php);
	return php->size == 0;
}

int HeapSize(HP* php)
{
	assert(php);
	return php->size;
}


Test.c

#define _CRT_SECURE_NO_WARNINGS 1
#include"Heap.h"

void HeapTest1()
{
	HP hp;
	HeapInit(&hp);
	HeapPrint(&hp);

	HeapPush(&hp, 12);
	HeapPush(&hp, 4);
	HeapPrint(&hp);


	HeapPush(&hp, 2);
	HeapPush(&hp, 22);
	HeapPush(&hp, 18);
	HeapPrint(&hp);

	HeapPush(&hp, 6);
	HeapPush(&hp, 10);
	HeapPush(&hp, 54);
	HeapPush(&hp, 43);
	HeapPrint(&hp);
}

int main()
{
	HeapTest1();
	return 0;
}

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

jetcache参考文档

jetcache简介 https://github.com/alibaba/jetcache/blob/master/docs/CN/GettingStarted.md 简介 JetCache是一个基于Java的缓存系统封装&#xff0c;提供统一的API和注解来简化缓存的使用。 JetCache提供了比SpringCache更加强大的注解&#xff0c;可以原生的支持TTL、两级…

shell变量类型含义 长方形面积计算 截取相应字段方法

1.总结变量的类型及含义&#xff1f; 2.实现课堂案例计算长方形面积&#xff1f;&#xff08;6种方式&#xff09; 3.定义变量urlhttps://blog.csdn.net/weixin_45029822/article/details/103568815&#xff08;通过多种方法实现&#xff09; 1&#xff09;截取网站访问的协议 …

文心一言 VS 讯飞星火 VS chatgpt (22)-- 算法导论4.2 2题

二、为Strassen算法编写伪代码。 文心一言&#xff1a; Strassen算法是一种用于矩阵乘法的算法&#xff0c;它的核心思想是通过不断将原始矩阵分割成较小的子矩阵来实现高效的乘法运算。以下是Strassen算法的伪代码&#xff1a; function Strassen(A, B): if A[0][0] 0 or…

Springboot整合WebSocket

目录 1.WebSocket 简介 2.WebSocket 实战 1.WebSocket 简介 WebSocket是一种在单个TCP连接上进行全双工通信的协议。WebSocket使得客户端和服务器之间的数据交换变得更加简单&#xff0c;允许服务端主动向客户端推送数据。在WebSocket API中&#xff0c;浏览器和服务器只需要…

基于html+css的图展示98

准备项目 项目开发工具 Visual Studio Code 1.44.2 版本: 1.44.2 提交: ff915844119ce9485abfe8aa9076ec76b5300ddd 日期: 2020-04-16T16:36:23.138Z Electron: 7.1.11 Chrome: 78.0.3904.130 Node.js: 12.8.1 V8: 7.8.279.23-electron.0 OS: Windows_NT x64 10.0.19044 项目…

C++入门

文章目录 &#x1f600;1. 命名空间&#x1f604;1.1 命名空间定义&#x1f604;1.2 命名空间使用 &#x1f60a;2. 输入和输出&#x1f609;3. 缺省参数&#x1fae0;3.1 缺省参数概念&#x1fae0;3.2 缺省参数分类 &#x1f62c;4. 函数重载&#x1f644;4.1 函数重载概念&a…

TypeScript9-声明文件

本篇文章来讲 TypeScript 的声明文件。 当我们在使用第三方库的时候&#xff0c;很多第三方库不是用 TS 写的&#xff0c;它们是通过原生的 JavaScript 或者是浏览器 / 或者是 node 提供的 run time 对象。如果我们直接使用 TS 肯定就会报编译不通过。 1. 声明语句 假设一个…

浅析变电站无人值守管理的模式与特点

安科瑞虞佳豪 近年来&#xff0c;随着电网的发展&#xff0c;变电站实行无人值班管理模式已成为电网的发展方向。自1998年始&#xff0c;辉县市就开始了变电站综合自动化改造&#xff0c;截止目前全局所属24座变电站&#xff08;其中35kV19座、110kV5座&#xff09;已全部实现…

API自动化测试【postman生成报告】

PostMan生成测试报告有两种&#xff1a; 1、控制台的模式 2、HTML的测试报告 使用到一个工具newman Node.js是前端的一个组件&#xff0c;主要可以使用它来开发异步的程序。 一、控制台的模式 1、安装node.js 双击node.js进行安装&#xff0c;安装成功后在控制台输入node …

Java集合基础

4 集合基础 集合提供一种存储空间可变的存储模型,存储的数据容量可以改变ArrayLis<>: 可调整大小的数组实现<>:是一种特殊的数据类型,泛型可储存重复元素怎么使用呢 在出现E的地方我们使用引用数据类型替换即可举例:ArrayList<String>、ArrayList<Stu…

财务共享时代企业数智化应用能帮我们做些什么?

随着企业规模的不断扩大和业务范围的逐步扩展&#xff0c;财务工作的难度和复杂度也在不断提高&#xff0c;传统的手工录入和处理方式呈现出流程长、效率低、易出错等问题。为了提升财务工作的效率和准确性&#xff0c;越来越多的企业开始利用数智化应用打造企业内部的财务数智…

绝对不能错过的7个零基础免费的ChatGPT镜像网站

还在为打不开openai官网烦心&#xff1f;本文帮你实现ChatGPTMidJourney自由(&#xffe3;∇&#xffe3;)/ &#x1f4d2;收集了一些截至目前(2023年5月25日午12:00)可以免费访问&#xff0c;并且零基础也能正常使用的镜像网站&#xff0c;后续将持续维护更新(&#xff61;&a…

平安银行广州分行立足地域文化,增强差异化权益服务软实力

立足地域文化&#xff0c;拓展差异化权益服务 瓦屋纸窗之下&#xff0c;一盏清茶&#xff0c;三五好友&#xff0c;怡然自若。中国人对茶的喜爱由来已久&#xff0c;茶文化已成为中华传统文化中一张亮丽的名片&#xff0c;而广东茶文化则是中国四大茶文化系列之一。平安银行广州…

抖音seo优化源代码搭建+抖音小程序私有化开源部署

抖音seo优化源码&#xff0c;抖音seo矩阵系统搭建&#xff0c;抖音账号矩阵系统开发&#xff0c;企业在做账号矩阵过程中&#xff0c;最头疼的莫过于私域线索转化&#xff0c;作为开发者都知道&#xff0c;目前市面上我们了解的矩阵系统除了挂载POI信息外&#xff0c;无法挂载留…

unity四叉树和视锥体剔除

这个最好还是看代码&#xff0c;项目有注释放在这里&#xff1a; GetbadEarlyup/Quadtree-cone-scene: 这是一个unity四叉树场景视锥体剔除的Demo (github.com)https://github.com/GetbadEarlyup/Quadtree-cone-scene国内地址&#xff1a; Quadtree-cone-scene: unity四叉树和…

VESD静电监控系统:提高静电防护效果与管理效率

随着科学技术不断发展&#xff0c;现代的工业对静电防护的要求越来越高。因为静电的存在可能会对产品质量、工作环境、甚至是人身产生威胁。静电监控系统是一项高效的管理工具&#xff0c;能够有效地控制和监测静电产生的情况&#xff0c;提高静电防护效果和管理效率。 VESD静电…

U盘超级加密3000试用版与正式版的区别有哪些?

U盘超级加密3000是一款专业的U盘加密软件&#xff0c;它可以为U盘、移动硬盘、内存卡等移动存储设备加密。软件拥有正式版和试用版&#xff0c;那么这两个版本有什么区别呢&#xff1f;下面我们就一起来了解一下。 U盘超级加密3000试用版和正式版的区别 打开软件时的区别 试用…

基于SSM的酒店客房管理系统

✌全网粉丝20W,csdn特邀作者、博客专家、CSDN新星计划导师、java领域优质创作者,博客之星、掘金/华为云/阿里云/InfoQ等平台优质作者、专注于Java技术领域和毕业项目实战✌ &#x1f345;文末获取项目下载方式&#x1f345; 一、项目背景介绍&#xff1a; 酒店管理系统是一款高…

VMware重新安装VMwareTool字体为灰色情况+ubuntu时间设置

文章目录 前言&#xff1a;1. 重新安装VMwareTool字体为灰色2. VMware下ubuntu的时间设置 前言&#xff1a; 之前退出VMware关闭的时候没有等待虚拟机的状态保存&#xff0c;强制关机了。这就导致后面使用的时候&#xff0c;共享目录无法显示情况。对于上面的情况我的博客里面…

ASP-IIS中间件文件解析与写权限

ASP-IIS中间件文件解析与写权限 IIS文件解析 IIS 6 解析漏洞 1、该版本默认会将*.asp;.jpg 此种格式的文件名&#xff0c;当成Asp解析 2、该版本默认会将*.asp/目录下的所有文件当成Asp解析。 如&#xff1a;logo.asp;.jpg xx.asp/logo.jpgIIS 7.x 解析漏洞 在一个文件路…