二叉树[完全二叉树堆的实现]

二叉树的概念

一颗二叉树是结点的一个有限集合,该集合或者为空,或者是由一个根节点加上左子树和柚子树的二叉树组成

二叉树的特点

1、每个结点最多有俩个子树,每个结点的度不超过2
2、二叉树子树有左右之分,并且次序不能颠倒

特殊二叉树

1、满二叉树:一个二叉树,如果每一个层的结点都到达最大值时为满二叉树。也就是说如果一个二叉树的深度为K,则满二叉树的结点为(2^k)-1。
2、完全二叉树:一棵深度为k的有n个结点的二叉树,对树中的结点按从上至下、从左到右的顺序进行编号,如果编号为i(1≤i≤n)的结点与满二叉树中编号为i的结点在二叉树中的位置相同,则这棵二叉树称为完全二叉树。
完全二叉树:
完全二叉树
满二叉树:
在这里插入图片描述

二叉树的性质

1、如果规定根节点的层数为1,则二叉树每一层的节点个数为2^(i-1),i代表层数。
2、如果规定根节点的层数为1,则二叉树的最大结点个数为2^h-1。
3、对于任何一个二叉树,度为0的结点个数为n0,度为2的结点个数为n2,则有n0 = n2+1。
4、如果规定根节点的层数为1,结点个数为n的满二叉树的深度为log2(n+1).
5、对于具有n个结点的完全二叉树,结点按照从上向下从左向右的顺序进行从0开始编号。则对于序号为i的结点(i>0),则它的父亲结点为(i-1)/2;左孩子结点为2i+1;右孩子结点为2i+2;且左右孩子下标必须小于n。

完全二叉树的顺序结构及实现

1、堆的概念及结构
如果有一个关键码的集合K = {k0,k1, k2,…,kn-1},把它的所有元素按完全二叉树的顺序存储方式存储
在一个一维数组中,并满足:Ki <= K2i+1 且 Ki<= K2i+2 (Ki >= K2i+1 且 Ki >= K2i+2) i = 0,1,2…,则称为
小堆(或大堆)。将根节点最大的堆叫做最大堆或大根堆,根节点最小的堆叫做最小堆或小根堆。
2、堆的性质:
堆中某个节点的值总是不大于或不小于其父节点的值;
堆总是一棵完全二叉树。
在这里插入图片描述

##堆的向下调整算法
向下调整算法有一个前提:左右子树必须是一个堆,才能调整。
在这里插入图片描述
思路:
在这里插入图片描述
代码:

#include <stdio.h>

void swap(int* a, int* b)
{
	int temp = *a;
	*a = *b;
	*b = temp;

}
void AdjustDown(int* a, int i, int n)
{
	//找出左右孩子最小的哪一个
	int parent = i;
	int child = 2 * parent + 1;
	//一直比到孩子超出数组最大值结束
	while (child < n)
	{
		if (child + 1 < n && a[child] > a[child + 1])
		{
			child = child + 1;
		}
		//如果父亲比孩子大
		if (a[parent] > a[child])
		{
			//交换父亲孩子
			swap(&a[parent], &a[child]);
			parent = child;
			child = 2 * parent + 1;
		}
		//如果父亲比孩子都小,停止交换
		else
		{
			break;
		}
	}
}
void ptintarr(int* a, int size)
{
	for (int i = 0; i < size; i++)
	{
		printf("%d ", a[i]);
	}
	printf("\n");
}
int main()
{
	int array[] = { 27,15,19,18,28,34,65,49,25,37};
	//求出数组的大小
	int size = sizeof(array) / sizeof(array[0]);
	AdjustDown(array, 0, size);
	ptintarr(array, size);
	return 0;
}

堆的实现

上面我们说的堆的向下调整算法,只适合根节点的左右子树都是一个堆的情况下。如果左右子树不是一个堆呢?
思路:
在这里插入图片描述
代码:

#include <stdio.h>

void swap(int* a, int* b)
{
	int temp = *a;
	*a = *b;
	*b = temp;

}
void AdjustDown(int* a, int i, int n)
{
	//找出左右孩子最小的哪一个
	int parent = i;
	int child = 2 * parent + 1;
	//一直比到孩子超出数组最大值结束
	while (child < n)
	{
		if (child + 1 < n && a[child] > a[child + 1])
		{
			child = child + 1;
		}
		//如果父亲比孩子大
		if (a[parent] > a[child])
		{
			//交换父亲孩子
			swap(&a[parent], &a[child]);
			parent = child;
			child = 2 * parent + 1;
		}
		//如果父亲比孩子都小,停止交换
		else
		{
			break;
		}
	}
}
void ptintarr(int* a, int size)
{
	for (int i = 0; i < size; i++)
	{
		printf("%d ", a[i]);
	}
	printf("\n");
}
int main()
{
	//int array[] = { 27,15,19,18,28,34,65,49,25,37};
	求出数组的大小
	//int size = sizeof(array) / sizeof(array[0]);
	//AdjustDown(array, 0, size);
	//ptintarr(array, size);
	//return 0;
	int array[] = {1,8,3,5,7,6};
	int size = sizeof(array) / sizeof(array[0]);
	//找出最后一个叶子
	int end = size - 1;
	//找出它的父亲
	int parent = (end - 1) / 2;
	while (parent >= 0)
	{
		AdjustDown(array, parent, size);
		parent--;
	}
	ptintarr(array, size);
}
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值