数据结构——树


前言

二叉树在数据结构中比较重要的部分,属于逻辑结构。
包括:树和二叉树的转换,树转换成二叉树,森林转化尾二叉树的方法。


一、树是什么?

1.树是n(n>=0)个结点的有限集合,n=0时,它为空树。
2.树有且仅有一个根节点。
3.树除根节点以外,每一个结点可分为m(m>0)个互不相交的集合,其中每一个集合,又是一棵树。

二、树

1.树的基本术语

结点:树中的一个单独单元

结点的度:结点拥有的子树数目称为结点的度

树的度:树的度时树内各结点度的最大值

叶子: 度为0的结点或终端节点

非终端节点: 度不为0的结点

双亲和孩子: 结点的子树称为该结点的孩子,相应的,该节点称该孩子的双亲

兄弟: 拥有同一个双亲的结点之间互称为兄弟

祖先: 从根节点到该节点所经分支上的所有结点

子孙: 以某一结点为根的子树中任意结点称为该节点的子孙

层次: 结点的层数从根开始定义,根为第一层,根的孩子为第二层,以此类推。

堂兄弟:双亲在同一层的孩子结点称为堂兄弟

树的深度: 树节点中最大的层数称为树的深度或高度

有序树或无序树: 树中结点的各子树从左至右是有序的称为有序树,反之 ,为无序树。

森林: m(m>=0)棵树组成的集合。

2.二叉树

1. 二叉树是n(n>=0)个结点的有限集合,n=0时,它为空树。
2. 二叉树中每个结点的度不大于2
3. 二叉树的子树有左右之分
4. 有且仅有一个根结点

如果i处结点是二叉树的任意一结点,那么(2*i)处和(2*i+1)分别是它的左右孩子。

二叉树的性质

性质1:二叉树的第i层上最多有2^(i-1)个结点
性质2:深度为k的二叉树最多有2^k-1个结点	
性质3:对于任意一棵二叉树,如果其终端结点(叶子节点)树为N0,度为2的结点数目为N2,则N0=N2+1

2.满二叉树(特殊的二叉树)

每一层上的节点数都是最大节点数,即每一层i的结点数都是2^(i-1)
深度为k的满二叉树有2^(k-1)个结点


3.完全二叉树(特殊的二叉树)

深度为k,且有n个结点,当且仅当其每一个节点都与深度为k的满二叉树中从1-n的编号一一对应。

在满二叉树的基础上最后一层的结点自右向左依次减少
叶子节点只能在层次最大的两层出现
对于任意一结点,若其右分支下的子孙最大层数为A,那么其左分支下的子孙最大层数必为A或A+1.


4.二叉树的存储结构

1.顺序存储结构
#define SIZEMAX 100
typedef TELemType SqBiTree[SiZEMAX];//1位置存储根节点信息
SqBiTree S; 

以满二叉树为例
把根节点存放在S[1],那么它的左右孩子分别放在S[21]和S[21+1]处。
任意一结点在S[X],那么它的左右孩子分别放在S[2X]和S[2X+1]处。

2.链式存储结构
typedef struct Node
{
	ElemType Data;//数据域
	struct Node *Lchild;//左指针(左孩子)
	struct Node *Rchild;//右指针(右孩子)
}BiTNode,*BiTree;

5.遍历二叉树

1.先序遍历(根左右)
2.中序遍历(左根右)
3.后序遍历(左右根)

以先序遍历为例(递归)

void Traverse(BiTree T)
{
	if(T)
	{
		printf(T->Data);//每进入一个结点就先输出结点内容
		Traverse(T->Lchild);
		Traverse(T->Rchild);
	}
}

递归遍历二叉树的实质就是反复压栈弹栈的过程。(以下面的二叉树为例进行分析)
先序遍历结果为 1 2 4 3.
在这里插入图片描述
在这里插入图片描述

非递归遍历二叉树就是利用栈反复进行压栈弹栈。先序和中序遍历类似,只有后续遍历有一点不同。
后序遍历要把每一个结点做一个标记,记录这个结点压栈的次数。

下面以后续遍历二叉树为例

typedef struct Node
{
	ElemType Data;//数据域
	struct Node *Lchild;//左指针(左孩子)
	struct Node *Rchild;//右指针(右孩子)
	int flag;//在创建二叉树的时候把flag的值赋予0
}BiTNode,*BiTree;
#define SIZE 10//栈的长度
//定义栈
typedef struct
{
	
	BiTree *arr;//指针数组(存储BiTNode*类型的数据,简单来说就是存储BiTree类型的数据)
	//Bitree会指向BiTNode类结点的地址。
	int top;//标记
}Stack;
//初始化栈
void InitStack(Stack &S)
{
	S.arr=new BiTree[SIZE];
	if(!S.arr)
	{
		printf("申请内存失败\n");
	}else
	{
		S.top=0;
		printf("申请内存成功\n");
	}
	
}
//压栈
void Push(Stack &S,BiTree P)
{
	S.arr[S.top++]=P;
}
//弹栈
void Pop(Stack &S,BiTree &P)
{
	P=S.arr[--S.top];
}
//判断栈是否为空
bool AdjustStack(Stack S)
{
	if(S.top)
	{
	return true;
	}else
	{
	return false;
	}
}
//后续遍历二叉树
void Traverse(BiTree &T)//这里传入引用类型,是因为要修改每一个结点的flag标记
{
	Stack S;//定义栈
	BiTree Temp;
	InitStack(S);//初始化栈
	while(T||AdjustStack(S))
	{
		while(T)
		{
			Push(S,T);
			T->flag++;//标记加一
			T=T->Lchild;//指针向左孩子移动
		}
		if(AdjustStack(S))
		{
			Pop(S,Temp);
			if(Temp->flag==2)
			{
				printf(Temp->data);//输出该节点的信息
			}else
			{
			T=Temp->Rchild;
			Push(S,T);
			T—>flag++;
			}
		}
	}
}

后续递归仅仅多了一个标记用来记录遍历指针经过该结点的次数。


6.线索二叉树

总结

提示:这里对文章进行总结:
例如:以上就是今天要讲的内容,本文仅仅简单介绍了pandas的使用,而pandas提供了大量能使我们快速便捷地处理数据的函数和方法。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值