Hierarchical nonlinear structure - tree (find the problem) 04

Traversing the tree

Here Insert Picture Description
Breadth-first traversal (Breadth-First Search)

1. Tree based breadth first traversal order of the storage structure
Here Insert Picture Description
2. Based on the binary tree structure stored in breadth first traversal chain
starts to access from the root node, then this node as a clue, sequential access is directly connected nodes (child ) sequence, this sequence is a clue, the operation is repeated until all nodes have finished accessing.

Here Insert Picture Description

Algorithm Description:
(1) initializing a queue, the queue and the root;
(2) dequeue a queue element, to obtain a node, the access node;
(3) if the left child node is not empty, the left subtree of the node queue;
(4) if the right child node is not empty, then the right subtree of the node queue;
(5) loop steps 2 through 4 until the queue is empty .

Binary junction structure is described:

  typedef struct node
  {  
      datatype  data;
      struct node *lchild,*rchild;
  }   bitree;
 bitree *Q[MAXSIZE]; 
//设数组Q做队列,队列元素类型为二叉链表结点类型

Program description:

/*=====================================
函数功能:层次遍历二叉树,打印遍历序列
函数输入:二叉链表根结点地址bitree *Ptr
函数输出:无
=======================================*/

void levelOrder (bitree *Ptr)  
{
 	bitree 	*s;
?
 	rear=1; front=0;   					//循环队列初始化 
 	Q[rear]= Ptr;      					//根结点入队 
 	if ( Ptr!=NULL ) 					//根结点非空 
 	{ 	
 		while ( front<rear )   			//队列非空, 执行以下操作 
 		{	
 			front= (front+1)% MAXSIZE;
 			Ptr=Q[front];             	//队头元素出队 
 			printf (" %c ", Ptr→data);    	//访问出队结点 
 			if (Ptr→lchild!=NULL)    		//Ptr的左孩子入队 
 			{	 
 				rear=(rear+1) % MAXSIZE;
   				Q[rear]= Ptr→lchild;
 			}
 			if (Ptr→rchild!=NULL) 		//Ptr的右孩子入队 
 			{ 	
 				rear=(rear+1) % MAXSIZE; 
     			Q[rear]= Ptr→rchild;
 			}  
  		}
 	}
} 

Depth-first traversal (Depth-First Search)

The method of depth-first traversal:
preorder (DLR)
preorder (LDR)
postorder (LRD)

Depth-first traversal recursive algorithm:

1. preorder recursive algorithm

DLR recursive procedure: every time the first visit the root, walk left branch of the tree, until the left subtree is empty, return, and then visit the right subtree.
Here Insert Picture Description

Here Insert Picture Description

Program:

/*=================================
函数功能:先序遍历树的递归算法
函数输入:树的根结点
函数输出:无
屏幕输出:树的先序遍历序列
====================================*/
void PreOrder(BinTreeNode  *t) 
{
 	if( t!=NULL )
 	{
		putchar(t->data);
		PreOrder (t->lchild);
		PreOrder (t->rchild);
 	}
}    //先序遍历

2. In order traversal recursive algorithm

/*=============================
函数功能:中序遍历树的递归算法
函数输入:树的根结点
函数输出:无
屏幕输出:树的中序遍历序列
===============================*/
void  inorder(BinTreeNode *t)
{
    if ( t ) 
    {
         inorder(t->lchild);
         putchar(t->data);  
         inorder(t->rchild);
    }
}

3. postorder recursive algorithm

/*=====================================
    函数功能:后序遍历树的递归算法
    函数输入:树的根结点
    函数输出:无
    屏幕输出:树的后序遍历序列
======================================*/
void  postorder (BinTreeNode *t)
{
    if ( t ) 
    {    postorder(t->lchild);
         postorder(t->rchild);
         putchar(t->data);  
    }
}

Build binary linked list traversal method

Solution: All nodes algorithm basic idea, according to preorder order to establish the list of binary link and complete the corresponding node.
Sequence preorder tree is ABD @ F @@@ CE @@@
Here Insert Picture Description

/*=========================================
函数功能:用先序遍历的方法建立二叉链表
函数输入:(二叉链表根结点)
函数输出:二叉链表根结点
键盘输入:树的先序遍历序列,子树为空时输入@
============================================*/	  
BinTreeNode *CreatBTree_DLR(BinTreeNode *root )
{   
	char ch;
	scanf("%c",&ch);
	if (ch=='@')  root=NULL; //ch=='@'子树为空,则root=NULL返回
	else  
	{                                                  
		root=( BinTreeNode * )malloc(sizeof(BinTreeNode));//建立结点
	   	root->data = ch;  
		//构造左子树链表,并将左子树根结点指针赋给(根)结点的左孩子域
	   	root->lchild=CreatBTree_DLR(root->lchild);
	   	//构造右子树链表,并将右子树根结点指针赋给(根)结点的右孩子域
	   	root->rchild=CreatBTree_DLR(root->rchild);   
	}
	return (root);        
}

4. A non-recursive depth-first traversal algorithm

When implementing the recursive stack it is most commonly used auxiliary structure, using a stack to record yet traversed node, to prepare for future access may be recursive depth-first traversal into a non recursive algorithm.

So what are the benefits of non-recursive algorithm than the recursive algorithm?

1) Non-recursive preorder

算法设计:
Here Insert Picture Description
遇到一个结点,就访问该结点,并把此结点推入栈中,然后去遍历它的左子树。
遍历完它的左子树后,从栈顶弹出这个结点,并按照它的右链接指示的地址再去遍历该结点的右子树结构。

程序如下:

/*==================================
函数功能:先序遍历树的非递归算法
函数输入:树的根结点
函数输出:无
屏幕输出:树的先序遍历序列
=========================================*/
#define MAX 20
	void PreOrder_NR(BinTreeNode *root) 
	{ 
		BinTreeNode *Ptr;
		BinTreeNode *Stack[MAX]; //栈定义
		int top=0; //栈顶指针
		
		Ptr=root; 
		do 
	   {
		   while( Ptr!=NULL) //树结点非空,遍历其左子树
		   {
			   printf("%c", Ptr->data) ;  //打印结点值
			   Stack[top]=Ptr;  //树结点进栈
			   top++;
			   Ptr=Ptr->lchild;  //查看左子树
		   }
		   if (top>0)  //栈非空,出栈
		   {
			   top--;
			   Ptr=Stack[top]; 
			   Ptr=Ptr->rchild; //取栈顶结点右子树
		   }
		}  while( top>0 || Ptr!=NULL); 
	 }

2)非递归中序遍历
Here Insert Picture Description
3)非递归后序遍历
Here Insert Picture Description
测试程序:

/*=========================================
测试功能:树的各种遍历算法测试
测试函数:
 	1. 用先序遍历的方法建立二叉链表CreatBTree_DLR
	2. 非递归先序遍历序列PreOrder_NR
	3. 递归先序遍历序列PreOrder
	4. 递归中序遍历序列inorder
	5. 递归后序遍历序列postorder
==========================================*/
#include "stdio.h"
#include <stdio.h>
#include <stdlib.h>
typedef struct node
{ char data;
  struct node *lchild,*rchild;
} BinTreeNode;

int main()
{
	BinTreeNode *RPtr;
	printf("建立树,输入树的先序遍历序列\n");
	RPtr=CreatBTree_DLR(RPtr);
	printf("\n非递归先序遍历序列结果");
	PreOrder_NR(RPtr);
	printf("\n递归先序遍历序列结果");
	PreOrder(RPtr);
	printf("\n递归中序遍历序列结果");
	inorder(RPtr);
	printf("\n递归后序遍历序列结果");
	postorder(RPtr);
	printf("\n");
}

树的遍历的应用

1.求二叉树深度

1)按先序遍历的方式求二叉树深度
二叉树的深度是二叉树中结点层次的最大值。可通过先序遍历来计算二叉树中每个结点的层次, 其中的最大值即为二叉树的深度。

Here Insert Picture Description
Here Insert Picture Description
该算法会导致根结点右子树求深度不准确

程序实现:

/*===================================================
函数功能:按先序遍历的方式求二叉树深度
函数输入:根结点
函数输出:树的深度
屏幕输出:(叶子结点值、层数、树的当前高度)——方便调试用
=====================================================*/
int  h=0; //全局量累计树的深度
int   TreeDepth_DLR(BinTreeNode *p, int leve ) 
{      
    		if ( p!= NULL) 
		{
			leve++; 
  			if( leve>h )  h=leve; 
			putchar(p->data);
			printf(" leve=%d,h=%d\n",leve,h);
			h=TreeDepth_DLR( p->lchild, leve );  //计算左子树的深度    
			h=TreeDepth_DLR( p->rchild, leve );  //计算右子树的深度  
   		} 
       	return  h; 
} 

2)按后序遍历的方式求二叉树深度
Here Insert Picture Description
Here Insert Picture Description
把左右子树的高度分别记录在lh、rh两个变量中,即使它们都是局部量,但在每一层二者都是可比较的。

程序实现:

/*================================================
函数功能:按后序遍历的方式求二叉树深度
函数输入:根结点
函数输出:树的深度
屏幕输出:(叶子结点值、左右子树高度)——方便调试用
================================================*/
int  TreeDepth_LRD(BinTreeNode *p )
{  
   if (p!=NULL) 
     {
         int lh = TreeDepth_LRD( p->lchild );
         int rh = TreeDepth_LRD( p->rchild );
         putchar(p->data);
         printf(":lh=%d  rh=%d\n",lh+1,rh+1);
         return lh<rh?  rh+1:  lh+1;
    }
  return 0; 
}

2.统计叶子数目

利用遍历的方式来访问树的各个结点,由于叶子结点的特殊性,因此可以统计出一棵树中叶子的数目。
叶子结点判断条件:
root ->lchild == NULL && root ->rchild==NULL
或者: !root->lchild && !root->rchild

统计二叉树中叶子结点的数目并打印出叶子结点的值。

解:
若结点root的左右指针均空,则为叶子。可选用任何一种遍历算法查找叶子,将其统计并打印出来。

【方法一】用先序遍历递归法求树的叶子结点的数目

/*============================================
函数功能:用先序遍历递归法求树的叶子结点的数目
函数输入:二叉树根结点
函数输出:无(通过全局量传递叶子结点的数目)
屏幕输出:叶子结点值
=============================================*/
int sum=0;//通过全局量传递叶子结点的数目
void LeafNum_DLR(BinTreeNode *root)    
{   if ( root!=NULL )  //非空二叉树条件,等效于 if(root)
	{	if(!root->lchild && !root->rchild)  //是叶子结点则统计并打印
		{   
			sum++;    
			printf("%c  ",root->data);   
		}
		LeafNum_DLR(root->lchild); //递归遍历左子树,直到叶子处
		LeafNum_DLR(root->rchild); //递归遍历右子树,直到叶子处
	} 
}

【方法二】递归求树的叶子结点的数目

/*====================================
函数功能:递归求树的叶子结点的数目
函数输入:根结点地址
函数输出:叶子结点数目
=======================================*/
int LeafNum(BinTreeNode *root ) 
{	if (root ==NULL) return(0);
	else if (root ->lchild==NULL && root ->rchild==NULL)
	          return(1);
	else return(LeafNum(root->lchild)+LeafNum(root->rchild));
}

求叶子结点函数的测试

Here Insert Picture Description

/*============================================
测试功能:求叶子结点的数目的测试
测试函数:
1. 递归求树的叶子结点的数目LeafNum 
2. 用先序遍历递归法求树的叶子结点的数目LeafNum_DLR 
===============================================*/
int main()
{
	BinTreeNode *RPtr;
	int i;
	RPtr=creatBtree_DLR(RPtr);
	LeafNum_DLR(RPtr);
	printf("LeafNum_DLR:%d\n ",sum);
	i=LeafNum(RPtr);
	printf("LeafNum:%d \n",i);
	return 0;
}
Published 26 original articles · won praise 3 · Views 1469

Guess you like

Origin blog.csdn.net/herui7322/article/details/104216054