【数据结构】(C语言):堆(二叉树的应用)

news2024/11/19 21:20:41

堆:

  • 此处堆为二叉树的应用,不是计算机中用于管理动态内存的堆。
  • 形状是完全二叉树。
  • 堆分两种:最大堆,最小堆。
  • 最大堆:每个节点比子树所有节点的数值都大,根节点为最大值。
  • 最小堆:每个节点比子树所有节点的数值都小,根节点为最小值。
  • 左右节点的数值没有顺序要求,但有左子节点才能有右子节点。
  • 一般用数组实现堆。最小堆可以实现优先队列。

注:完全二叉树:每个节点最多2个节点,倒数第二层级(含)之前层级的所有节点都有元素,最后一层级从左到右依次有元素(中间不能断)。

子树:节点及其所有子节点形成子树。(即节点,左右子节点,左右子节点的左右子节点,。。。)

根节点:没有父节点。

兄弟节点:其父节点是同一个节点。

父子节点在数组中的索引号
节点索引号(根节点为0)
节点x
父节点(x-1)// 2
左兄弟节点(右节点才有)x - 1
右兄弟节点(左节点才有)x + 1
左子节点2x + 1
右子节点2x + 2


C语言实现:(使用数组实现最小堆)

创建堆(结构体数据类型):记录数组地址和元素个数

// 堆(结构体数据类型)
typedef struct Heap
{
	int *p;			// 记录数组地址
	int n;			// 记录元素个数
} Heap;             // 别名

 (函数)堆初始化:

// 堆初始化
void init(Heap *heap, int length)
{
	heap->p = (int *)malloc(length * sizeof(int));    // 分配内存空间
	if(heap->p == NULL)
	{
		perror("Memory allocation failed");
		exit(-1);
	}
	heap->n = 0;            // 元素个数,初始化为0
}

 创建堆变量,并初始化

Heap heap;         // 创建堆变量
init(&heap, 8);    // 设置数组最大元素个数为8

添加元素:

1、先在末尾添加元素。

2、(向上调整)与父节点比较大小,若小于父节点,与父节点交换位置,直到开头位置(根节点,数组第一个元素)。

(注:子节点索引号为x,父节点索引号为(x-1)//2)

void add(Heap *heap, int data)		// add a element to the heap
{
	// 往末尾添加元素
	heap->p[heap->n] = data;
	// (向上调整) 与父节点比较,小于父节点的值,与父节点交换位置
	int cur = heap->n;
	while(cur > 0)
	{
		int parent = ceil((cur - 1) / 2);
		if(heap->p[parent] > data)
		{
			heap->p[cur] = heap->p[parent];
			heap->p[parent] = data;
			cur = parent;
		}
		else break;
	}
    // 每添加一个元素,元素个数+1
	heap->n++;
}

删除(根节点):

1、记录根节点(数组第一个元素)和末尾节点(数组最后一个元素)。

2、末尾节点的值换到根节点位置,元素个数-1。

3、(向下调整)从根节点开始,依次与左右子节点比较大小,数值小的是父节点,直到比对到末尾。

(注:父节点索引号为x,左子节点索引号为2x+1,右子节点索引号为2x+2)

int delete(Heap *heap)			// delete root from the heap
{
	if(heap->n == 0) return -1;    // 空树
	heap->n--;                     // 每删除一次根节点,元素个数-1
	int root = heap->p[0], enddata = heap->p[heap->n];
	heap->p[0] = enddata;	       // 末尾元素换到第一个位置
	// (向下调整) 与左右子节点比较,若子节点小,与较小子节点交换位置
	int cur = 0;
	while(cur <= heap->n)
	{
		int left = cur * 2 + 1, right = cur * 2 + 2, minchild;
		if(left > heap->n) break;				// 没有左子节点
		if(right > heap->n) minchild = left;	// 没有右子节点,有左子节点
		else									// 左右子节点都有的情况
		{
			// 左右子节点比较,找到较小子节点
			if(heap->p[right] < heap->p[left]) minchild = right;
			else minchild = left;
			// 父节点与较小子节点比较,若子节点小,与子节点交换位置
			if(heap->p[minchild] < enddata)
			{
				heap->p[cur] = heap->p[minchild];
				heap->p[minchild] = enddata;
				cur = minchild;
			}
			else break;
		}
	}
	return root;
}

获取根节点:(数组第一个元素)

int getroot(Heap *heap)			// get the root from the heap
{
	if(heap->n == 0)
	{
		printf("Empty heap\n");
		exit(-1);
	}
	return heap->p[0];
}

遍历堆:(类似广度遍历二叉树)

每个节点比子树的所有节点都小,但左右节点没有顺序要求。

void traverse(Heap *heap)		// show element one by one (like breadth traverse the tree)
{
	if(heap->n == 0) return ;

	printf("elements(%d): ", heap->n);
	for(int k = 0; k < heap->n; k++)
	{
		printf("%d  ", heap->p[k]);
	}
	printf("\n");
}

清空堆:

释放数组内存空间,指向数组的指针指向NULL,元素个数为0。

void clear(Heap *heap)		// clear the heap (free memory space of the array)
{
	free(heap->p);          // 释放数组内存空间
	heap->p = NULL;         // 指针指向NULL,避免野指针
	heap->n = 0;            // 元素个数为0
}

 


完整代码:(heap.c)

#include <stdio.h>
#include <math.h>
#include <stdlib.h>

/* structure */
typedef struct Heap
{
	int *p;			// memory address of the heap (array)
	int n;			// the number of the heap
} Heap;

/* function prototype */
void init(Heap *, int);		// heap initialization
void add(Heap *, int);		// add a element to the heap
int delete(Heap *);			// delete root from the heap
int getroot(Heap *);		// get the root from the heap
void traverse(Heap *);		// show element one by one (likely breadth traverse the tree)
void clear(Heap *);			// clear the heap (free memory space of the array)

/* main function */
int main(void)
{
	Heap heap;
	init(&heap, 8);
	printf("length: %d\n", heap.n);

	add(&heap, 5);	
	printf("root(the minimum): %d\n", getroot(&heap));
	traverse(&heap);
	add(&heap, 8);	
	add(&heap, 3);	
	add(&heap, 9);	
	add(&heap, 2);
	printf("root(the minimum): %d\n", getroot(&heap));
	traverse(&heap);

	delete(&heap);	
	printf("root(the minimum): %d\n", getroot(&heap));
	traverse(&heap);
	delete(&heap);	
	printf("root(the minimum): %d\n", getroot(&heap));
	traverse(&heap);
	
	clear(&heap);
	printf("length: %d\n", heap.n);
	printf("root(the minimum): %d\n", getroot(&heap));
	return 0;
}

/* subfunction */
void init(Heap *heap, int length)		// heap initialization
{
	heap->p = (int *)malloc(length * sizeof(int));
	if(heap->p == NULL)
	{
		perror("Memory allocation failed");
		exit(-1);
	}
	heap->n = 0;
}

void add(Heap *heap, int data)		// add a element to the heap
{
	// add a element to the end of the heap
	heap->p[heap->n] = data;
	// (adjust up) compair with parent,if smaller than parent, change the position
	int cur = heap->n;
	while(cur > 0)
	{
		int parent = ceil((cur - 1) / 2);
		if(heap->p[parent] > data)
		{
			heap->p[cur] = heap->p[parent];
			heap->p[parent] = data;
			cur = parent;
		}
		else break;
	}
	heap->n++;
}

int delete(Heap *heap)			// delete root from the heap
{
	if(heap->n == 0) return -1;
	heap->n--;
	int root = heap->p[0], enddata = heap->p[heap->n];
	heap->p[0] = enddata;	// put the last element to the first position
	// (adjust down) compair with left and right child, minimun is parent
	int cur = 0;
	while(cur <= heap->n)
	{
		int left = cur * 2 + 1, right = cur * 2 + 2, minchild;
		if(left > heap->n) break;				// no left child
		if(right > heap->n) minchild = left;	// have left child, no right child
		else									// have left child and right child
		{
			// compair left child and right child, find smaller one
			if(heap->p[right] < heap->p[left]) minchild = right;
			else minchild = left;
			// smaller child compair with parent,if child is the smallest, change
			if(heap->p[minchild] < enddata)
			{
				heap->p[cur] = heap->p[minchild];
				heap->p[minchild] = enddata;
				cur = minchild;
			}
			else break;
		}
	}
	return root;
}

int getroot(Heap *heap)			// get the root from the heap
{
	if(heap->n == 0)
	{
		printf("Empty heap\n");
		exit(-1);
	}
	return heap->p[0];
}

void traverse(Heap *heap)		// show element one by one (like breadth traverse the tree)
{
	if(heap->n == 0) return ;

	printf("elements(%d): ", heap->n);
	for(int k = 0; k < heap->n; k++)
	{
		printf("%d  ", heap->p[k]);
	}
	printf("\n");
}

void clear(Heap *heap)		// clear the heap (free memory space of the array)
{
	free(heap->p);
	heap->p = NULL;
	heap->n = 0;
}

编译链接: gcc -o heap heap.c

执行可执行文件: ./heap

 

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

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

相关文章

推动高效能:东芝TB67H301FTG全桥直流电机驱动IC

在如今高度自动化的时代&#xff0c;电子产品的性能和效率成为了工程师们关注的焦点。东芝的TB67H301FTG全桥直流电机驱动IC应运而生&#xff0c;以其卓越的技术和可靠性&#xff0c;成为众多应用的理想选择。无论是在机器人、家用电器、工业自动化&#xff0c;还是在其他需要精…

面试篇-系统设计题总结

这里记录一些有趣的系统设计类的题目&#xff0c;一般大家比较喜欢出的设计类面试题目会和高可用系统相关比如秒杀和抢红包等。欢迎大家在评论中评论自己遇到的题目&#xff0c;本篇文章会持续更新。 1、设计一个抢红包系统 抢红包系统其实也是秒杀类中的一个场景&#xff0…

【Linux系统编程】深入剖析:四大IO模型机制与应用(阻塞、非阻塞、多路复用、信号驱动IO 全解读)

目录 概述&#xff1a; 1. 阻塞IO (Blocking IO) 2. 非阻塞IO (Non-blocking IO) 3. IO多路复用 (I/O Multiplexing) 4. 信号驱动IO (Signal-driven IO) 阻塞式IO 非阻塞式IO 信号驱动IO&#xff08;Signal-driven IO&#xff09; 信号IO实例&#xff1a; IO多路复用…

后端之路——最规范、便捷的spring boot工程配置

一、参数配置化 上一篇我们学了阿里云OSS的使用&#xff0c;那么我们为了方便使用OSS来上传文件&#xff0c;就创建了一个【util】类&#xff0c;里面有一个【AliOSSUtils】类&#xff0c;虽然本人觉得没啥不方便的&#xff0c;但是黑马视频又说这样还是存在不便维护和管理问题…

Java支付宝沙箱支付环境配置及简单测试

Java支付宝沙箱环境配置(测试) 1. 沙箱配置环境 沙箱应用 - 开放平台 (alipay.com) 2. 需要用到的基本信息 3. Pom文件添加依赖 <!--支付宝依赖 --><dependency><groupId>com.alipay.sdk</groupId><artifactId>alipay-easysdk</artifactId…

上海晋名室外危废品暂存柜第三次复购项目落地

近日又有一台SAVEST室外危废品暂存柜项目成功验收交付使用。 用户单位是一家致力于光伏电池银浆用电子级银粉的国产化&#xff0c;并开发MLCC、锂离子电池、半导体等领域使用的纳米级粉体材料的企业。 用户于2021年4月底订购1台室外危化品暂存柜和1台室外危废品暂存柜&#x…

南京,协同开展“人工智能+”行动

南京&#xff0c;作为江苏省的省会城市&#xff0c;一直以来都是科技创新和产业发展的高地。近日&#xff0c;南京市政府正式印发了《南京市进一步促进人工智能创新发展行动计划&#xff08;2024—2026 年&#xff09;》和《南京市促进人工智能创新发展若干政策措施》的“11”文…

【JNDI注入利用工具】JNDIExploit v1.1

# 简介 JNDIExploit一款用于 JNDI注入 利用的工具&#xff0c;大量参考/引用了 Rogue JNDI 项目的代码&#xff0c;集成了JDNI注入格式&#xff0c;能够更加方便的开启服务端后直接利用&#xff0c;支持反弹Shell、命令执行、直接植入内存shell等&#xff0c;并集成了常见的by…

海思SD3403/SS928V100开发(14)WIFI模块RTL8821驱动调试

1.前言 芯片平台: 海思SD3403/SS928V100 操作系统平台: Ubuntu20.04.05【自己移植】 WIFI模块: LB-LINK的RTL8821 2. 调试记录 参考供应商提供的操作手册 2.1 lsusb查看设备 2.2 编译供应商提供的驱动 2.2.1 修改Makefile 2.2.2 编译报错 解决办法: 将Makefile中arm…

并发编程工具集——读写锁-ReadWriteLock(上篇)(十六)

什么是读写锁 基本原则&#xff1a;&#xff08;读读不互斥、读写互斥、写写互斥&#xff09; 允许多个线程同时读共享变量&#xff1b;只允许一个线程写共享变量&#xff1b;如果一个写线程正在执行写操作&#xff0c;此时禁止读线程读共享变量。读写锁与互斥锁的一个重要区别…

Turborepo简易教程

参考官网&#xff1a;https://turbo.build/repo/docs 开始 安装全新的项目 pnpm dlx create-turbolatest测试应用包含&#xff1a; 两个可部署的应用三个共享库 运行&#xff1a; pnpm install pnpm dev会启动两个应用web(http://localhost:3000/)、docs(http://localhost…

springboot智慧家政系统-计算机毕业设计源码96192

目 录 摘要 1 绪论 1.1 选题背景与意义 1.2开发现状 1.3论文结构与章节安排 2 智慧家政系统系统分析 2.1 可行性分析 2.1.1 技术可行性分析 2.1.2 经济可行性分析 2.1.3 操作可行性分析 2.2 功能需求分析 2.2.1 功能性分析 2.2.2 非功能性分析 2.3 系统用例分析 …

MMSC物料库位扩充

MMSC物料库位扩充 输入事务码MMSC&#xff1a; 回车后添加新的库位即可&#xff1a; 代码实现&#xff0c;使用BDC *&------------------------------------------------* *&BDC的定义 *&------------------------------------------------* DATA gt_bdcdata T…

意图数据集HWU、Banking预处理

当谈到意图数据集时&#xff0c;HWU、Banking和Clinc是三个常见的数据集。以下是关于这三个数据集的介绍&#xff1a; 目录 一、数据集介绍 HWU数据集 Banking数据集 Clinc数据集 二、数据集预处理 数据处理 数据存储 数据类别分析 句子长度统计 一、数据集介绍 HW…

C++20中的三向比较运算符(three-way comparison operator)

在C20中&#xff0c;引入了一个新的特性&#xff0c;即"三向比较运算符(three-way comparison operator)"&#xff0c;由于其外观&#xff0c;也被称为"宇宙飞船运算符(spaceship operator)"&#xff0c;其符号为<>。目的是简化比较对象的过程。这个…

JavaScript中闭包的理解

闭包&#xff08;Closure&#xff09;概念&#xff1a;一个函数对周围状态的引用捆绑在一起&#xff0c;内层函数中访问到其外层函数的作用域。简单来说;闭包内层函数引用外层函数的变量&#xff0c;如下图&#xff1a; 外层在使用一个函数包裹住闭包是对变量的保护&#xff0c…

用递归解决冒泡排序问题

冒泡排序是种很简单的排序方式. 如果用循环方式, 通常就是两层循环. 由于两层循环都是与元素个数 N 线性相关, 所以可以简单估算出它的时间复杂度是 O(N2), 通常而言, 这是较糟糕的复杂度. 当然, 这也几乎是所有简单方式的宿命, 想简单就别想效率高! 前面篇章说到递归也是一种循…

【LabView学习篇 - 1】:初始LabView

文章目录 初始LabView前面板和程序框图前面板&#xff08;Front Panel&#xff09;程序框图&#xff08;Block Diagram&#xff09;交互和工作流程 练手小案例&#xff1a;LabView中实现加法操作 初始LabView LabVIEW&#xff08;Laboratory Virtual Instrument Engineering W…

学习笔记——动态路由——OSPF(基础配置)

九、OSPF基础配置 1、OSPF基础配置 <Huawei>sys [Huawei]sys AR1 [AR1]un in en //取消配置回馈信息 [AR1]int g0/0/0 [AR1-GigabitEthernet0/0/0]ip add 10.1.12.1 24 //给ar1路由接口0配置IP地址 # 配置OSPF [AR1-GigabitEthernet0/0/0]ospf 1 router…