递归法和非递归法遍历二叉树

遍历二叉树

  • 遍历定义:顺着某一条搜索路径巡防二叉树中的结点,使得每个结点均被访问一次,而且仅被访问一次(又称周游)。
  • 遍历目的:得到树中所有结点得一个线性排列。
  • 遍历用途:它是树结构插入、删除、修改、查找和排序运算得前提,是二叉树一切运算得基础和核心。
  • 遍历方法:
    在这里插入图片描述
    依次遍历二叉树中的三个组成部分,便是遍历了整个二叉树
    假设:L:遍历左子树 D:访问根结点 R:遍历右子树
    则遍历整个二叉树方案共有:
    DLR、LDR、LRD、DRL、RDL、RLD六种。

1.遍历二叉树递归算法描述

若规定先左后右,则只有前三种情况:
DLR ——先(根)序遍历
LDR——中(根)序遍历
LRD——后(根)序遍历
在这里插入图片描述

先序遍历二叉树的操作定义

  • 若二叉树为空,则空操作;否则:
    1.访问根结点(D);
    2.先序遍历左子树(L);
    3.先序遍历右子树(R)。
Status PreOrderTraverse(BiTree T)
{
    if(T==NULL) return OK;  //空二叉树
    else{
         cout << T->data;  //访问根结点 
	     PreOrderTraverse(T->lchild); //先序遍历左子树 
	     PreOrderTraverse(T->rchild); //先序遍历右子树
	    } 
}	

在这里插入图片描述

中序遍历二叉树的操作定义

  • 若二叉树为空,则空操作;否则
    1.中序遍历左子树(L);
    2.访问根结点(D);
    3.中序遍历右子树(R)。
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次。
    在这里插入图片描述
    在这里插入图片描述
  • 时间效率:O(n) //每个结点只访问一次
  • 空间效率:O(n) //栈占用的最大辅助空间

2.中序非递归算法描述

基本思想
1.建立一个
2.结点进栈,遍历左子树
3.结点出栈,输出根结点,遍历右子树

【算法步骤】
①初始化一个空栈 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; }	
	} // while
	return OK;  
}	

3.层次遍历算法

对于一颗二叉树,从根结点开始,按从上到下,从左到右的顺序访问每一个结点。(每个结点仅访问一次)
算法设计思路:使用一个队列
I. 将根结点进队;
II.队不空时循环:从队列中出列一个结点*p,访问它:
①若它有左孩子结点,将左孩子结点进队
②若它有右孩子结点,将右孩子结点进队

使用队列类型定义如下:

typedef struct{
    BTNode data[MaxSize];  //存放队中元素
    int front, rear;       //队头和队尾指针
}SqQueue;                  //顺序循环队列类型    

二叉树层次遍历算法:

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);
	}                       //有右孩子时将其进队 	
}

4.根据遍历序列确定二叉树

  • 若二叉树中各结点的值均不相同,则二叉树结点的先序序列、中序序列和后序序列都是唯一的。
  • 由二叉树的先序序列和中序序列,或由二叉树的后序序列和中序序列可以确定唯一一个二叉树。

在这里插入图片描述

原创文章 50 获赞 139 访问量 2万+

猜你喜欢

转载自blog.csdn.net/diviner_s/article/details/105586904