树与二叉树(一)

1.树
(1)基本概念
树是n(n>=0)个结点的有限集合,n=0时,为空树。而在任意一棵非空树中应满足:
1)有且只有一个称为的结点;
2)当n>1时,其余结点可分为m(m>0)个互不相交的有限集合T1,T2…Tm,其中每个集合本身又是一棵树,并且称为根节点的子树
显然,树的定义是递归的,是一种递归的数据结构,树同时作为一种逻辑结构,也是一种分层结构,具有以下两个特点:
树的根结点没有前驱结点除根结点外的所有结点有且只有一个前驱结点
树的所有节点可以有零个或多个后继结点
(2)基本术语
1)结点K
K的祖先结点:根A到点K唯一路径上的任意结点;
K的子孙节点:若结点B是结点K的祖先结点,则结点K是结点B的子孙结点;
K的双亲结点:路径上最接近结点K的结点E称为K的双亲结点,K则为E的孩子结点,根A是唯一没有双亲结点的结点;
K的兄弟结点:有相同双亲的结点。
2)度
树中一个结点的子结点个数称为结点的度,树中结点的最大度数称为树的度;
3)分枝结点
度大于0的结点称为分枝结点,度为0的结点称为叶子结点。(又称端结点)
4)结点的深度、高度和层次
结点的深度:从根节点开始自顶向下逐层累加;
结点的高度:从叶结点开始自底向上逐层累加的;
树的高度(深度):树中结点的最大层数。
5)有序树和无序树
有序树:树中结点的子树从左至右是有次序的,不能交换,称之为有序树,反之无序树。
6)路径和路径长度
路径:树中两个节点所经过的结点序列,路径长度则是,路径上所经过的边的个数。
7)森林
m(m>=0)棵互不相交树的集合(只要将树的根结点删除就成了森林)。
(3)基本性质
树具有以下最基本的性质:
1)树中的节点数等于所有结点的度数加1;
2)度为m的树中第i层至多有m^i-1个结点(i>=1);
3)高度为h的m差数至多有(m^h-1)*(m-1)个结点;
4)具有n个结点的m叉树最小高度为【log(n(m-1)+1)】。
2.二叉树
(1)定义
二叉树,即每个结点至多只有两个子树的的树(即每个结点不存在度大于2的结点),且二叉树的子树有左右之分,并且不能任意颠倒
与树相似,二叉树也采用递归的形式定义。二叉树是n(n>=0)个结点的有限集合
或者为空二叉树,即n=0;
或者由一个根结点和互不相交的被称为根的左子树和右子树组成,其中左子树和右子树又分别是一棵二叉树。
(2)二叉树的5种基本形态
二叉树是有序树,其左右子树不可颠倒,否则将形成一棵新的二叉树。即使是二叉树中只有一棵子树,也需要区分左右子树。二叉树的5中基本形态如下所示:
在这里插入图片描述
(3)几个特殊的二叉树
1)满二叉树
一棵高为h,且含有2^h-1个结点的二叉树成为满二叉树。即,树中每层都含有最多的结点,如下图所示:
满二叉树的叶子结点都集中在二叉树的最下面一层,并且,除了叶子结点之外,每个结点的度数均为2。
在这里插入图片描述
编号:若我们对二叉树按层进行编号,(约定编号规则为:从根节点即为1开始,从上到下,从左到右)这样,对于每个结点均对应一个编号,对于编号为i的结点,若有双亲,则双亲为⌊i/2⌋,若有左孩子,则左孩子为2i,若有右孩子,则右孩子为2i+1
2)完全二叉树
在这里插入图片描述
3)二叉排序树
即为一棵二叉树或者是空二叉树,或者是具有如下性质的二叉树:左子树上所有结点的关键字小于根结点的关键字;右子树上所有结点的关键字均大于根结点的关键字。且,左右子树是一棵二叉排序树。
4)平衡二叉树
树上任一结点的左子树和右子树的深度之差不超过1。
(4)二叉树的性质
1)非空二叉树上的叶子结点数等于度为2的结点数加1,即n0=n2+1;
2)非空二叉树上第k层上至多有2^k-1(k>=1)个结点;
3)高度为h的树至多有2^h-1(h>=1)个结点;
4)对于完全二叉树按从上到下,从左到右的顺序依次编号1,2,…n,则具有以下关系:
①当i>1时,结点i的双亲编号为⌊i/2⌋,即当i为偶数时,其双亲结点的编号是i/2,它是双亲结点的左孩子,当i为奇数时,其双亲结点的编号为(i-1)/2,为双亲结点的右孩子;
②当2i<=n时,结点i的左孩子编号为3i,否则无左孩子;
③当2i+1<=n时,结点i的右孩子编号为3i,否则右左孩子;
④结点i所在的层次(深度)为⌊log2^i+1⌋。
5)具有n(n>0)个结点的完全二叉树的高度为⌈log2^(n+1)⌉ 或者⌊log2n⌋+1.
3.二叉树的存储结构
(1)顺序存储结构
在这里插入图片描述

(2)链式存储结构
二叉树链式存储的结点结构:
lchild data rchild

左指针域数据域右指针域
lchilddatarchild

二叉链表的存储结构:
在这里插入图片描述
在二叉树的链接存储中,结点的结构如下:

   typedef struct  BiTNode
   {   ElemType data;
       struct BiTNode *lchild,*rchild;
   } BiTNode,*BiTree;

其中,data表示值域,用于存储对应的数据元素,lchild和rchild分别表示左指针域和右指针域,用于分别存储左孩子节点和右孩子节点(即左、右子树的根节点)的存储位置。
4.二叉树的遍历和线索二叉树
二叉树的遍历是指按照某条搜索路径访问树中的每个结点,要求每个结点访问一次,并只被访问一次。
主要的遍历次序主要有先序(NLR)、中序(LNR)和后序(LRN)三种算法,
(1)先序操作(PreOrder)
若二叉树为空,则什么也不做,否则:
1)先访问根结点;
2)先序遍历左子树;
3)先序遍历右子树。
对应的递归算法如下:

void PreOrder(BiTree T){
	if(T!-NULL){
	visit(T);
	PreOrder(T->lchild);
	PreOrder(T->rchild);
	}
	}

(2)中序遍历(InOrder)
若二叉树为空,则什么也不做,否则:
1)中序遍历左子树;
2)中访问根结点;
3)中序遍历右子树。
对应的递归算法如下:

void InOrder(BiTree T){
	if(T!-NULL){
	InOrder(T->lchild);
	visit(T);
	InOrder(T->rchild);
	}
	}

(3)后序遍历(PostOrder)
若二叉树为空,则什么也不做,否则:
1)后序遍历左子树;
2)后序遍历右子树;
3)后访问根结点。
对应的递归算法如下:

void PostOrder(BiTree T){
	if(T!-NULL){
	PostOrder(T->lchild);
	PostOrder(T->rchild);
	visit(T);
	}
	}

(4)递归算法与非递归算法的转换
通过,我们可以将二叉树的递归遍历算法转换为非递归算法,下面给出二叉树中序遍历的非递归算法。
实现思路:
先扫描(并非访问)根结点的所有左结点并将其一一进栈,然后出栈一个结点*p(显然该结点没有左孩子结点或其左孩子结点已被访问过),访问它。然后扫描该结点的右孩子结点,将其进栈,再扫描右孩子结点的左孩子结点并一一进栈,如此继续,知道栈空为止。

中序非递归遍历的算法如下:
void InOrder(BiTree T){
		//二叉树的中序非递归实现,需要借助栈实现
	InitStack(S); //初始化栈
	BiTree p=T;	//建立遍历指针
	while(p||!IsEmpty(S)){		//当栈或p非空时进行循环
		if(p){		//
		Push(S,p);	//跟指针进栈,遍历左子树
		p=p->lchild;		//	每遇到非空二叉树,向左
		}
		else
		{
		Pop(S,p);		//跟指针退栈,访问根结点,遍历右子树
		visit(p);		//
		p=p->rchild;	//向右子树走 
	}
	}
	}

(5)层次遍历
如下图所示便是二叉树的层次遍历,按照箭头所指,从上往下,依次遍历,对二叉树中的每个结点进行访问。
在这里插入图片描述
要实现上图所示的遍历,需要借助一个队列,具体的实现思路如下所示:
先将二叉树的根结点入队,然后出队,访问该结点,若它有左子树,则将左子树根结点入队;若它有右子树,则将它的右子树入队,然后出队,对出队结点进行访问,如此反复,指导队空。

二叉树的层次遍历算法如下:
void LevelOrder(BiTree T)
{
	InitQueue(Q);	//初始化辅助队列
	BiTree q;	//
	EnQueue(Q,T);	//根结点入队
	while(!IsEmpty(Q)){	// 队列不空时进行循环
		DeQueue(Q,p); //队头元素出队
		visit(p);  //访问当前p所指向结点
		if(p->lchild!=NULL)
			EnQueue(Q,p->lchild);	//左子树不空,左子树入队
		if(p->rchild!=NULL)
			EnQueue(Q,p->rchild);	//右子树不空,右子树入队
			}
	}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值