数据结构:二叉树---堆

文章目录

  • 前言
  • 一、堆的概念及结构
  • 二、堆的实现
    • 1.头文件Heap.h(结构及其方法的声明)
    • 2.源文件Heap.c(方法的实现)
  • 总结

前言

二叉树是一种特殊的树结构,其中每个节点最多有两个子节点。堆是一种特殊的二叉树,它满足以下性质:

  1. 堆是一个完全二叉树:除了最后一层外,其他层节点个数都是满的,最后一层的节点都集中在左侧。
  2. 堆中每个节点的值大于等于(或小于等于)其子节点的值,这个性质被称为堆序性。

一、堆的概念及结构

堆是一种特殊的二叉树结构,它具有以下两个特点:

1. 堆是一棵完全二叉树:堆中的所有节点从左到右依次填入,不留下任何空洞。

2. 堆中每个节点的值都大于或等于(或小于或等于)其子节点的值:对于最大堆,父节点的值大于或等于其子节点的值;对于最小堆,父节点的值小于或等于其子节点的值。

堆有两种常见的实现方式:数组和二叉树。

1. 数组实现:堆可以使用一维数组来表示,节点的位置与数组的索引存在对应关系。具体来说,对于数组中的第i个元素,它的左子节点位于2i的位置,右子节点位于2i+1的位置,父节点位于i/2的位置。

2. 二叉树实现:堆也可以使用二叉树来表示,每个节点有左子节点和右子节点。通过比较父节点与子节点的值,可以保持堆的性质。

typedef int HPDataType;
// 逻辑结构和物理结构不一样
typedef struct Heap
{
	HPDataType* a;
	int size;
	int capacity;
}HP;

二、堆的实现

1.头文件Heap.h(结构及其方法的声明)

#pragma once

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


typedef int HPDataType;
// 逻辑结构和物理结构不一样
typedef struct Heap
{
	HPDataType* a;
	int size;
	int capacity;
}HP;

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

void HPInit(HP* php);
void HPDestroy(HP* php);
void HPPush(HP* php, HPDataType x);
void HPPop(HP* php);
HPDataType HPTop(HP* php);
bool HPEmpty(HP* php);

2.源文件Heap.c(方法的实现)

2.1 初始化与销毁

#include"Heap.h"

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

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

2.2 交换

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

在函数调用栈区中改变元素大小记得传入地址

2.3 向上调整

/向上调整(插入时判断孩子是否大于(小堆)或小于(大堆)父亲)
void AdjustUp(HPDataType* a, int child)
{ 
	// 循环三要素
	// 初始条件
	// 中间过程
	// 结束条件
	int parent = (child - 1) / 2;
	//while (parent >= 0)   巧合,歪打正着
	while (child > 0)
	{
		if (a[child] < a[parent])
		{
			Swap(&a[child], &a[parent]);
			child = parent;    
			parent = (child - 1) / 2;
		} 
		else
		{
			break;
		}
	}
}

注意循环结束条件如果使用父亲节点则会有巧合刚好不满足条件语句

 

2.4向下调整

//向下调整 (前提:左右孩子是小堆,或者大堆)
void AdjustDown(HPDataType* a, int n, int parent)
{
	// 先假设左孩子小
	int child = parent * 2 + 1;

	while (child < n)  // 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.5 插入

void HPPush(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;
		}

		php->a = tmp;
		php->capacity = newcapacity;
	}

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

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

此处的扩容类比顺序表 

2.6 删除

// logN
// 从小到大依次被取出,变有序了
void HPPop(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);
}

此时小堆结构变为降序,次方法为之后堆排序做铺垫 

 

2.7 取父亲节点

HPDataType HPTop(HP* php)
{
	assert(php);
	assert(php->size > 0);

	return php->a[0];
}

2.8判空

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

	return php->size == 0;
}

总结

堆是一种特殊的数据结构,用于存储和管理一组元素。它的主要作用包括:

1. 优先级队列:堆可以将元素按照一定的优先级进行排序,使得可以快速访问和操作优先级最高的元素。这在诸如调度算法、事件处理等场景中非常有用。

2. 堆排序:堆排序是一种高效的排序算法,它利用堆的性质将元素快速排序。堆排序的时间复杂度为O(nlogn),相比于其他排序算法具有较好的性能。

3. 动态数据结构:堆可以动态地添加和删除元素,而且能够维持堆的性质。这在需求频繁变化的场景中非常有用,例如实时系统中的任务调度。

4. 选择最大/最小元素:对于大顶堆,堆顶元素就是最大元素;对于小顶堆,堆顶元素就是最小元素。通过堆可以快速找到最大或最小的元素。

总之,堆是一种功能强大的数据结构,具有高效的操作和灵活的应用。它在算法和数据处理领域中被广泛使用。

  • 21
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 2
    评论
算法与数据结构它们分别涵盖了以下主要内容: 数据结构(Data Structures): 逻辑结构:描述数据元素之间的逻辑关系,如线性结构(如数组、链表)、树形结构(如二叉树、堆、B树)、图结构(有向图、无向图等)以及集合和队列等抽象数据类型。 存储结构(物理结构):描述数据在计算机中如何具体存储。例如,数组的连续存储,链表的动态分配节点,树和图的邻接矩阵或邻接表表示等。 基本操作:针对每种数据结构,定义了一系列基本的操作,包括但不限于插入、删除、查找、更新、遍历等,并分析这些操作的时间复杂度和空间复杂度。 算法: 算法设计:研究如何将解决问题的步骤形式化为一系列指令,使得计算机可以执行以求解问题。 算法特性:包括输入、输出、有穷性、确定性和可行性。即一个有效的算法必须能在有限步骤内结束,并且对于给定的输入产生唯一的确定输出。 算法分类:排序算法(如冒泡排序、快速排序、归并排序),查找算法(如顺序查找、二分查找、哈希查找),图论算法(如Dijkstra最短路径算法、Floyd-Warshall算法、Prim最小生成树算法),动态规划,贪心算法,回溯法,分支限界法等。 算法分析:通过数学方法分析算法的时间复杂度(运行时间随数据规模增长的速度)和空间复杂度(所需内存大小)来评估其效率。 学习算法与数据结构不仅有助于理解程序的内部工作原理,更能帮助开发人员编写出高效、稳定和易于维护的软件系统。
逻辑结构:描述数据元素之间的逻辑关系,如线性结构(如数组、链表)、树形结构(如二叉树、堆、B树)、图结构(有向图、无向图等)以及集合和队列等抽象数据类型。 存储结构(物理结构):描述数据在计算机中如何具体存储。例如,数组的连续存储,链表的动态分配节点,树和图的邻接矩阵或邻接表表示等。 基本操作:针对每种数据结构,定义了一系列基本的操作,包括但不限于插入、删除、查找、更新、遍历等,并分析这些操作的时间复杂度和空间复杂度。 算法: 算法设计:研究如何将解决问题的步骤形式化为一系列指令,使得计算机可以执行以求解问题。 算法特性:包括输入、输出、有穷性、确定性和可行性。即一个有效的算法必须能在有限步骤内结束,并且对于给定的输入产生唯一的确定输出。 算法分类:排序算法(如冒泡排序、快速排序、归并排序),查找算法(如顺序查找、二分查找、哈希查找),图论算法(如Dijkstra最短路径算法、Floyd-Warshall算法、Prim最小生成树算法),动态规划,贪心算法,回溯法,分支限界法等。 算法分析:通过数学方法分析算法的时间复杂度(运行时间随数据规模增长的速度)和空间复杂度(所需内存大小)来评估其效率。 学习算法与数据结构不仅有助于理解程序的内部工作原理,更能帮助开发人员编写出高效、稳定和易于维护的软件系统。
逻辑结构:描述数据元素之间的逻辑关系,如线性结构(如数组、链表)、树形结构(如二叉树、堆、B树)、图结构(有向图、无向图等)以及集合和队列等抽象数据类型。 存储结构(物理结构):描述数据在计算机中如何具体存储。例如,数组的连续存储,链表的动态分配节点,树和图的邻接矩阵或邻接表表示等。 基本操作:针对每种数据结构,定义了一系列基本的操作,包括但不限于插入、删除、查找、更新、遍历等,并分析这些操作的时间复杂度和空间复杂度。 算法: 算法设计:研究如何将解决问题的步骤形式化为一系列指令,使得计算机可以执行以求解问题。 算法特性:包括输入、输出、有穷性、确定性和可行性。即一个有效的算法必须能在有限步骤内结束,并且对于给定的输入产生唯一的确定输出。 算法分类:排序算法(如冒泡排序、快速排序、归并排序),查找算法(如顺序查找、二分查找、哈希查找),图论算法(如Dijkstra最短路径算法、Floyd-Warshall算法、Prim最小生成树算法),动态规划,贪心算法,回溯法,分支限界法等。 算法分析:通过数学方法分析算法的时间复杂度(运行时间随数据规模增长的速度)和空间复杂度(所需内存大小)来评估其效率。 学习算法与数据结构不仅有助于理解程序的内部工作原理,更能帮助开发人员编写出高效、稳定和易于维护的软件系统。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

取加若则_

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值