深入理解数据结构第一弹——二叉树(1)——堆

这篇具有很好参考价值的文章主要介绍了深入理解数据结构第一弹——二叉树(1)——堆。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

前言:

在前面我们已经学习了数据结构的基础操作:顺序表和链表及其相关内容,今天我们来学一点有些难度的知识——数据结构中的二叉树,今天我们先来学习二叉树中堆的知识,这部分内容还是非常有意思的,下面我们就开始慢慢学习

准备工作:本人习惯将文件放在test.c、SeqList.c、SeqList.h三个文件中来实现,其中test.c用来放主函数,SeqList.c用来放调用的函数,SeqList.h用来放头文件和函数声明

一、什么是树

在正式进行二叉树的学习之前,我们要了解一下树是何物,其实我们经常讲到的计算机中的树其实是以数组的形式存在在内存中的,只是它的可以形象化成树的形状,如下:

深入理解数据结构第一弹——二叉树(1)——堆,数据结构,算法,c语言

如图,其中0所在位置被称为树顶或者树根都可以,下面的称为子树,其中1所在分叉称为左子树,2所在分叉成为右子树

还有一些规则如下:

深入理解数据结构第一弹——二叉树(1)——堆,数据结构,算法,c语言

对于学过离散数学的同学来说这部分知识并不难,没有学过的自己再去搜一下了解一下吧,这里只讲了一些大概内容

二、什么是堆

树里面有几个特殊的概念,例如完全二叉树和满二叉树,而堆就是完全二叉树的一种完全二叉树就是除了最后一层外,其他层节点数达到最大

堆与普通的完全二叉树的不同在于它的大小堆的性质

大堆:树任何一个父亲>=孩子

小堆:树任何一个父亲<=孩子

例如:

深入理解数据结构第一弹——二叉树(1)——堆,数据结构,算法,c语言

三、堆的节点结构

堆用的顺序表的结构,所以堆的节点结构与顺序表差异不大

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

堆的节点结构很简单,定义一个指针,两个表示容量的整形即可

四、堆的基本操作

//初始化
void HeapInit(HP* php);
//销毁
void HeapDestory(HP* php);
//插入
void HeapPush(HP* php, HPDataType x);
//删除
void HeapPop(HP* php);
//找堆顶元素
HPDataType HeapTop(HP* php);
//判断是否为空
bool HeapEmpty(HP* php);
//算个数
int HeapSize(HP* php);

看上面的函数声明部分我们就可以看到我们每一步要实现的内容,接下来,我们就来一步一步进行实现

1、初始化

//初始化
void HeapInit(HP* php)
{
	assert(php);
	php->a = NULL;
	php->capacity = 0;
	php->sz = 0;
}

2、销毁

//销毁
void HeapDestory(HP* php)
{
	free(php->a);
	free(php);
}

3、插入元素

插入元素时要先检查空间是否够用,如果不够用要先进行扩容

//交换
void Swap(HPDataType* p1, HPDataType* p2)
{
	HPDataType tmp = *p1;
	*p1 = *p2;
	*p2 = tmp;
}
//删除

//向上调整(小堆)
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 AdjustDown(int* 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 HeapPush(HP* php, HPDataType x)
{
	assert(php);
	if (php->sz == php->capacity)
	{
		int newcapacity = php->capacity == 0 ? 4 : php->capacity * 2;
		HPDataType* tmp = (HPDataType*)realloc(php->a, sizeof(HPDataType) * newcapacity);
		php->a = tmp;
		php->capacity = newcapacity;
	}
	php->a[php->sz] = x;
	php->sz++;

	//向上调整
	AdjustUp(php->a, php->sz - 1);
}

在这一步我们还创建了几个其他的函数分担一些功能,这些函数在后文中也有应用

4、判断栈顶元素是否为空

这一步在下面有用到,例如当删除树根元素时,如果树根元素为空就无法操作,所以需要判断树根元素是否为空

//判断是否为空
bool HeapEmpty(HP* php)
{
	assert(php);
	return php->sz == 0;
}

5、删除元素

这里删除元素是删除树根元素

//删除
void HeapPop(HP* php)
{
	assert(php);
	assert(!HeapEmpty(php));
	Swap(&php->a[0], &php->a[php->sz - 1]);
	php->sz--;
	//向下调整
	AdjustDown(php->a, php->sz,0);
}

6、返回树根元素

//找堆顶元素
HPDataType HeapTop(HP* php)
{
	assert(php);
	assert(!HeapEmpty(php));
	return php->a[0];
}

7、算个数

//算个数
int HeapSize(HP* php)
{
	assert(php);
	return php->sz;
}

五、完整代码实例

SeqList.h

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

//初始化
void HeapInit(HP* php);
//销毁
void HeapDestory(HP* php);
//插入
void HeapPush(HP* php, HPDataType x);
//删除
void HeapPop(HP* php);
//找堆顶元素
HPDataType HeapTop(HP* php);
//判断是否为空
bool HeapEmpty(HP* php);
//算个数
int HeapSize(HP* php);

test.c

//堆
int main()
{
	HP hp;
	HeapInit(&hp);
	int a[] = { 65,100,70,32,50,60 };
	for (int i = 0; i < sizeof(a) / sizeof(int); i++)
	{
		HeapPush(&hp, a[i]);
	}
	while (!HeapEmpty(&hp))
	{
		int top = HeapTop(&hp);
		printf("%d ", top);
		HeapPop(&hp);
	}
	return 0;
}

SeqList.c文章来源地址https://www.toymoban.com/news/detail-854028.html

//堆
//初始化
void HeapInit(HP* php)
{
	assert(php);
	php->a = NULL;
	php->capacity = 0;
	php->sz = 0;
}
//销毁
void HeapDestory(HP* php)
{
	free(php->a);
	free(php);
}
//交换
void Swap(HPDataType* p1, HPDataType* p2)
{
	HPDataType tmp = *p1;
	*p1 = *p2;
	*p2 = tmp;
}
//删除

//向上调整(小堆)
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 AdjustDown(int* 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 HeapPush(HP* php, HPDataType x)
{
	assert(php);
	if (php->sz == php->capacity)
	{
		int newcapacity = php->capacity == 0 ? 4 : php->capacity * 2;
		HPDataType* tmp = (HPDataType*)realloc(php->a, sizeof(HPDataType) * newcapacity);
		php->a = tmp;
		php->capacity = newcapacity;
	}
	php->a[php->sz] = x;
	php->sz++;

	//向上调整
	AdjustUp(php->a, php->sz - 1);
}
//删除
void HeapPop(HP* php)
{
	assert(php);
	assert(!HeapEmpty(php));
	Swap(&php->a[0], &php->a[php->sz - 1]);
	php->sz--;
	//向下调整
	AdjustDown(php->a, php->sz,0);
}
//判断是否为空
bool HeapEmpty(HP* php)
{
	assert(php);
	return php->sz == 0;
}
//找堆顶元素
HPDataType HeapTop(HP* php)
{
	assert(php);
	assert(!HeapEmpty(php));
	return php->a[0];
}
//算个数
int HeapSize(HP* php)
{
	assert(php);
	return php->sz;
}

到了这里,关于深入理解数据结构第一弹——二叉树(1)——堆的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包赞助服务器费用

相关文章

  • 【数据结构】带你深入理解栈

    【数据结构】带你深入理解栈

    栈是一种特殊的线性表。其只允许在固定的一端进行插入和删除元素的操作,进行数据的插入和删除的一端称作 栈顶 ,另外一端称作 栈底 。 栈不支持随机访问 ,栈的数据元素遵循 后进先出 的原则,即 LIFO(Late In First Out)。 也许有人曾经听说过 压栈 和 入栈 的术语,以

    2024年02月03日
    浏览(10)
  • 【数据结构】 顺序表详解!深入理解!

    【数据结构】 顺序表详解!深入理解!

    🎥 屿小夏 : 个人主页 🔥个人专栏 : 数据结构解析 🌄 莫道桑榆晚,为霞尚满天! ​ 什么是数据结构?我们为什么要学数据结构?数据结构中的顺序表长什么样子?它是怎么运用? ​ 本期我们将对这些一一讲解,彻底明白数据结构的重要性,以及顺序表是一种什么的数据

    2024年02月08日
    浏览(9)
  • 【脚踢数据结构】深入理解栈

    【脚踢数据结构】深入理解栈

    (꒪ꇴ꒪ ),Hello我是 祐言QAQ 我的博客主页:C/C++语言,Linux基础,ARM开发板,软件配置等领域博主🌍 快上🚘,一起学习,让我们成为一个强大的攻城狮! 送给自己和读者的一句鸡汤🤔: 集中起来的意志可以击穿顽石! 作者水平很有限,如果发现错误,可在评论区指正,感谢🙏

    2024年02月13日
    浏览(11)
  • 深入浅出二叉树— C语言版【数据结构】

    深入浅出二叉树— C语言版【数据结构】

    目录 ​编辑 1.树概念及结构 1.1树的概念 1.2 树的相关概念 ​1.3 树的表示 2.二叉树概念及结构   2.1概念 2.2 特殊的二叉树 2.3 二叉树的性质  2.4 简单二叉树题目练习  2.5 二叉树的存储结构 2.5.1 顺序存储——堆 2.5.2 链式存储 树是一种 非线性的数据结构 ,它是由n(n=0)个有

    2024年02月03日
    浏览(10)
  • 【数据结构】深入探讨二叉树的遍历和分治思想(一)

    【数据结构】深入探讨二叉树的遍历和分治思想(一)

    🚩 纸上得来终觉浅, 绝知此事要躬行。 🌟主页:June-Frost 🚀专栏:数据结构 🔥该文章主要讲述二叉树的递归结构及分治算法的思想。  为了实现二叉树的基本操作以及更好的了解二叉树的结构,先手动创造一个链式二叉树。  创建出来的结构: 📗创建出来的这棵二叉

    2024年02月08日
    浏览(12)
  • C/C++数据结构之深入了解树与二叉树:概念、存储结构和遍历

    C/C++数据结构之深入了解树与二叉树:概念、存储结构和遍历

    树是一种常见的数据结构,它在计算机科学和数学中都有广泛的应用。树结构的最简单形式是二叉树,本文将深入探讨树和二叉树的概念、存储结构以及二叉树的遍历,并提供一些实际的代码示例来帮助理解这些概念。 树 (Tree) 树是一种层次性数据结构,由节点(或称为顶点

    2024年02月06日
    浏览(10)
  • 【算法与数据结构】深入二叉树实现超详解(全源码优化)

    【算法与数据结构】深入二叉树实现超详解(全源码优化)

    上节我们学习了二叉树(前中后)序遍历 这节将实现二叉树。 让我们复习一下二叉树,接着就是二叉树的实现了😊,学习起来吧! 满二叉树:一个二叉树,如果每一个层的结点数都达到最大值,则这个二叉树就是满二叉树。也就是说,如果一个二叉树的层数为K,且结点总

    2024年04月11日
    浏览(10)
  • 深入理解数据结构:队列的实现及其应用场景

    深入理解数据结构:队列的实现及其应用场景

    队列(Queue)是一种具有先进先出(FIFO)特性的数据结构。在队列中,数据的插入和删除操作分别在队列的两端进行。插入操作在队列的尾部进行,而删除操作则在队列的头部进行。这种特性使得队列在很多实际应用中非常有用,比如任务调度、缓冲区管理等。 线性表是一种

    2024年04月28日
    浏览(11)
  • (一)深入理解Mysql底层数据结构和算法

    (一)深入理解Mysql底层数据结构和算法

    索引是帮助MySQL高效获取数据的排好序的数据结构 数据结构模拟网站:Data Structure Visualization 二叉树 不适合做自增ID的数据结构。如下示意图,假设采用二叉树作为表自增主键ID的数据存储结果如下:当查询id为5的数据时,其查询次数为5次 红黑树 不适合做mysql的索引,因为当

    2024年01月25日
    浏览(14)
  • 深入理解哈希表:数据结构中的重要角色

    目录 一. 哈希表的原理与结构 哈希函数 存储数组 哈希冲突与解决方法 总结 二. 哈希函数的作用与设计 哈希函数的作用: 哈希函数的设计: 常见的哈希函数设计方法包括: 三. 哈希冲突与解决方法 1. 开放寻址法(Open Addressing) 2. 链地址法(Chaining) 四. 哈希表的应用 五

    2024年02月11日
    浏览(11)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包