树和二叉树的定义和实现

树和二叉树的定义

树是一个或多个结点的有限集合,存在一个为根的特定结点,其余结点被分为n个无不相交集合,T1,T2,T3……Tn,其中的每一个集合都是一棵树,T1,T2……Tn为根结点的子树。
在这里插入图片描述
结点:树中一个独立单元
结点的度:结点拥有的子树数称为结点的度
树的度:树内各结点度的最大值
叶子:度为0的结点或终端结点
非终端结点:度不为0的结点
双亲和孩子:结点的子树的根称为该结点的孩子,该结点称为孩子的双亲
层次:结点的层次从根开始定义,根为第一层,根的孩子为第二层,以此类推

树的基本性质
1.树中所有结点数等于所有结点的度数之和加一(这个一就是根结点)
2.对于度为m的树,第i层最多有m的i-1次幂个结点
3.对于高度为h,度为m的树,最多有(m的h幂-1)/(m-1)个结点(等比数列求和)

二叉树
二叉树是n个结点所构成的集合,它或为空树(n=0)或为非空树
对于非空树T
1.有且仅有一个根结点
2.除根结点以外的其余结点分为两个互不相交的子集T1和T2,分别称为T的左子树和右子树,且T1和T2本身都是二叉树
3.二叉树每一个结点至多有两棵子树
4.二叉树的子树有左右之分,其次序不能颠倒

二叉树的基本形态
在这里插入图片描述
二叉树的性质
性质一:二叉树的第i层最多有2的i-1次幂个结点(i>=1)
性质二:深度为k的二叉树最多有2的k次幂-1个结点
性质三:对于任何非空的二叉树T,如果叶子结点的个数为n0,而度为2的结点数为n2,则n0=n2+1
总度数:n1×1+n2×2+1=总结点数:n0+n1+n2

特殊二叉树
1.满二叉树 2.完全二叉树 3.斜树 4.二叉排序树 5.二叉搜索树

满二叉树:所有叶子结点只出现在最后一排,深度为k且含有2^k-1的结点的二叉树
对于同样深度的二叉树,满二叉树的结点数最多,叶子结点的数量也最多,如果对满二叉树进行缩写,根结点从1开始,从上到下,从左到右,对于编号为i的结点,若存在孩子,则左孩子的编号为2i,右孩子的编号为2i+1

完全二叉树:深度为k的,有n个结点的二叉树,当且仅当其每一个结点都与深度为k的满二叉树中的编号一一对应时,称为完全二叉树

特点:
1.叶子结点只能在倒数第一层和倒数第二层上出现
2.对任意一个结点,若其右分支下的子孙的最大层次为i,则其左分支下的子孙的最大层次为1或i+1
3.没有左子树,不能有右子树,上一层没有铺满,不能有下一层

性质
1.具有n个结点的完全二叉树的深度为log2n+1(向下取整)
2.如果对一颗有n个结点的完全二叉树的结点按层序编号,则对任意结点i,以下结论成立:
1.i=1,结点i是根,无双亲,如果i>1则其双亲是i/2(向下取整)
2.2i>n,则i无左孩子,否则其左孩子是2i
3.如果2i+1>n,则该结点i无右孩子,否则其右孩子是2i+1

例题
1.

在这里插入图片描述
答案:完全二叉树的叶子结点只能在最后两层出现,求最多只能让第六层为倒数第二层,7^2-1-8×2=111

在这里插入图片描述
答案:总结点数n=n0+n1+n2,n0=n2+1,n=2×n2+n1+1,因为n为偶数,有一个度为一的结点,带入n2=383,n0=384

在这里插入图片描述

答案:题目表示叶节点只在最后一层,设高度为h,2^(h-1)=k,h=log2k+1=log2 2k
2^n-1=2k-1

二叉树的实现
二叉树的存储
1.顺序结构:除满二叉树和完全二叉树外,不适用,浪费空间

2.链式结构
1.二叉树的存储

在这里插入图片描述

typedef char ElemType;
typedef struct TreeNode
{
	ElemType data;
	struct TreeNode* lchild;
	struct TreeNode* rchild;
}TreeNode;
typedef TreeNode* BiTree;

2.创建二叉树
以前序输出的形式构建一个如下图的二叉树
在这里插入图片描述

char str[] = "ABDH#K###E##CFI###G#J##";
int index = 0;
void creatTree(BiTree* t)
{
	ElemType ch;
	ch = str[index++];
	if (ch == '#')
	{
		*t = NULL;
	}
	else
	{
		*t = (BiTree)malloc(sizeof(TreeNode));
		(*t)->data = ch;
		creatTree(&((*t)->lchild));
		creatTree(&((*t)->rchild));
	}

}

3.二叉树的前序遍历

void preOrder(BiTree t)
{
	if (t == NULL)
	{
		return;
	}
	printf("c", t->data);
	preOrder(t->lchild);
	preOrder(t->rchild);
}

4.二叉树的中序遍历

先访问根结点,向树的左下方移动,直到遇到空结点为止,然后访问空结点的父节点,接着继续遍历该结点的右子树,如果右子树没有子树可以遍历,那么继续遍历上层最后一个未被访问的结点

void inOrder(BiTree t)
{
	if (t == NULL)
	{
		return;
	}
	inOrder(t->lchild);
	printf("c", t->data);
	inOrder(t->rchild);
}

5.二叉树的后序遍历
从根结点开始访问结点左右子树,再对该结点进行访问,这意味着该结点的子节点在该结点之前输出

void postOrder(BiTree t)
{
	if (t == NULL)
	{
		return;
	}
	postOrder(t->lchild);
	postOrder(t->rchild);
	printf("c", t->data);
}

在主函数上来验证上述功能

int main()
{
	TreeNode* t;
	creatTree(&t);
	preOrder(t);
	printf("\n");
	inOrder(t);
	printf("\n");
	postOrder(t);
	printf("\n");
	return 0;
}

运行结果
在这里插入图片描述
符合代码运算逻辑

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值