二叉树顺序结构与堆的概念及性质(c语言实现堆)

上次介绍了树,二叉树的基本概念结构及性质:二叉树数据结构:深入了解二叉树的概念、特性与结构

今天带来的是:二叉树顺序结构与堆的概念及性质,还会用c语言来实现堆


文章目录

  • 1. 二叉树的顺序结构
  • 2.堆的概念和结构
  • 3.堆的实现(小堆)
    • 3.1项目文件规划
    • 3.2结构体和各功能一览(Heap.h)
    • 3.3重要函数详解(Heap.c)
      • 3.3.1堆向上调整算法
      • 3.3.2堆向下调整算法
    • 3.4各功能实现(Heap.c)
      • 初始化和销毁
      • 插入
      • 删除堆顶
      • 返回根(堆顶)的存储的数据
      • 节点数量
      • 是否为空
    • 3.5建堆时间复杂度


1. 二叉树的顺序结构

普通的二叉树是不适合用数组来存储的,因为可能会存在大量的空间浪费。完全二叉树就比较适合使用顺序结构存储(数组)。现实中我们通常把(一种二叉树)使用顺序结构的数组来存储

注意:此堆非“彼堆”——操作系统虚拟进程地址空间中的堆。二者一个是一个是数据结构,一个是操作系统中管理内存的一块区域


2.堆的概念和结构

堆需要满足两点

  1. 堆是一个完全二叉树,即除了最底层,其他层都是完全填满,最底层从左到右填充
  2. 堆中的每个节点的值都必须大于等于(最大堆)或小于等于(最小堆)其子节点的值

根据节点值的大小关系,堆可以分为最大堆和最小堆。在最大堆中,根节点的值最大,每个节点的值都大于等于其子节点的值。在最小堆中,根节点的值最小,每个节点的值都小于等于其子节点的值

请添加图片描述

请添加图片描述


3.堆的实现(小堆)

3.1项目文件规划

请添加图片描述

  • 头文件Heap.h:用来基础准备(常量定义,typedef),链表表的基本框架,函数的声明
  • 源文件Heap.c:用来各种功能函数的具体实现
  • 源文件test.c:用来测试功能是否有问题,进行基本功能的使用

3.2结构体和各功能一览(Heap.h)

typedef int HPDataType;

typedef struct Heap//用顺序表来实现,跟顺序表的结构一样
{
	HPDataType* a;
	int size;//数量
	int capacity;//容量
}HP;

void HeapInit(HP* php);//初始化
void HeapDestroy(HP* php);//销毁

void HeapPush(HP* php, HPDataType x);//插入
// 规定删除堆顶(根节点)
void HeapPop(HP* php);//删除

HPDataType HeapTop(HP* php);//返回根(堆顶)的存储的数据

int HeapSize(HP* php);//堆的数据个数

bool HeapEmpty(HP* php);//是否为空

3.3重要函数详解(Heap.c)

3.3.1堆向上调整算法

i位置节点的双亲序号:(i-1)/2

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

void AdjustUp(HPDataType* a, int child)//传入数组和下标索引
{
	int father = (child - 1) / 2;//利用公式来算出父亲节点下标
	while (child > 0)
	{
		if (a[child] < a[father])
		{
			Swap(&a[child], &a[father]);
			//更新下标
			child = father;
			father = (father - 1) / 2;
		}
		else
		{
			break;//一旦符合小堆了,就直接退出
		}
	}
}

Swap 函数用于交换两个指针指向的值,而 AdjustUp 函数用于通过比较子节点与父节点并在有必要时交换它们来调整堆的结构,然后向上移动树,直到满足堆的性质

3.3.2堆向下调整算法

i位置的左孩子是 2 ∗ i + 1 2*i+1 2i+1,右孩子 2 ∗ i + 2 2*i+2 2i+2

void AdjustDown(HPDataType* a, int n, int father)
{
	int child = father * 2 + 1;//假设左孩子小  找出两者较小的来跟父节点比(大堆就找二者中较大的了)
	while (child < n)
	{
		if (child + 1 < n && a[child] > a[child + 1])
		{
			child++;
		}
		if (a[child] < a[father])
		{
			Swap(&a[child], &a[father]);
			father = child;
			child = father * 2 + 1;
		}
		else
		{
			break;
		}
	}
}
  1. 给定一个数组 a,表示堆的结构,以及数组的大小 n 和要进行调整的父节点的索引 father
  2. 计算父节点的左孩子的索引为 father * 2 + 1
  3. 进入一个 while 循环,只要左孩子的索引小于 n (不会出数组)就会继续
  4. 在循环内部,首先检查右孩子是否存在且右孩子的值是否大于左孩子的值,如果是,则更新 child 为右孩子的索引。这是为了找出左右孩子中值较大的那个
  5. 比较左孩子的值和父节点的值,如果左孩子的值小于父节点的值,则调用 Swap 函数交换这两个索引处的值,并更新 fatherchild 的值,然后重新计算 child 的索引。这一步的目的是将较大的子节点值向上移动,以满足堆的性质
  6. 如果左孩子的值不小于父节点的值,则跳出循环,因为堆的性质已经满足

3.4各功能实现(Heap.c)

初始化和销毁

void HeapInit(HP* php)
{
	assert(php);
	php->a = NULL;
	php->size = php->capacity = 0;
}

void HeapDestroy(HP* php)
{
	assert(php);
	free(php->a);
	php->a = NULL;
	php->size = php->capacity = 0;
}

插入

void HeapPush(HP* php, HPDataType x)
{
	assert(php);
	if (php->size == php->capacity)//检查有没有满
	{
		int newCapacity = php->capacity == 0 ? 4 : php->capacity * 2;
		HPDataType* tmp = (HPDataType*)realloc(php->a, newCapacity * sizeof(HPDataType));
		if (tmp == NULL)
		{
			perror("realloc fail");
			return -1;
		}
		php->a = tmp;
		php->capacity = newCapacity;
	}
	//开始插入
	php->a[php->size] = x;
	php->size++;
	//要确保是小堆
	AdjustUp(php->a, php->size - 1);
}

删除堆顶

void HeapPop(HP* php)//最外面那个和堆顶交换后,删去最外面的,再把新堆顶向下调整成小堆
{
	assert(php);
	assert(php->size > 0);//保证有东西可以删
	Swap(php->a[0], php->a[php->size - 1]);

	php->size--;

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

返回根(堆顶)的存储的数据

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

节点数量

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

是否为空

bool HeapEmpty(HP* php)
{
	assert(php);

	return php->size == 0;
}

3.5建堆时间复杂度

请添加图片描述

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


这次就到这里啦,下一次就利用这次的对来解决几个问题。感谢大家的支持!!!

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

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

相关文章

Kafka:本地设置

这是设置 Kafka 将数据从 Elasticsearch 发布到 Kafka 主题的三部分系列的第一部分;该主题将被 Neo4j 使用。第一部分帮助您在本地设置 Kafka。第二部分将讨论如何设置Elasticsearch将数据发布到Kafka主题。最后 将详细介绍如何使用连接器订阅主题并使用数据。 Kafka Kafka 是…

SpringBoot项目部署及多环境

1、多环境 2、项目部署上线 原始前端 / 后端项目宝塔Linux容器容器平台 3、前后端联调 4、项目扩展和规划 多环境 程序员鱼皮-参考文章 本地开发&#xff1a;localhost&#xff08;127.0.0.1&#xff09; 多环境&#xff1a;指同一套项目代码在把不同的阶段需要根据实际…

守护青山绿水 千巡翼Q20无人机变身护林员

守护青山绿水 千巡翼Q20无人机变身护林员 无人机目前在林业上的应用主要在森林资源调查、森林资源监测、森林火灾监测、森林病虫害监测防治、野生动物监测等方面。传统手段在森林资源调查中需要耗费大量人力物力&#xff0c;利用无人机技术可快速获得所需区域高精度信息&#…

Java核心知识点1-java和c++区别、隐式和显示类型转换

java和c区别 java通过虚拟机实现跨平台特性&#xff0c;但c依赖于特定的平台。java没有指针&#xff0c;它的引用可以理解为安全指针&#xff0c;而c和c一样具有指针。java支持自动垃圾回收&#xff0c;而c需要手动回收。java不支持多重继承&#xff0c;只能通过实现多个接口来…

WPF 消息日志打印帮助类:HandyControl+NLog+彩色控制台打印+全局异常捕捉

文章目录 前言相关文章Nlog配置HandyControl配置简单使用显示效果文本内容 全局异常捕捉异常代码运行结果 前言 我将简单的HandyControl的消息打印系统和Nlog搭配使用&#xff0c;简化我们的代码书写 相关文章 .NET 控制台NLog 使用 WPF-UI HandyControl 控件简单实战 C#更改…

【嵌入式开发 Linux 常用命令系列 7.3 -- linux 命令行数值计算】

文章目录 linux 命令行数值计算使用 awk使用 bc 命令使用 Bash 的内置算术扩展使用 expr脚本命令实现 linux 命令行数值计算 在 Linux 命令行中&#xff0c;您可以使用多种方法来执行基本的数学运算。以下是一些示例&#xff1a; 使用 awk awk 是一个强大的文本处理工具&…

Linux第一个小程序-进度条(c语言版)

目录 行缓冲区概念&#xff1a; 行缓冲区代码演示&#xff1a; ​编辑进度条代码 1&#xff1a;memset函数&#xff1a; 2&#xff1a;const char* lable"|/-\\"; 3&#xff1a;usleep C语言 usleep 函数的功能和用法&#xff1a; 4&#xff1a;进度条代码的实…

C语言经典算法【每日一练】20

题目&#xff1a;有一个已经排好序的数组。现输入一个数&#xff0c;要求按原来的规律将它插入数组中。 1、先排序 2、插入 #include <stdio.h>// 主函数 void main() {int i,j,p,q,s,n,a[11]{127,3,6,28,54,68,87,105,162,18};//排序&#xff08;选择排序&#xff09…

12.21自动售货机,单物品,多物品

自动售货机 if朴素方法 一种思路是用寄存器cnt记录已有的最小单位货币量&#xff0c;这里就是0.5 当d1时&#xff0c;cnt1;d2时&#xff0c;cnt2;d3时&#xff0c;cnt4; timescale 1ns/1ns module seller1(input wire clk ,input wire rst ,input wire d1 ,input wire d2 …

Python:日期和时间类型学习

背景 在非开发环境经常需要做一下日期计算&#xff0c;就准备使用Python&#xff0c;顺便记下来学习的痕迹。 代码 1 1 # coding utf-82 2 3 3 from datetime import *4 4 5 5 ########################## 日期 ##########################6 6 date_now date.today()…

【网络安全】全网最全的渗透测试介绍(超详细)

渗透测试介绍 渗透测试就是模拟攻击者入侵系统&#xff0c;对系统进行一步步地渗透&#xff0c;发现系统地脆弱环节和隐藏风险。最后形成测试报告提供给系统所有者。系统所有者可根据该测试报告对系统进行加固&#xff0c;提升系统的安全性&#xff0c;防止真正的攻击者入侵。…

【Leetcode 39】组合总和 —— 回溯法

39. 组合总和 给你一个无重复元素的整数数组candidates和一个目标整数target &#xff0c;找出candidates中可以使数字和为目标数target的 所有不同组合&#xff0c;并以列表形式返回。你可以按**任意顺序 **返回这些组合。 candidates中的同一个数字可以 无限制重复被选取 。…

C++线性表

线性表的定义及其运算 线性表是一种最简单、最基本也是最常用的线性结构。在线性结构中&#xff0c;数据元素之间存在一个对一个的线性关系&#xff0c;数据元素“一个接一个地排列”。在一个线性表中&#xff0c;数据元素的类型是相同的&#xff0c;或者说&#xff0c;线性表…

【教程】Typecho Joe主题开启并修复壁纸相册不显示问题

转载请注明出处&#xff1a;小锋学长生活大爆炸[xfxuezhang.cn] 背景说明 Joe主题本身支持“壁纸”功能&#xff0c;其实就是相册。当时还在网上找了好久相册部署的开源项目&#xff0c;太傻了。 但是网上教程很少&#xff0c;一没说如何开启壁纸功能&#xff0c;二没说开启后为…

Python跨年烟花秀

写在前面 今年跨年怎么过呢~博主用python的pygame实现了一场炫酷的烟花秀&#xff0c;一起来看看吧&#xff01; 环境需求 python3.11.4及以上PyCharm Community Edition 2023.2.5pyinstaller6.2.0&#xff08;可选&#xff0c;这个库用于打包&#xff0c;使程序没有python环境…

使用yolov5的2.0分支训练自己的模型并在x3派运行

目录 准备代码、权重、数据集配置环境准备数据标注数据 训练模型转换模型验证模型准备校准数据转换为板上模型模型精度分析 上板 之前训练自己模型的时候使用的是博主 bubbling的1.0分支的代码&#xff0c;博主的 博客比较详细&#xff0c;使用的是VOC2007数据集&#xff0c;…

迷宫问题的对比实验研究(代码注释详细、迷宫及路径可视化)

题目描述 对不同的迷宫进行算法问题&#xff0c;广度优先、深度优先、以及人工智能上介绍的一些算法&#xff1a;例如A*算法&#xff0c;蚁群算法等。 基本要求&#xff1a; &#xff08;1&#xff09;从文件读入9*9的迷宫&#xff0c;设置入口和出口&#xff0c;分别采用以上方…

基于huffman编解码的图像压缩算法matlab仿真

目录 1.算法运行效果图预览 2.算法运行软件版本 3.部分核心程序 4.算法理论概述 4.1 Huffman编码算法步骤 4.2 Huffman编码的数学原理 4.3 基于Huffman编解码的图像压缩 5.算法完整程序工程 1.算法运行效果图预览 2.算法运行软件版本 matlab2022a 3.部分核心程序 ..…

基于ElementUI二次封装el-table与el-pagination分页组件[实际项目使用]

效果&#xff1a; 二次封装el-table组件 <template><div><!-- showHeader:是否显示头部size:表格的大小height:表格的高度isStripe:表格是否为斑马纹类型tableData:表格数据源isBorder:是否表格边框handleSelectionChange:行选中&#xff0c;多选内容发生变化回…

遗传算法的应用——求解一元函数的极值

遗传算法的应用——求解一元函数的极值 1 基本概念2 预备知识3.1 模拟二进制转化为十进制的方法3.2 轮盘赌选择算法 3 问题4 Matlab代码5 运行效果6 总结 1 基本概念 遗传算法(Genetic Algorithm,GA)是模拟生物在自然环境中遗传和进化过程从而形成的随机全局搜索和优化方法&am…