二叉树相关理解

目录

前言

构成

 特殊的二叉树

1. 满二叉树

2.完全二叉树

3.二叉树的性质

4.二叉树的存储结构

二叉树的顺序结构及实现

1 二叉树的顺序结构

2 堆的概念及结构

3 堆的实现

4 堆的插入

 5 堆的删除

6 堆的代码实现


前言

树是一种 非线性 的数据结构,它是由 n n>=0 )个有限结点组成一个具有层次关系的集合

构成

1. 或者为空
2. 由一个根节点加上两棵别称为左子树和右子树的二叉树组成,二叉树是有序树,基本构成如下所示。

 特殊的二叉树

1. 满二叉树

  一个二叉树,如果每一个层的结点数都达到最大值,则这个二叉树就是满二叉树。也就是
说,如果一个二叉树的层数为K,且结点总数是 ,则它就是满二叉树。
 

简单来说:每层节点个数达到了最大值。如果一个二叉树的层数为k,且结点总数是(2^k)-1,则它是满二叉树。

2.完全二叉树

  完全二叉树是效率很高的数据结构,完全二叉树是由满二叉树而引出来的。对于深度为K
的,有n个结点的二叉树,当且仅当其每一个结点都与深度为K的满二叉树中编号从1至n的结点一一对应时称之为完全二叉树。 要注意的是满二叉树是一种特殊的完全二叉树
 

简单来说,假设二叉树总共有n个节点,如果该二叉树与高度相同的满二叉树前n个节点布局形式完全相同,则该二叉树为完全二叉树。

3.二叉树的性质


1. 若规定根节点的层数为1,则一棵非空二叉树的第i层上最多有 个结点.
2. 若规定根节点的层数为1,则深度为h的二叉树的最大结点数是 .
3. 对任何一棵二叉树, 如果度为0其叶结点个数为 , 度为2的分支结点个数为 ,则有 = +1
4. 若规定根节点的层数为1,具有n个结点的满二叉树的深度,h= . (ps: 是log以2为底,n+1为对数)
5. 对于具有n个结点的完全二叉树,如果按照从上至下从左至右的数组顺序对所有节点从0开始编号,则对于序号为i的结点有:
1. 若i>0,i位置节点的双亲序号:(i-1)/2;i=0,i为根节点编号,无双亲节点
2. 若2i+1<n,左孩子序号:2i+1,2i+1>=n否则无左孩子
3. 若2i+2<n,右孩子序号:2i+2,2i+2>=n否则无右孩子


4.二叉树的存储结构

1. 顺序存储
二叉树顺序存储在物理上是一个数组,在逻辑上是一颗二叉树。

 2. 链式存储

二叉树的链式存储结构是指,用链表来表示一棵二叉树,即用链来指示元素的逻辑关系。通常的方法是链表中每个结点由三个域组成,数据域和左右指针域,左右指针分别用来给出该结点左孩子和右孩子所在的链结点的存储地址。


二叉树的顺序结构及实现
 

1 二叉树的顺序结构
 

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

2 堆的概念及结构


    堆中某个节点的值总是不大于或不小于其父节点的值;堆总是一棵完全二叉树.完全二叉树的节点必须满足:如果任意节点都比其他孩子节点小,将其称为小堆。如果任意节点都比其他孩子节点大,将其称为大堆。

 

                                                                   大根堆示意图

3 堆的实现

堆的向下调整算法的前提:左右子树必须是一个堆,才能调整。例如:
int array [] = { 27 , 15 , 19 , 18 , 28 , 34 , 65 , 49 , 25 , 37 }

 以27为根的左右子树都满足堆的特性,只有根节点不满足。所以只需要调整根节点即可。

  int a [] = { 1 , 5 , 3 , 8 , 7 , 6 }; 例如该数组如何进行堆排序                                                                          

 

最终构成的大堆为8 7 6 5 1 3 .建堆的时间复杂度为O(N)

堆的插入

先插入一个 10 到数组的尾上,再进行向上调整算法,直到满足堆。

 5 堆的删除

删除堆是删除堆顶的数据,将堆顶的数据根最后一个数据一换,然后删除数组最后一个数据,再进行向下调 整算法。

6 堆的代码实现

typedef int  DataType;
typedef  int(*c)(int left, int right) ;
typedef struct Heap
{
	DataType *Array;
	int size;
	int capacity;
	c compare;
}Heap;
// 堆的构建
void HeapCreate(Heap* hp,DataType* a, int n);
// 堆的销毁
void HeapDestory(Heap* hp);
// 堆的插入
void HeapPush(Heap* hp, DataType x);
// 堆的删除
void HeapPop(Heap* hp);
// 取堆顶的数据
DataType HeapTop(Heap* hp);
// 堆的数据个数
int HeapSize(Heap* hp);
// 堆的判空
int HeapEmpty(Heap* hp);
void adjustup(int array[], int size, int parent);
int Less(int left,int right)
{
	return left < right;
}
int greater(int left, int right)
{
	return left > right;
}


void swap(int*a, int*b)
{
	int temp = *a;
	*a = *b;
	*b = temp;
}
//小堆调整
void adjustdown(Heap* hp,int parent)
{
	int size = hp->size;
	int *array = hp->Array;
	int child = 2*parent + 1;
	while (child<size)
	{
		if (child + 1<size&&hp->compare(array[child+1],array[child]))
		{
			child += 1;
		}
		
		if(hp->compare(array[child], array[parent]))
		{
			swap(&array[child], &array[parent]);
			parent = child;
			child = 2 * parent + 1;
		}
		else
		{
			return;
		}
	}
}

void adjustup(Heap* hp, int child)
{
	int size = hp->size;
	int *array = hp->Array;
	int parent = (child - 1) / 2;
	while (child)
	{
	
		if (hp->compare(array[child],array[parent]))
		{
			swap(&array[child], &array[parent]);
			child = parent;
			parent = (child - 1) / 2;
		}
		else
		{
			return;
		}
	}
}
// 堆的构建
void HeapCreate(Heap* hp, DataType* a, int n,c compare)
{
	//将数组传入堆
	hp->Array = (DataType*)malloc(sizeof(DataType)*n);
	hp->capacity = n;
	memcpy(hp->Array, a, sizeof(DataType)*n);
	hp->size = n;
	hp->compare = compare;
	for (int root = (n - 2)/2; root >=0;root--)
	{
		adjustdown(hp,root);
	}
}
// 堆的销毁
void HeapDestory(Heap* hp)
{
	free(hp->Array);
	hp->Array = NULL;
	hp->capacity = 0;
	hp->size = 0;
}
//扩容
void checkheapcapacity(Heap* hp)
{
	if (hp->capacity==hp->size)
	{
		int newcapacity = 2 * hp->capacity;
		DataType *ret = (DataType*)malloc(sizeof(DataType)*newcapacity);
		memcpy(ret, hp->Array, sizeof(DataType)*hp->size);
		free(hp->Array);
		hp->Array = ret;
		hp->capacity = newcapacity;
	}
}
// 堆的插入
void HeapPush(Heap* hp, DataType x)
{
	checkheapcapacity(hp);
	hp->Array[hp->size] = x;
	hp->size++;
	adjustup(hp, hp->size - 1);
}
// 堆的删除
void HeapPop(Heap* hp)
{
	if (HeapEmpty(hp))
	{
		return;
	}
	//将堆首与堆尾交换
	swap(&hp->Array[0],&hp->Array[hp->size-1]);
	hp->size--;
	//调整
	adjustdown(hp, 0);
	
}
// 取堆顶的数据
DataType HeapTop(Heap* hp)
{
	return hp->Array[0];
}
// 堆的数据个数
int HeapSize(Heap* hp)
{
	return hp->size;
}
// 堆的判空
int HeapEmpty(Heap* hp)
{
	return 0 == hp->size;
}
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值