递归法和非递归法遍历二叉树、层次遍历

递归法遍历二叉树

遍历二叉树是指按某条搜索路径巡访树中的每个结点,使得每个结点均被访问一次,而且仅被访问一次

访问的含义很广,可以是对结点做各种处理,包括输出结点的信息,对结点进行运算和修改等

先序遍历

先序遍历二叉树的操作定义如下:
若二叉树为空,则空操作;否则

  • 1、访问根结点
  • 2、先序遍历左子树
  • 3、先序遍历右子树

【算法描述】

Status PreOrderTraverse(BiTree T)
{
    if(T==NULL) return OK;
    else{
         cout << T->data;  //访问根结点 
	     PreOrderTraverse(T->lchild); //先序遍历左子树 
	     PreOrderTraverse(T->rchild); //先序遍历右子树
	    } 
}	        

中序遍历

中序遍历二叉树的操作定义如下:
若二叉树为空,则空操作;否则

  • 1、中序遍历左子树
  • 2、访问根结点
  • 3、中序遍历右子树

【算法描述】

Status InOrderTraverse(BiTree T)
{
    if(T==NULL) return OK;
    else{
	     InOrderTraverse(T->lchild); //中序遍历左子树 
	     cout << T->data;  //访问根结点 
	     InOrderTraverse(T->rchild); //中序遍历右子树
	    } 
}	    

后序遍历

后序遍历二叉树的操作定义如下:
若二叉树为空,则空操作;否则

  • 1、后序遍历左子树
  • 2、后序遍历右子树
  • 3、访问根结点
Status PostOrderTraverse(BiTree T)
{
    if(T==NULL) return OK;
    else{
	     PostOrderTraverse(T->lchild); //后序遍历左子树 
	     PostOrderTraverse(T->rchild); //后序遍历右子树
	     cout << T->data;  //访问根结点
	    } 
}	    	    

在这里插入图片描述
可以自己试试写出这些序列,更好的理解这个算法
在这里插入图片描述
在这里插入图片描述

如果去掉输出语句,从递归的角度看,三种算法使完全相同的,或说这三种算法的访问路径是相同的,只是访问结点的时机不同
在这里插入图片描述
从虚线的出发点到终点的路径上,每个结点经过3次
1次经过时访问=先序遍历
2次经过时访问=中序遍历
3次经过时访问=后序遍历

时间效率:O(n) //每个结点只访问一次
空间效率:O(n) //栈占用的最大辅助空间(只有一条单链)


非递归法遍历二叉树

非递归法遍历二叉树是利用进行遍历。算法会比递归法麻烦些
这里只举中序遍历例子
【算法步骤】
①初始化一个空栈 S,指针 p 指向根结点
②申请一个结点空间 q,用来存放栈顶弹出的元素
③当 p 非空或者栈 S 非空时,循环执行以下操作:

  • 如果 p 非空,则将 p 进栈,p指向该结点的左孩子
  • 如果 p 为空,则弹出栈顶元素并访问,将p指向该结点的右孩子

【算法描述】

Status InOrderTraverse(BiTree T)
{
	BiTree p; InitStack(S); p=T;
	while(p || !StackEmpty(S))
	{
		if(p) { Push(S,p); p = p->lchild; }
		else  { Pop(S,q); cout << q->data; //Pop(S,q),将栈顶元素弹出,并使q指向该元素 
	           p = q->rchild; }	
	}
	return OK; 
}	    

层次遍历二叉树

对于一棵二叉树,从根结点开始,按从上到下、从左到右的(一层一层的)顺序访问每一个结点,且每一个结点仅仅访问一次
在这里插入图片描述
算法设计思路:使用一个队列
使用队列类型定义如下:
在这里插入图片描述

【算法步骤】
1、将根结点进队
2、队不空时循环:从队列中出列一个结点*p,访问它:
①若它有左孩子结点,将左孩子结点进队
②若它有右孩子结点,将右孩子结点进队

【算法描述】

void LevelOrder(BTNode *b)
{
	BTNode *p; SqQueue *qu;
	InitQueue(qu);    //初始化队列 
	enQueue(qu,b);    //根结点指针进入队列 
	while(!QueueEmpty(qu)) //队不为空,则循环 
	{
		deQueue(qu,p);     //出队结点p 
		cout << p->data;
		if(p->lchild!=NULL) enQueue(qu,p->lchild);
		                    //有左孩子时将其进队 
		if(p->rchild!=NULL) enQueue(qu,p->rchild);
	}                       //有右孩子时将其进队 	
}
发布了33 篇原创文章 · 获赞 81 · 访问量 1万+

猜你喜欢

转载自blog.csdn.net/wmy0217_/article/details/104171203