二叉树的遍历与线索化

二叉树的遍历

二叉树遍历:
按一定规律对二叉树中的每个结点进行访问且仅访问一次。
二叉树的基本结构由根结点、左子树和右子树组成。
在这里插入图片描述
L、D、R分别表示遍历左子树、访问根结点、遍历右子树,
那么对二叉树的遍历顺序就可以有:

  • 访问根,遍历左子树,遍历右子树 (记做DLR)。
  • 访问根,遍历右子树,遍历左子树 (记做DRL)。
  • 遍历左子树,访问根,遍历右子树 (记做LDR)。
  • 遍历左子树,遍历右子树,访问根 (记做LRD)。
  • 遍历右子树,访问根,遍历左子树 (记做RDL)。
  • 遍历右子树,遍历左子树,访问根 (记做RLD)。

在以上六种方式中,按先左后右的顺序:就只剩下DLR 、LDR 和LRD三种。
根据对根的访问先后顺序:

  • DLR为先序遍历先根遍历
  • LDR为中序遍历(对称遍历);
  • LRD为后序遍历
    注意:先序、中序、后序遍历是递归定义的,即在其子树中亦按上述规律进行遍历。

先序遍历(DLR)操作过程
若二叉树为空,则为空操作,否则依次执行如下操作:
(1)访问根结点;
(2)按先序遍历左子树;
(3)按先序遍历右子树。

中序遍历(LDR)操作过程
若二叉树为空,则为空操作,否则依次执行如下操作:
(1)按中序遍历左子树;
(2)访问根结点;
(3)按中序遍历右子树。

后序遍历(LRD)操作过程
若二叉树为空,则为空操作,否则依次执行如下操作:
(1)按后序遍历左子树;
(2)按后序遍历右子树;
(3)访问根结点。

如下二叉树,其先序、中序、后序遍历的序列为:
在这里插入图片描述

  • 先序遍历: A、B、D、F、G、C、E、H
  • 中序遍历: B、F、D、G、A、C、E、H
  • 后序遍历: F、G、D、B、H、E、C、A

表达式求值:(a + b * c) – d / e
在这里插入图片描述

  • 先序(前缀):-+a*bc/de
  • 中序(中缀):a+b*c-d/e
  • 后序(后缀):abc*+de/-

中缀:表达式通常形式,只是没有括号;
前缀:波兰表达式,波兰逻辑学家J.Lukasiewicz提出;
后缀:逆波兰表达式,计算机易于求值。

先序遍历算法:

void  PreOrder(BiTree root) 
{	if (root!=NULL)
	{	
	    Visit(root ->data);       /*访问根结点*/
	  	PreOrder(root ->LChild);  /*先序遍历左子树*/
	  	PreOrder(root ->RChild);  /*先序遍历右子树*/
	}
} 

中序遍历算法:

void  InOrder(BiTree root)  
{	if (root!=NULL)
	{
	    InOrder(root ->LChild);   /*中序遍历左子树*/
	    Visit(root ->data);        /*访问根结点*/
	    InOrder(root ->RChild);   /*中序遍历右子树*/
	}
} 

后序遍历算法:

void  PostOrder(BiTree root)  
{	if(root!=NULL)
	{
	    PostOrder(root ->LChild);  /*后序遍历左子树*/
	    PostOrder(root ->RChild);  /*后序遍历右子树*/
	    Visit(root ->data);       /*访问根结点*/
	}
} 

中序遍历二叉树的递归过程:
在这里插入图片描述

递归算法的时间复杂度:

  • n个结点,每个都作子树被访问;
  • 入栈、出栈和访问各一次;
  • 时间复杂度为O(n).

遍历算法应用

1. 输出二叉树中的结点

给出的是先序的算法,其他两种只需将访问操作变为输出操作即可。

void  PreOrder(BiTree root) 
/*先序遍历二叉树,root为指向二叉树根结点的指针*/
{	
    if (root!=NULL)
	{
		printf("%c ", root->data);  /*输出结点*/
		PreOrder(root->LChild);  /*先序遍历左子树*/
		PreOrder(root->RChild);  /*先序遍历右子树*/
	}
}

2. 输出二叉树中的叶子结点

void  PreOrder(BiTree root) 
/*先序遍历二叉树, root为指向二叉树根结点的指针*/
{	
    if (root!=NULL)
	{	
	    if (root->LChild==NULL && root->RChild==NULL)
	       printf("%c  ", root->data);  /*输出叶子结点*/
		PreOrder(root->LChild);  /*先序遍历左子树*/
		PreOrder(root->RChild);  /*先序遍历右子树*/
	}
}

3. 统计叶子结点数目
方法1(后序遍历):

/* LeafCount保存叶子结点数目的全局变量,调用之前初始化值为0 */
void leaf(BiTree root)
{  
   if(root!=NULL)
   {
       leaf(root->LChild);
       leaf(root->RChild);
       if (root->LChild==NULL && root->RChild==NULL)
           LeafCount++;
   }
} 

方法2(后序遍历):
采用分治算法,如果是空树,返回0;如果只有一个结点,返回1;否则为左右子树的叶子结点数之和。

int leaf_b(BiTree root)
{
	int LeafCount;
	if(root==NULL)	
	    LeafCount=0;
	else 
		if((root->Lchild==NULL) && (root->Rchild==NULL))
			LeafCount=1;
		else 
			LeafCount=leaf_b(root->LChild)+leaf_b(root->RChild);
	return LeafCount;
}

4. 建立二叉链表方式存储的二叉树
给定二叉树遍历序列,创建二叉树(链表)。
这里说的遍历序列是一种“扩展遍历序列”:用小圆点显示表示空子树。
在这里插入图片描述
如,先序遍历序列A B . D F. .G . .C . E . H . .
【算法思想】
读入当前根结点的数据,如果是“.”则将当前树根置为空,否则申请一个新结点,存入当前根结点的数据,分别用当前根结点的左子域和右子域进行递归调用,创建左、右子树。

void CreateBiTree(BiTree *bt)
{	
    char ch;
	ch = getchar();
    if(ch == '.')  *bt = NULL;
    else 
	{	
	        *bt = (BiTree)malloc(sizeof(BiTNode)); //生成一个新结点
       		(*bt)->data=ch;
        	CreateBiTree(&((*bt)->LChild)); //生成左子树
        	CreateBiTree(&((*bt)->RChild)); //生成右子树
	}
}

5. 求二叉树的高度
高度其实就是左右子树高度最大值+1。
在这里插入图片描述

  • 后序:先求hl, hr, 再return hl>hr?hl+1:hr+1
  • 先序:从根累计高度(h=1),子树h+1 。

后序算法:

int PostTreeDepth(BiTree bt)   /* 后序遍历求二叉树的高度递归算法 */
{	
    int hl, hr, max;
	if(bt != NULL)
	{	hl = PostTreeDepth(bt->LChild);  /* 求左子树的深度 */
		hr = PostTreeDepth(bt->RChild);  /* 求右子树的深度 */
		max = hl>hr?hl:hr;          /* 得到左、右子树深度较大者*/
		return(max+1);               /* 返回树的深度 */
	}
	else return(0);             /* 如果是空树,则返回0 */
}

先序算法:

void PreTreeDepth(BiTree bt, int h)
/* h为bt指向结点所在层次,初值为1*/
/*depth为当前求得的最大层次,为全局变量,初值为0 */
{  
    if(bt != NULL)
    {     
        if(h > depth)   depth = h;     /*层次值h大于depth,更新*/
     	PreTreeDepth(bt->Lchild, h+1);  /* 遍历左子树 */
     	PreTreeDepth(bt->Rchild, h+1);  /* 遍历右子树 */
    }
}

6. 按树状打印二叉树

示意:
在这里插入图片描述
【算法思想】
二叉树的横向打印应是竖向显示的90度旋转,恰好为逆中序顺序(RDL)。
每次递归进层时层深度加1。

void PrintTree(BiTree bt, int nLayer) //nLayer:结点层次
{
 	if(bt == NULL)  return;
	PrintTree(bt->RChild, nLayer+1);
	for(int i=0;i<nLayer;i++)  
	   printf("  ");//深度
	printf("%c\n", bt->data);//按逆中序输出结点,用层深决定的左、右位置
	PrintTree(bt->LChild,nLayer+1);
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值