二叉树的遍历

一、先定义二叉树的数据结构

typedef struct TreeNode *BinTree;

struct TreeNode
 {
     ElementType data;
     BinTree left;
     BinTree right;
 };

二、基于DFS的递归遍历
       1. 先序遍历(PreOrder)
void PreOrder(BinTree T)
{
	if(!T) return;
	Visit(T);
	PreOrder(T->left);
	PreOrder(T->right);
}

      2. 中序遍历(InOrder)
void InOrder(BinTree T)
{
	if(!T) return;
	InOrder(T->left);
	Visit(T);
	InOrder(T->right);
}

      3. 后序遍历(PostOrder)
void PostOrder(BinTree T)
{
	if(!T) return;
	InOrder(T->left);
	InOrder(T->right);
	Visit(T);
}

      Summarize: 这三种遍历过程,经过结点的路线是一样的,只是访问各结点的时机不同。

三、利用堆栈实现非递归遍历
       借助堆栈实现实际上就是模拟递归函数调用时的入栈和出栈过程,先序遍历是结点第一次入栈即访问,然后分别对该结点的左右子树遍历;中序遍历是当结点出栈时,表明刚完成对该结点左子树的访问,这时访问该结点。
      1. 先序非递归
          1) 遇到一个结点,访问后入栈,并遍历其左子树;
          2) 当左子树遍历完后,从栈顶弹出一个结点;
          3) 按该结点的右指针遍历其右子树;
          4) 当p为NULL且栈空时,整个遍历过程结束。
void PreOrder(BinTree T)
{
	stack<BinTree> S;
	BinTree p = T;

	while(p || !S.empty())
	{
		while(p){
			Visit(p);
			S.push(p);
			p = p->left;
		}
		if(!S.empty()){
			p = S.top();
			S.pop();
			p = p->right;
		}
	}
}

      2. 中序非递归
          同先序基本一样,不同之处在于访问结点的时机,是在结点出栈后访问。
void InOrder(BinTree T)
{
	stack<BinTree> S;
	BinTree p = T;

	while(p || !S.empty())
	{
		while(p){
			S.push(p);
			p = p->left;
		}
		if(!S.empty()){
			p = S.top();
			Visit(p);
			S.pop();
			p = p->right;
		}
	}
}

      3. 后序非递归
          与前两个非递归的过程不同,后序遍历必须在左右子树均访问后才访问根结点,关键是要确定什么时候右子树遍历结束。一种思路是在某一结点的左子树遍历完后将其再次入栈,等到再次出栈就说明其右子树已经遍历结束,这时候就可以访问该结点了。也就是说,在整个后序非递归过程中,每个结点出入栈两次,第一次出栈说明其左子树遍历完成,第二次出栈说明其右子树也遍历完成,而为了区分是第几次出栈,每个结点需要添加一个变量标记。
void postOrder(BinTree T)
{
    if(!T) return;

    stack<BinTree> S;
    BinTree p = T;
    while(p || !S.empty())
    {
        if(p){
            S.push(p); 
            p = p->left;
        }
        else{
            p = S.top();
            S.pop();  
            p->flag++;
            if(p->flag == 2){
                Visit(p);
                p = NULL;
            }
            else{
                S.push(p);
                p = p->right;
            }
        }
    }
}

四、基于BFS的层序遍历
       1. 层序遍历用队列实现,从根节点开始,首先将根节点入队,然后执行循环:结点出队并访问,左右结点入队,直到队列为空,形成按广度优先搜索的遍历方式。
       基本过程:
       1) 根节点入队;
       2) 从队列中出队一个结点;
       3) 访问该结点;
       4) 如果该结点左右子结点非空,依次入队;
       5) 队列为空,遍历结束。
void LevelOrder(BinTree T)
{
    if(!T) return;

    queue<BinTree> Q;
    BinTree p = T;
    Q.push(p);
    while(!Q.empty())
    {
        p = Q.front();
        Visit(p);
        Q.pop();

        if(p->left)
            Q.push(p->left);
        if(p->right)
            Q.push(p->right);
    }
}

     2. 有意思的是,基于层序遍历的思想也可以实现先序、中序和后序三种遍历。只要将队列改为栈,同时改变结点的的入栈顺序即可。
        1) 先序:入栈顺序为右结点再左结点。
void LevelPreOrder(BinTree T)
{
    if(!T) return;
    stack<BinTree> S;
    BinTree p = T;
    S.push(p);
    while(!S.empty())
    {
        p = S.top();
        Visit(p);
        S.pop();

        if(p->right)
            S.push(p->right);
        if(p->left)
            S.push(p->left);
    }
}

       2) 中序:为了知道左右子树什么时候遍历结束,结点需要出入栈两次,第一次出栈后在左右结点间再次入栈,第二次出栈时即可访问该结点。
           入栈顺序:右结点->当前结点->左结点
void LevelInOrder(BinTree T)
{
    if(!T) return;
    stack<BinTree> S;
    BinTree p = T;
    S.push(p);
    while(!S.empty())
    {
        p = S.top();
        p->flag++;
        S.pop();
        if(p->flag == 2){
            Visit(p);
        }
        else{
            if(p->right)
                S.push(p->right);
            S.push(p);
            if(p->left)
                S.push(p->left);
        }
    }
}

        3) 后序:与中序类似,结点第一次出栈后在左右结点之前再次入栈,第二次出栈后访问。入栈顺序:当前结点->右结点->左结点
void LevelPostOrder(BinTree T)
{
    if(!T) return;
    stack<BinTree> S;
    BinTree p = T;
    S.push(p);
    while(!S.empty())
    {
        p = S.top();
        p->flag++;
        S.pop();
        if(p->flag == 2){
            Visit(p);
        }
        else{
            S.push(p);
            if(p->right)
                S.push(p->right);
            if(p->left)
                S.push(p->left);
        }
    }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值