【数据结构】堆的实现(向下调整和向上调整法)和堆排序的实现

这篇具有很好参考价值的文章主要介绍了【数据结构】堆的实现(向下调整和向上调整法)和堆排序的实现。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

建大堆向上调整法,【数据结构】知识篇+代码讲解,数据结构,算法

目录

一、堆的概念引入

二、小堆的实现

①、堆的初始化--HeapInit

②、小堆的向下调整法的实现

③、堆排序的实现

 ④、堆的插入和向上调整法

 ⑤、删除堆顶数据

⑥、获取堆顶

三、时间复杂度总结:


注:本文logN表示以2为底N的对数

一、堆的概念引入

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

建大堆向上调整法,【数据结构】知识篇+代码讲解,数据结构,算法

 堆的概念及结构:

大堆(大根堆):1、完全二叉树  2、每个父亲>=孩子

小堆(小根堆):1、完全二叉树  2、每个父亲<=孩子

将根节点最大的堆叫做最大堆或大根堆,根节点最小的堆叫做最小堆或小根堆。

堆就像一个完全二叉树+数组来存储,只是在这个基础上分大根堆和小根堆(简称大堆和小堆)

而关于左右孩子谁大谁小完全无关


建大堆向上调整法,【数据结构】知识篇+代码讲解,数据结构,算法

堆的意义:

用来选数,因为比如大堆,父亲就是最大的,以后讲的堆排序就是用的这个特征,大堆特点:根(堆顶)就是最大值,小堆特点:根(堆顶)就是最小值。实际应用比如选出哪个地方好评最好的食品,就用到了堆。

堆的性质:

  • 堆中某个节点的值总是不大于或不小于其父节点的值;
  • 堆总是一棵完全二叉树。

例题:

 下列关键字序列为堆的是(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

思路:因为堆的完全二叉树按照数组来存储,则从第一个往后每一层的节点数为1、2、4、6......

比如A:

建大堆向上调整法,【数据结构】知识篇+代码讲解,数据结构,算法

二、堆的实现(主要用小堆实现)

本质就是一个完全二叉树用数组来存,我们用一个动态数组就好

分为三个文件:Heap.h    Heap.c    test.c

关键:

逻辑结构是完全二叉树,物理结构是数组,本质上逻辑结构只是想象出来的,物理结构才是我们真实操作的,所以针对数组,我们真实的是操作它的下标。

如果想构建小堆(大堆一样的思路):

建大堆向上调整法,【数据结构】知识篇+代码讲解,数据结构,算法

首先,我们会跟线性表一样建立一个动态数组来存堆的数据

typedef int HPDataType;
typedef struct Heap
{
	HPDataType* _a;
	int _size;
	int _capacity;
}Heap;

①、向下调整法的实现

向下调整法(大小堆都适用):

  • 前提:如果一棵树中左右子树都是小堆(或大堆),只有根节点不满足,那么就可使用向下调整算法。(这个方法很重要,讲的堆排序都要用到这个算法)数组建堆主要依赖的就是向下调整法
  • 基础知识:对于完全二叉树而言,已知父亲节点的下标为i,则他的左孩子下标为2*i+1,右孩子下标为2*i+2
  • 思路:找出左右孩子中小的那一个,然后与父亲节点交换,然后再找下一个父亲和孩子,再次找出左右孩子中小的那一个,不断比较并交换,直到最后的下标超出了数组的范围。

下面是只有一个左子树的情况(以小堆为例)元素个数n=10,此时数值为37的下标为9,9+1会造成越界

建大堆向上调整法,【数据结构】知识篇+代码讲解,数据结构,算法

综上,调整终止条件有两个:

  • 当二叉树是满二叉树:child < n循环(调整)才会继续
  • 当二叉树的最后某一节点只有左子树(不可能只有右子树,因为是完全二叉树),child+1<n循环(调整)才会继续,否则这种情况会越界
  • 交换过程中满足孩子大于父亲了,说明此次无需交换了

 下面是小堆的向下调整法:

//向下调整算法。前提:左右子树都是小堆
void AdjustDown(HPDataType* a, int n, int root)
{// root说明从root开始调,root不是每次都是0

	//找出左右孩子中小的那一个,默认认为左孩子是小的那一个,否则就加以调整即可
	int parent = root;
	int child = parent * 2 + 1;//先默认child是左孩子,我们的目的是让child成为小的那一个
	while (child < n)
	{//当孩子的下标<n的时候才会一直比较交换,越界就说明堆构建完了
		if (child + 1 < n && a[child + 1] < a[child])//判断还要有一个只有左子树的情况
		{//如果右孩子比左孩子还小,就让child变成右孩子,即下标+1即可
			child++;
		}
		//如果孩子小于父亲就交换
		if (a[child] < a[parent])
		{
			Swap(&a[child], &a[parent]);
			parent = child;//进行下一次的比较判断
			child = parent * 2 + 1;
		}
		else
		{
			break;//因为孩子已经>=父亲了,满足小堆的条件了,就无须继续往下判断,
			//因为在调整的过程中可能就存在在越界之前,孩子>=父亲的情况
            //谨记向下调整法用于只有堆顶不满足,而左右子树满足堆的性质的时候使用
		}
		//仅交换一次还不能够满足小堆,应该持续比较并交换,所以应该是个循环
	}

}

 相反,大堆的向下调整法只要变一下符号即可

//向下调整算法。前提:左右子树都是大堆
void AdjustDown(HPDataType* a, int n, int root)
{// root说明从root开始调,root不是每次都是0

	//找出左右孩子中大的那一个,默认认为左孩子是大的那一个,否则就加以调整即可
	int parent = root;
	int child = parent * 2 + 1;//先默认child是左孩子,我们的目的是让child成为大的那一个
	while (child < n)
	{//当孩子的下标<n的时候才会一直比较交换,越界就说明堆构建完了
		if (child + 1 < n && a[child + 1] > a[child])//判断还要有一个只有左子树的情况
		{//如果右孩子比左孩子还大,就让child变成右孩子,即下标+1即可
			child++;
		}
		//如果孩子大于父亲就交换
		if (a[child] > a[parent])
		{
			Swap(&a[child], &a[parent]);
			parent = child;//进行下一次的比较判断
			child = parent * 2 + 1;
		}
		else
		{
			break;//因为孩子已经<=父亲了,满足大堆的条件了,就无须继续往下判断,
			//因为在调整的过程中可能就存在在越界之前,孩子<=父亲的情况
            //谨记向下调整法用于只有堆顶不满足,而左右子树满足堆的性质的时候使用
		}
		//仅交换一次还不能够满足大堆,应该持续比较并交换,所以应该是个循环
	}

}

向下调整法的时间复杂度:

 因为对于堆来说,按最糟糕的情况来算,那就是每一层就要交换一次节点,那么整个堆就要交换高度次,即log(N+1) (以2为底N+1的对数),故时间复杂度:O(logN)

②、建堆的实现

因为向下调整法是构建在左右子树都是小堆(或大堆)的前提下,那怎么使左右子树是小堆(或大堆)

 只有一个节点时既可看作小堆也可看作大堆,如果以小堆为例,那对于一个完全二叉树,只看叶子结点肯定保证是小堆了(可看做是小堆),那只需从叶子结点的父亲开始调整为小堆,其下标为(n-1-1)/2(因为向下调整法只要在左右子树是小堆(或大堆),根节点不保证是小堆(或大堆)的下用,那么叶子结点可以看做是左右子树),然后在判断它的前一个元素(只需要下标-1就找到上一个元素了),不断往上调整,直到调完最上面的根节点就结束了,最上面的根节点的下标为0

    //数组构建堆
	for (int i = (n - 1 - 1) / 2; i >= 0; i--)
	{//从最后的叶子结点的父节点开始向下调整
		AdjustDown(php->_a, php->_size, i);
//为什么每次都可传堆的大小?本质上,size可以看为终止条件
//当child<size时循环继续,否则循环终止
//那不同节点用向下调整法只是终止的快慢的问题,但最后都会终止
    }

那分析一下向下调整法建堆的时间复杂度: 

建大堆向上调整法,【数据结构】知识篇+代码讲解,数据结构,算法

建大堆向上调整法,【数据结构】知识篇+代码讲解,数据结构,算法

③、堆的初始化--HeapInit

①、数组应该存堆的数据,而数据是源于你传入的数据,用动态数组拷贝数据,才方便后续操作

②、数组建堆要用向下调整法,满足树中所有父亲节点均小于孩子。

void HeapInit(Heap* php, HPDataType* a, int n)
{
	//php: hp代表heap,前面多个p表示指针
	php->_a = (HPDataType*)malloc(sizeof(HPDataType) * n);
	if (php->_a == NULL)
	{//一般malloc很少会失败,为了严谨最好检查一下
		printf("malloc fail!\n");
		exit(-1);
	}
	memcpy(php->_a, a, sizeof(HPDataType) * n);
	//把需要的数据拷贝到堆中,拷贝后才方便动态进行
	//因为传给我们的数组a,它是静态的,不便于后续操作
	php->_size = n;//堆的特点就是本来堆中就有n个数据
	php->_capacity = n;

	//数组构建堆
	for (int i = (n - 1 - 1) / 2; i >= 0; i--)
	{//从最后的叶子结点的父节点开始向下调整
		AdjustDown(php->_a, php->_size, i);
//为什么每次都可传堆的大小?本质上,size可以看为终止条件
//当child<size时循环继续,否则循环终止
//那不同节点用向下调整法只是终止的快慢的问题,但最后都会终止
	}
}

当然也可以用递归来写,但是一般除了练习,最好不要用递归,最好用迭代

④、堆排序的实现(假设排为降序)

若利用向下调整法建小堆可以找出最小的一个,但为了排序,如何找到次小的?正常逻辑是除了这个最大的其他节点再次建小堆,因为再次建小堆就可以再次找到最小的,但是这个方法时间复杂度比较大,为O(N*N)【因为相当于等差数列】

【排降序】:建小堆

【排升序】:建大堆

那么如何减少时间复杂度?

思路:

建大堆向上调整法,【数据结构】知识篇+代码讲解,数据结构,算法

 已知建堆的时间复杂度为O(N),而在排序过程中,由于要每次选出剩余数中最小的数,并保存到每次最后的节点,并要再执行一次向下调整算法,总共需要进行N-1(≈N)次,则向下调整算法的时间复杂度:O(NlogN),再加上建堆的时间复杂度,则=N*logN+N,综上,堆排序的时间复杂度:O(NlogN)

void HeapSort(int* a, int n)
{
	//1、数组建堆
	for (int i = (n - 1 - 1) / 2; i >= 0; --i)
	{
		AdjustDown(a, n, i);
	//当然i也可初始化为n-1,即从叶子结点开始调,但是这么做肯定没有从叶子结点
	//的父节点开始调高效
	}
	//2、找次小,排序
	int end = n - 1;
	while (end > 0)
	{
		Swap(&a[0], &a[end]);
		
		//再继续选次小的
		AdjustDown(a, end, 0);
		--end;
//没有真的删除最后一个数据,只是说我下次再找小交换,最后一个数据
//不被看作堆里面的,不造成影响
	}
}

 ⑤、堆的插入和向上调整法

 插入数据,为了保持堆(小堆或大堆)的性质,它与普通线性表的插入还不完全相同,因为它插入的数据可能会使原来是小堆变成不是小堆,即它比他的父亲还小,就需要重新调整。

头插可以吗?第一、头插会导致关系变乱,原来是父子关系的两节点,会出现父子变兄弟,第二,头插需要挪动数据(因为用的是数组),会导致效率低下,所以用尾插尾插需要用到向上调整法

还是以小堆为例 

向上调整法思路如下: 

建大堆向上调整法,【数据结构】知识篇+代码讲解,数据结构,算法

 也就是从最后插入的数据跟它的父亲比大小,比父亲小就交换,比父亲大就说明不用交换了,满足小堆

void AdjustUp(HPDataType* a, int n, int child)//child表示从哪里开始往上调,他被视为孩子
{
	int parent = (child - 1) / 2;
	while (child > 0)
	{//这里的循环判断条件不应该看父节点,父节点不管怎么都可以>=0,比如child=0,(0-1)/2=0
	//如果以父亲<0作为循环终止条件是判断不出来的
		if (a[child] < a[parent])
		{
			Swap(&a[child], &a[parent]);
			child = parent;
			parent = (child - 1) / 2;
		}
		else
		{
			break;//孩子比父亲大,就无须调整了
		}
	}
}

那么尾插的代码如下: 

void HeapPush(Heap* php, HPDataType x)
{
	assert(php);
	if (php->_capacity == php->_size)
	{
		php->_capacity *= 2;
		HPDataType* tmp = (HPDataType*)realloc(php->_a, sizeof(HPDataType) * php->_capacity);
		if (tmp != NULL)
		{
			php->_a = tmp;
		}
	}
	php->_a[php->_size++] = x;//先插入x
	//然后利用向上调整法再调节为小堆
	AdjustUp(php->_a, php->_size, php->_size - 1);
}

 ⑤、删除堆顶数据

直接删堆顶不行,因为关系会变乱,比如原来的父子关系会变成兄弟,那这里和堆排序的思路差不多,第一个数据与最后一个交换,但是这里最后一个数据是真删,然后再向下调整法,就可以把堆顶删掉了。这里不需要尾删,因为简单且没意义,我们一般都会删除堆顶,不断找次小的数。

void HeapPop(Heap* 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(Heap* php)
{
	assert(php);
	assert(php->_size > 0);

	return php->_a[0];
}

Heap.h:

#pragma once

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

typedef int HPDataType;
typedef struct Heap
{
	HPDataType* _a;
	int _size;
	int _capacity;
}Heap;

//堆的初始化
void HeapInit(Heap* php, HPDataType* a, int n);
//堆的销毁
void HeapDestroy(Heap* php);
//数据插入
void HeapPush(Heap* php,HPDataType x);//与线性表不同的是插入数据后,要保持堆的特性
//删除堆顶的数据
void HeadPop(Heap* php);//并不是删除那么简单,删除完数据还是要保持堆的特性
//获得堆顶的数据
HPDataType HeapTop(Heap* php);

Heap.c:

#define _CRT_SECURE_NO_WARNINGS 1
#include"Heap.h"

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

//向下调整算法。前提:左右子树都是小堆
void AdjustDown(HPDataType* a, int n, int root)
{
	//找出左右孩子中小的那一个,默认认为左孩子是小的那一个,否则加以调整即可
	int parent = root;
	int child = parent * 2 + 1;//先默认child是左孩子的下标,我们的目的是让child成为小的那一个
	while (child < n)
	{//当孩子的下标(每一轮循环child下标都会被更新为左孩子的下标)<n的时候才会一直比较交换,越界就说明堆构建完了
		if (child + 1 < n && a[child + 1] < a[child])//判断还要有一个只有左子树的情况
		{//如果右孩子比左孩子还小,就让child变成右孩子,即小标+1即可
			child++;
		}
		//如果孩子小于父亲就交换
		if (a[child] < a[parent])
		{
			Swap(&a[child], &a[parent]);
			parent = child;//进行下一次的比较判断
			child = parent * 2 + 1;//再次假设小的孩子是左孩子,进行下一次循环
		}
		else
		{
			break;//满足小堆的条件了,无须继续往下判断,
			//因为在调整的过程中,可能出现孩子>=父亲的情况
		}
		//仅交换一次还不能够满足小堆,应该持续比较并交换,所以应该是个循环
	}

}

//向上调整法
void AdjustUp(HPDataType* a, int n, int child)//child表示从最后底开始的下标,因为是从下往上调
{
	int parent = (child - 1) / 2;
	while (child > 0)
	{//这里的循环判断条件不应该看父节点,父节点不管怎么都可以>=0,比如child=0,(0-1)/2=0
	//如果以父亲<0作为循环终止条件是判断不出来的
		if (a[child] < a[parent])
		{
			Swap(&a[child], &a[parent]);
			child = parent;
			parent = (child - 1) / 2;
		}
		else
		{
			break;//孩子比父亲大,就无须调整了
		}
	}
}
void HeapInit(Heap* php, HPDataType* a, int n)
{
	//php: hp代表heap,前面多个p表示指针
	php->_a = (HPDataType*)malloc(sizeof(HPDataType) * n);
	if (php->_a == NULL)
	{//一般malloc很少会失败,为了严谨最好检查一下
		printf("malloc fail!\n");
		exit(-1);
	}
	memcpy(php->_a, a, sizeof(HPDataType) * n);
	//把需要的数据拷贝到堆中,拷贝后才方便动态进行
	//因为传给我们的数组a,它是静态的,不便于后续操作
	php->_size = n;//堆的特点就是本来堆中就有n个数据
	php->_capacity = n;

	//构建堆
	for (int i = (n - 1 - 1) / 2; i >= 0; i--)
	{//从最后的叶子结点的父节点开始向下调整
		AdjustDown(php->_a, php->_size, i);
	}

}

//堆的销毁
void HeapDestroy(Heap* php)
{
	assert(php);
	free(php->_a);
	php->_a = NULL;
	php->_capacity = php->_size = 0;
}

//堆排序的实现
void HeapSort(int* a, int n)
{
	//1、数组建堆
	for (int i = (n - 1 - 1) / 2; i >= 0; --i)
	{
		AdjustDown(a, n, i);
	//当然i也可初始化为n-1,即从叶子结点开始调,但是这么做肯定没有从叶子结点
	//的父节点开始调高效
	}
	//2、找次小,排序
	int end = n - 1;
	while (end > 0)
	{//最后临界条件是end=0,即只剩下一个元素,就无须再排了
		Swap(&a[0], &a[end]);//把建好的堆的最小元素换到和最后的一个元素换
		
		//再继续选次小的
		AdjustDown(a, end, 0);//传入了n-1个元素,相当于把最后的一个元素除去了
		--end;
	}
}

//从堆尾部插入数据
void HeapPush(Heap* php, HPDataType x)
{
	assert(php);
	if (php->_capacity == php->_size)
	{
		php->_capacity *= 2;
		HPDataType* tmp = (HPDataType*)realloc(php->_a, sizeof(HPDataType) * php->_capacity);
		if (tmp != NULL)
		{
			php->_a = tmp;
		}
	}
	php->_a[php->_size++] = x;//先插入x
	//然后利用向上调整法再调节为小堆
	AdjustUp(php->_a, php->_size, php->_size - 1);
}

//从删除堆顶数据
void HeapPop(Heap* 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(Heap* php)
{
	assert(php);
	assert(php->_size > 0);

	return php->_a[0];
}

test.c:

#define _CRT_SECURE_NO_WARNINGS 1
#include"Heap.h"

int main()
{
	int a[] = { 27,15,19,18,28,34,65,49,25,37 };
	Heap hp;
	HeapInit(&hp, a, sizeof(a) / sizeof(a[0]));
	HeapPush(&hp, 19);
	printf("堆顶为%d\n", HeapTop(&hp));
	HeapDestroy(&hp);

	return 0;
}

三、时间复杂度总结:

向上调整法复杂度=向下调整法时间复杂度=O(logN)

向下建堆的时间复杂度:O(N)

堆排序的时间复杂度:O(N*logN)文章来源地址https://www.toymoban.com/news/detail-772522.html

到了这里,关于【数据结构】堆的实现(向下调整和向上调整法)和堆排序的实现的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

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

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

相关文章

  • 数据结构---堆的实现

    前言 一、什么是堆? 二、 堆的实现 1. 堆的结构  2. 接口实现 总结 堆(Heap)是计算机科学中一类特殊的数据结构,是最高效的优先级队列。堆通常是一个可以被看做一棵完全二叉树的数组对象。 现实中我们通常把 堆(一种二叉树) 使用 顺序结构的数组 来存储, 大根堆 :根节

    2024年02月02日
    浏览(39)
  • 数据结构:堆的实现

    如果有一个关键码的集合 K = { k1 ,k2 ,k3 ,…,kn },把它的所有元素按完全二叉树的顺序存储方式存储在一个一维数组中,并且 k(i)  k(i*2+1) 和 k(i)  k(i*2+2), i = 0 , 1 , 2…,则称为小堆 ( 或大堆 ) 。将根节点最大的堆叫做最大堆或大根堆,根节点最小的堆叫做最小堆或小

    2024年02月13日
    浏览(34)
  • 数据结构之堆的结构与实现

    目录 一、堆的概念及结构 1.1堆的概念  1.2堆的性质 1.3堆的结构 二、堆的实现 2.1堆向下调整算法(父亲与孩子做比较)  2.2堆的向上调整算法(孩子与父亲做比较) 2.3堆的创建(向下建堆)  2.4向下建堆的时间复杂度 2.5堆的插入 2.6堆的删除 2.7堆的完整代码实现 三、堆的应

    2024年02月08日
    浏览(40)
  • 数据结构—小堆的实现

    前言:前面我们已经学习了二叉树,今天我们来学习堆,堆也是一个二叉树,堆有大堆有小堆,大堆父节点大于子节点,小堆父节点总小于子节点,我们在学习C语言的时候也有一个堆的概念,那个堆是操作系统中的堆,与我们今天所学的堆全然不同。我们就来实现下小堆。

    2024年02月05日
    浏览(33)
  • 数据结构:堆的实现(C实现)

    个人主页 : 个人主页 个人专栏 : 《数据结构》 《C语言》 当一颗完全二叉树用顺序表来存储时,其被称为堆。 堆总是一棵完全二叉树 堆的某个节点的值总是不大于(大堆)或不小于(小堆)其父节点的值 其可以被用来解决top k 问题 或 堆排序 下面就是要实现的堆的功能 重点在

    2024年02月13日
    浏览(36)
  • 数据结构——二叉树(堆的实现)

    目录   树概念及结构 树的相关概念 树的表示  二叉树的概念及结构   堆 堆的实现   结构体建立 初始化   添加元素  打印堆  删除堆首元素  返回首元素  判断是否为空 空间销毁  刷题找工作的好网站——牛客网 牛客网 - 找工作神器|笔试题库|面试经验|实习招聘内推,

    2024年02月11日
    浏览(44)
  • 【数据结构之堆的实现】

    前言: 前篇学习了 数据结构之树和二叉树的基本概念知识,那么这篇继续学习怎么实现基本的操作。所以先建议看完上篇知识点,才有助于消化知识和理解。 / 知识点汇总 / 概念 :堆(Heap)是计算机科学中一类特殊的数据结构,是最高效的优先级队列。堆通常是一个可以被看

    2024年01月19日
    浏览(42)
  • 【数据结构】堆的实现及应用

    简单不先于复杂,而是在复杂之后 。 1.1 二叉树的顺序结构 普通的二叉树是不适合用数组来存储的,因为可能会存在大量的空间浪费。 而完全二叉树更适合使用顺序结构存储。 现实中我们通常把堆(一种二叉树)使用顺序结构的数组来存储,需要注意的是这里的堆和操作系

    2024年02月21日
    浏览(48)
  • 【数据结构】结构实现:顺序存储模式实现堆的相关操作

    🚩 纸上得来终觉浅, 绝知此事要躬行。 🌟主页:June-Frost 🚀专栏:数据结构 🔥该文章着重讲解了使用顺序结构实现堆的插入和删除等操作。  二叉树的顺序存储是指将二叉树中的所有节点按照一定的顺序(一层一层)存储到一个数组中。  我们可以通过数组下标来表示

    2024年02月08日
    浏览(48)
  • 【数据结构】——二叉树堆的实现

     大佬们点点关注,点点赞?! 在上篇博客中我们已经介绍了树和二叉树的相关概念,相信大家都已经清楚了树和二叉树的基本思想,下面我们就来着重看看二叉树堆的实现。 在看堆的实现,我们先看看二叉树的顺序存储 二叉树的顺序存储就是以顺序表来实现的,也就是把

    2024年04月13日
    浏览(58)

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

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

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

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

二维码1

领取红包

二维码2

领红包