数据结构之堆

文章介绍了树作为非线性数据结构的概念,特别是堆这一完全二叉树的特例。详细阐述了堆的两种类型——大堆和小堆,以及如何在小堆中进行插入和删除元素的操作,包括向上调整和向下调整算法。此外,还提供了堆的初始化和销毁方法。
摘要由CSDN通过智能技术生成

在前面的学习中,我们已经学习了数据结构中的顺序表,链表,栈,队列。这些数据结构都是线性数据结构,从这篇文章开始,我们将要研究这种非线性数据结构。

堆的介绍 

首先介绍一下什么是树

树是有限个节点构成的具有层次关系的集合。因为这种关系的逻辑图看起来像一颗倒挂的树,故叫做树。

其次介绍一下树的种类

树又分为二叉树非二叉树,二叉树又分为完全二叉树满二叉树。这篇文章主要详细介绍,堆是一种完全二叉树。

其次介绍一下堆的种类

堆又分为大堆,小堆。大堆:父节点大于等于子节点  小堆:父节点小于等于子节点

堆的实现 

堆的实现:堆的逻辑结构是完全二叉树,存储结构是顺序结构。下面以小堆的实现为例。

要实现堆,首先明白堆的逻辑结构完全二叉树存储结构顺序表

在完全二叉树中,有如下结论

父节点找左孩子:parent*2+1

父节点找右孩子:parent*2+2

孩子找父节点:(child-1)/2

heap.h

 

 heap.c 

堆的初始化 

void IntiHeap(Hp* heap)
{
	assert(heap);
    //malloc一块空间,用来初始化顺序表
	DateType* tmp = (DateType*)malloc(4 * sizeof(DateType));
	assert(tmp);//保证malloc成功
	heap->arr = tmp;//初始化顺序表
	heap->size = 0;//有效数据个数0
	heap->capcity = 4;//初始容量4
}

堆的销毁

void DestoryHeap(Hp* heap)
{
	assert(heap);
	free(heap->arr);//释放顺序表空间
	heap->arr = NULL;//将指针置空,避免成为野指针
	heap->size = 0;//有效数据置0
	heap->capcity = 0;//容量置0
}

堆的插入

堆的插入是这里的关键,这里以小堆为例,欲在小堆里插入一个元素,这里的步骤为:

step1.直接插入到堆尾        step2.向上调整。

void HeapPush(Hp* heap, DateType n)
{
	assert(heap);
	if (heap->size == heap->capcity)//检查容量
	{
		//扩容
		DateType* tmp = realloc(heap->arr, 2 * heap->capcity * sizeof(DateType));
		assert(tmp);
		heap->arr = tmp;
		heap->capcity *= 2;
	}
	//直接插入,未做调整step1
	heap->arr[heap->size] = n;
	heap->size++;
	//向上调整step2
	UpAdjust(heap->arr, heap->size - 1);//参数为堆的存储顺序表和堆尾节点下标(孩子)
}

向上调整算法

void UpAdjust(DateType* arr, int child)//向上调整算法
{
	int parent = (child - 1) / 2;//找到父亲节点
	while (child != 0)//直到child成为0,不需要向上调整
	{
		if (arr[child] < arr[parent])//如果不满足小堆定义
		{
			//交换
			swap(&arr[child],&arr[parent]);
		}
		else//满足就不需要向上调整了
		{
			break;
		}
        //向上迭代child,parent
		child = parent;
		parent = (child - 1) / 2;
	}
}

堆顶元素删除

堆顶元素删除的步骤为:

step1.交换堆顶元素和堆尾元素,直接删除堆尾元素    step2.向下调整堆。

void HeapPop(Hp* heap)
{
	assert(heap);
	assert(!HeapEmpty(heap));//保证堆不为空
	//step1:先交换,再size--,再调整堆
	swap(&heap->arr[0], &heap->arr[heap->size - 1]);
	heap->size--;
	//step2:调堆,向下调整算法
	DownAdjust(heap->arr, heap->size, 0);
}

向下调整算法:

step2

              //堆的存储结构 堆的有效数据个数 向下调整起始父节点
void DownAdjust(DateType* arr, int size, int parent)
{
	int child = parent * 2 + 1;//找到左孩子
	while (child<size)
	{
         //防止没有右孩子,越界
		if (child+1<size&&arr[child] > arr[child + 1])//调整并找到数据较小的child
		{
			child++;//由左孩子变为右孩子
		}
		
		if (arr[child] < arr[parent])//如果不满足小堆定义
		{
			swap(&arr[child], &arr[parent]);//交换
            //迭代
			parent = child;
			child = parent * 2 + 1;
		}
		else
		{
			break;
		}
	}
}

判断堆是否为空

bool HeapEmpty(Hp* heap)
{
	assert(heap);
	return heap->size == 0;
}

获取堆顶元素

DateType TopHeap(Hp* heap)
{
	assert(heap);
	return heap->arr[0];
}

获取堆有效数据

int HeapSize(Hp* heap)
{
	return heap->size;
}
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

无极太族

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

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

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

打赏作者

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

抵扣说明:

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

余额充值