二叉树的顺序结构(堆的实现)

前言

普通的二叉树是不适合用数组来存储的,因为可能会存在大量的空间浪费。而完全二叉树更适合使用顺序结 构存储。
现实中我们通常把堆 ( 一种二叉树 ) 使用顺序结构的数组来存储,需要注意的是这里的堆和操作系统 虚拟进程地址空间中的堆是两回事,一个是数据结构,一个是操作系统中管理内存的一块区域分段。

1.堆的概念及结构

如果有一个关键码的集合 K = { k0, k1,k2,…,k(n-1)},把它的所有元素按完全二叉树的顺序存储方式存储 在一个一维数组中,并满足:Ki <=K(2*i+1)且Ki<=K(2*i+2)(Ki >=K(2*i+1)且Ki>=K(2*i+2)  i =0 1 , 2…,则称为小堆 (或大堆) 。将根结点最大的堆叫做最大堆或大根堆,根结点最小的堆叫做最小堆或小根堆。(这里的数字都是对应的下标
堆的性质:
堆中某个结点的值总是不大于或不小于其父结点的值;
堆总是一棵完全二叉树。

2.堆的创建和功能实现

2.1堆的基本结构的创建和相关函数声明。

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

typedef int  Datatype;
typedef  struct Heap {
	Datatype* a;
	int size;
	int capacity;
}HP;
// 堆的初始化
void HeapInit(HP* hp);
// 堆的销毁
void HeapDestory(HP* hp);
// 堆的插入
void HeapPush(HP* hp, Datatype x);
// 堆的删除
void HeapPop(HP* hp);
// 取堆顶的数据
Datatype HeapTop(HP* hp);
// 堆的数据个数
bool HeapSize(HP* hp);
// 堆的判空
int HeapEmpty(HP* hp);
//向上调整
void Adjustup(Datatype* a, int child);
//向下调整
void Adjustdown(Datatype* a, int n, int parent);
//数据交换
void Swap(Datatype* p1, Datatype* p2);

2.2 各函数的实现与讲解

2.1堆的初始化和销毁

堆的初始化和销毁与以前的动态数组实现顺序表和栈的初始化和销毁基本是一样的,在这里小编就不多解释了。

// 堆的初始化
void HeapInit(HP* hp) {
	assert(hp);
	hp->a = NULL;
	hp->size = hp->capacity = 0;
}
// 堆的销毁
void HeapDestory(HP* hp) {
	assert(hp);
	free(hp->a);
	hp->a = NULL;
	hp->size = hp->capacity = 0;
}
2.2堆数据的插入
补充向上调整法
随便给出一个数组,这个数组逻辑上可以看做一颗完全二叉树,但是还不是一个堆,现在我们通过算法,把它构建成一个堆。根结点左右子树不是堆,我们怎么调整呢?
向上调整法
通过比较新插入元素与其父节点的值来判断是否需要进行交换。如果新插入元素的值大于父节点的值,就将它们进行交换,并更新索引值。这样,逐步向上调整,直到新插入元素找到了合适的位置,保证了堆的性质。
//向上调整
void Adjustup(Datatype* 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* hp, Datatype x) {
	assert(hp);
	if (hp->size == hp->capacity) {
		int newcapacity = hp->capacity == 0 ? 4 : hp->capacity * 2;
		Datatype* temp = (Datatype*)realloc(hp->a, sizeof(Datatype) * newcapacity);
		if (temp == NULL) {
			perror("realloc fail");
			return;
		}
		hp->a = temp;
		hp->capacity = newcapacity;
	}
	hp->a[hp->size] = x;
	hp->size++;
	Adjustup(hp->a, hp->size-1);
}

例如数组a[]={1, 5, 3, 8, 7, 6},依次插入并建立大堆后的顺序是:

  1. 插入 1,堆变为 [1]
  2. 插入 5,堆变为 [5, 1]
  3. 插入 3,堆变为 [5, 1, 3]
  4. 插入 8,堆变为 [8, 5, 3, 1]
  5. 插入 7,堆变为 [8, 7, 3, 1, 5]
  6. 插入 6,堆变为 [8, 7, 6, 1, 5, 3]

所以,建立大堆后的顺序是 [8, 7, 6, 1, 5, 3]。

2.3堆的删除
补充向下调整法

在这里惯性思维是直接删除头顶数据,然后重新建堆,通过向上调整法,但是我们需要从最后一个元素依次遍历向上调整。

这里我们采用向下调整法。

删除堆是删除堆顶的数据,将堆顶的数据根最后一个数据一换,然后删除数组最后一个数据,再进行向下调整算法。
本张图是小堆的删除。大堆的删除方式是一样的。
因为堆数据插入是建立大堆的,所以这里的代码是大堆的向下调整。
//向下调整
void Adjustdown(Datatype* a, int n, int parent) {
	//假设法,假设左孩子大
	int child = parent * 2 + 1;
	
	while (child < n ) {
		if (child + 1 < n && a[child + 1] > a[child])//a[child+1]<a[child]
			child = child + 1;
		if (a[child] > a[parent]) {  //a[child]<a[parent]
			Swap(&a[child], &a[parent]);
		   parent = child;
		    child = parent * 2 + 1;
	}
		else break;
		
	}
}

堆的删除

// 堆的删除
void HeapPop(HP* hp) {
	assert(hp);
	assert(hp->size > 0);
	Swap(&hp->a[0], &hp->a[hp->size - 1]);
	hp->size--;
	Adjustdown(hp->a, hp->size, 0);
}

最后我们会发现删除的数据是从大到小排列的,这里就可以牵扯到堆排序的应用,小编在下节会讲解的。

2.4其他函数实现(交换,判空,堆顶数据,数据个数)
//数据交换
void Swap(Datatype* p1, Datatype* p2) {
	Datatype temp = *p1;
	*p1 = *p2;
	*p2 = temp;
}
// 取堆顶的数据
Datatype HeapTop(HP* hp) {
	assert(hp);
	assert(hp->size > 0);
	return hp->a[0];
}
// 堆的数据个数
int HeapSize(HP* hp) {
	assert(hp);
	return hp->size;
}
// 堆的判空
bool HeapEmpty(HP* hp) {
	assert(hp);
	return hp->size == 0;

}

3.代码测试

#include "Heap.h"
void TestHeap1()
{
	int a[] = { 4,2,8,1,5,6,9,3,2,23,55,232,66,222,33,7,66,3333,999 };
	//int a[] = { 1,5,3,8,7,6 };
	HP hp;
	HeapInit(&hp);
	for (int i = 0; i < sizeof(a) / sizeof(int); i++)
	{
		HeapPush(&hp, a[i]);
	}
	printf("堆的大小为%d\n", HeapSize(&hp));

	int i = 0;
	while (!HeapEmpty(&hp))
	{
		printf("%d ", HeapTop(&hp));
		//a[i++] = HPTop(&hp);
		HeapPop(&hp);
	}
	printf("\n");
}
/*
	// 找出最大的前k个
	int k = 0;
	scanf("%d", &k);
	while (k--)
	{
		printf("%d ", HeapTop(&hp));
		HeapPop(&hp);
	}
	printf("\n");

	HeapDestory(&hp);
}*/
int main(){
TestHeap1();
return 0;
}

4.堆的选择题(方便大家理解)

1. 下列关键字序列为堆的是:(A)
A 100 , 60 , 70 , 50 , 32 , 65             B 60 , 70 , 65 , 50 , 32 , 100             C 65 , 100 , 70 , 32 , 50 , 60
D 70 , 65 , 100 , 32 , 50 , 60             E 32 , 50 , 100 , 70 , 65 , 60             F 50 , 100 , 70 , 65 , 60 , 32
2. 已知小根堆为 8 , 15 , 10 , 21 , 34 , 16 , 12 ,删除关键字 8 之后需重建堆,在此过程中,关键字之间的比较次数是(C)。
A 1                      B 2                        C 3                        D 4
3. 最小堆 [ 0 , 3 , 2 , 5 , 7 , 4 , 6 , 8 ], 在删除堆顶元素 0 之后,其结果是(C)
A [ 3 2 5 7 4 6 8 ]                  B [ 2 3 5 7 4 6 8 ]
C [ 2 3 4 5 7 8 6 ]                  D [ 2 3 4 5 6 7 8 ]

本节内容到此结束,下次小编将讲解堆排序的知识,欢迎大家捧场!!!

期待各位友友的三连和评论!!!

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

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

相关文章

less学习笔记

一、什么是less&#xff1f; Less是CSS预处理语言&#xff0c;可以使用变量、嵌套、运算等&#xff0c;便于维护项目CSS样式代码。 二、less安装 使用npm包管理工具&#xff0c;全局安装less包 npm install -g lessless安装好的同时&#xff0c;lessc也安装好了 通过 lessc -…

[office] Excel数据透视表有什么用途?Excel数据透视表怎么做? #学习方法#职场发展

Excel数据透视表有什么用途&#xff1f;Excel数据透视表怎么做&#xff1f; Excel数据透视表是一种数据汇总手段&#xff0c;如果表格内的数据太多&#xff0c;单靠肉眼是很难准确分辨数据的&#xff0c;而使用数据透视表&#xff0c;就可以很方便的筛选各种数据。如果你不知道…

企业获客有哪些好的广告推广拓客渠道?

在这个数字化营销的时代&#xff0c;企业要想在激烈的市场竞争中脱颖而出&#xff0c;选择正确的广告宣传渠道至关重要。随着互联网技术的飞速发展&#xff0c;各类媒体平台如雨后春笋般涌现&#xff0c;为企业提供了广阔的宣传空间。云衔科技通过多元化的媒体渠道&#xff0c;…

C语言.数据结构.单链表

数据结构.单链表 1.链表的概念及结构2.单链表的实现2.1链表的打印2.2节点的申请2.3单链表的尾插2.4单链表的头插2.5单链表的尾删2.6单链表的头删2.7单链表节点的查找2.8在指定位置之前插入数据2.9在指定位置之后插入数据2.10删除pos节点2.11删除pos之后的节点2.12单链表的销毁2…

伽马校正技术在AI绘画中的作用

随着人工智能技术的飞速发展&#xff0c;AI绘画已经成为了艺术创作领域的一股新兴力量。在这个数字化时代&#xff0c;计算机图形学和机器学习的结合为我们带来了前所未有的创作工具。然而&#xff0c;为了实现更加真实和自然的色彩表现&#xff0c;伽马校正技术在其中扮演着至…

NSSCTF-Web题目5

目录 [SWPUCTF 2021 新生赛]error 1、题目 2、知识点 3、思路 [LitCTF 2023]作业管理系统 1、题目 2、知识点 3、思路 [HUBUCTF 2022 新生赛]checkin 1、题目 2、知识点 3、思路 [SWPUCTF 2021 新生赛]error 1、题目 2、知识点 数据库注入、报错注入 3、思路 首先…

极光公布2024年第一季度财报

2024年6月6日&#xff0c;中国深圳——中国领先的客户互动和营销科技服务商极光&#xff08;Aurora Mobile&#xff0c;纳斯达克股票代码&#xff1a;JG&#xff09;&#xff08;以下称“极光”或“公司”&#xff09;公布截至2024年3月31日第一季度未经审计的财报。 2024年第…

UDSonCAN刷写之StayInBOOT和FlashDiver

目录 0 前言 1 StayInBOOT 2 Flash Driver 0 前言 最近在做刷写相关的工作&#xff0c;顺便搞懂了StayInBOOT和FlashDiver&#xff0c;写出来作为分享&#xff0c;如果有哪里不对也请多多指正。 1 StayInBOOT StayInBOOT在整个流程中的位置如下图所示&#xff0c;从图中可…

VCAST创建单元测试工程

1. 设置工作路径 选择工作目录,后面创建的 UT工程 将会生成到这个目录。 2. 新建工程 然后填写 工程名称,选择 编译器,以及设置 基础路径。注意 Base Directory 必须要为代码工程的根目录,否则后面配置环境会失败。 这样工程就创建好了。 把基础路径设置为相对路径。 …

CasaOS玩客云如何部署小雅AList并结合内网穿透远程访问海量资源

文章目录 前言1. 本地部署AList2. AList挂载网盘3. 部署小雅alist3.1 Token获取3.2 部署小雅3.3 挂载小雅alist到AList中 4. Cpolar内网穿透安装5. 创建公网地址6. 配置固定公网地址 前言 本文主要介绍如何在安装了CasaOS的玩客云主机中部署小雅AList&#xff0c;并在AList中挂…

【Python报错】已解决ModuleNotFoundError: No module named ‘timm’

成功解决“ModuleNotFoundError: No module named ‘timm’”错误的全面指南 一、引言 在Python编程中&#xff0c;经常会遇到各种导入模块的错误&#xff0c;其中“ModuleNotFoundError: No module named ‘timm’”就是一个典型的例子。这个错误意味着你的Python环境中没有安…

[数据集][目标检测]攀墙攀越墙壁数据集VOC格式-701张

数据集格式&#xff1a;Pascal VOC格式(不包含分割路径的txt文件和yolo格式的txt文件&#xff0c;仅仅包含jpg图片和对应的xml) 图片数量(jpg文件个数)&#xff1a;701 标注数量(xml文件个数)&#xff1a;701 标注类别数&#xff1a;1 标注类别名称:["fq"] 每个类别标…

2024华为数通HCIP-datacom最新题库(变题更新③)

请注意&#xff0c;华为HCIP-Datacom考试831已变题 请注意&#xff0c;华为HCIP-Datacom考试831已变题 请注意&#xff0c;华为HCIP-Datacom考试831已变题 近期打算考HCIP的朋友注意了&#xff0c;如果你准备去考试&#xff0c;还是用的之前的题库&#xff0c;切记暂缓。 1、…

pdf处理命令合集

安装weasyprint用于生成pdf 单个文件合成多个pdf linux - Merge / convert multiple PDF files into one PDF - Stack Overflow

优化电梯调度1:实现高效优先级队列算法

概述&#xff1a; 写作原由&#xff1a; 今天早上上班时候&#xff0c;等电梯等了快十分钟&#xff0c;故此猜想这个电梯运行的算法到底是啥&#xff0c;当年面试工作时候&#xff0c;给出笔试题也是有这个电梯算法的&#xff0c;故此需要坐下来慢慢想想。 随着高层建筑的增…

matrix-breakout-2-morpheus vulnhub靶场

端口扫描 80 81 需要用户名密码登录 目录扫描 robots.txt 妹用 找不到利用点&#xff0c;换个扫描器再扫 发现新的文件 graffiti.txt graffiti.php 输入的数据Post后会回显到页面上 抓包看看&#xff0c;居然直接传文件路径 发现我们post的数据被写入了graffiti.…

一种简单的借助微信扫码登录

公司内部登录一些网页、小工具&#xff0c;使用微信登录&#xff0c;可以保证安全又减少了输密码的麻烦。 需要使用两个码 左边的码是固定的&#xff0c;右边的是动态生成的 左边码&#xff1a;小程序后台生成的带参数的小程序码&#xff0c;带了一个自定义的参数fromscan1 流…

芒果YOLOv8改进169:即插即用 | 秩引导的块设计核心CIB结构,设计一种秩引导的块设计方案,旨在通过紧凑型架构设计减少被显示为冗余的阶段的复杂性

💡🚀🚀🚀本博客 秩引导的块设计,设计了一种秩引导的块设计方案,旨在通过紧凑型架构设计减少被显示为冗余的阶段的复杂性 :内含源代码改进 适用于 YOLOv8 按步骤操作运行改进后的代码即可 文章目录 即插即用|秩引导的块设计|最新改进 YOLOv8 代码改进论文理论YOLO…

探索ChatGPT-4在解决化学知识问题上的研究与应用

1. 概述 近年来&#xff0c;人工智能的发展主要集中在 GPT-4 等大型语言模型上。2023 年 3 月发布的这一先进模型展示了利用广泛知识应对从化学研究到日常问题解决等复杂挑战的能力。也开始进行研究&#xff0c;对化学的各个领域&#xff0c;从化学键到有机化学和物理化学&…

单轴测径仪和双轴测径仪的区别

关键字&#xff1a;单轴测径仪、双轴测径仪、单轴双轴的结构差异、功能区别、应用场景、测量精度、测头、外径尺寸检测、 单轴测径仪和双轴测径仪在多个方面存在显著的区别&#xff0c;这些区别主要体现在其结构、功能、应用场景以及测量精度上。 首先&#xff0c;从结构上来…