非递归二叉树的遍历

我们都知道,对二叉树进行递归遍历非常简单,但递归算法需要额外的栈机制来存储每次递归的值。既然递归算法内部使用栈实现的,那么我们也可以借助于栈来实现二叉树的非递归遍历。下面我们将讲解利用非递归实现二叉树的前序、中序和后序遍历。

1、非递归二叉树前序遍历:

我们知道,二叉树的前序遍历对节点的访问顺序是根节点、左子节点然后右自节点。根据其访问顺序我们可以很容易用栈来实现。具体实现思路如下:

1、遍历根节点的左子树,将每个节点的左子节点存入栈中,并在访问遍历的节点。

2、当遇到左子节点为空时,从栈中取出该节点的父节点,遍历其父节点的右子节点。

3、若该节点无右子节点,则将其从栈中删除,取该节点的父节点,并访问其右节点。

4、若该节点有右子节点,则将其右子节点当做根节点,重复1.

具体实现代码如下:

 1 void preorderWithOutRecursion(BinaryTreeNode *proot)
 2 {
 3     BinaryTreeNode *p = proot;
 4     BinaryTreeNode *tmp = NULL;
 5     stack<BinaryTreeNode *> mystack;
 6     if(proot == NULL)
 7     {
 8         return;
 9     }
10
11     while(p)
12     {
13         mystack.push(p);
14         cout << p->val << ‘\t‘;      //访问遍历的节点
15         p = p->pleft;
16     }
17     while(!mystack.empty())
18     {
19         p = mystack.top();
20         mystack.pop();
21         p = p->pright;
22         while(p)
23         {
24             mystack.push(p);         //当右节点存在时,重复前面步骤
25             cout << p->val << ‘\t‘;
26             p = p->pleft;
27         }
28     }
29 }

2、非递归二叉树中序遍历:

二叉树的中序遍历基本思想是先遍历根节点左子树,然后访问根节点,最后遍历根节点的右子树。同理,我们根据上面前序遍历的经验可以完成中序非递归遍历:

1、遍历根节点的左子树,将其存入栈中。

2、当遍历完左子树后,访问根节点。

3、遍历根节点右子树。

具体代码如下:

 1 void inorderWithOutRecursion(BinaryTreeNode *proot)
 2 {
 3     BinaryTreeNode *p = proot;
 4     if(p == NULL)
 5     {
 6         return;
 7     }
 8     stack<BinaryTreeNode *> mystack;
 9     while(p)
10     {
11         mystack.push(p);    //遍历左子树
12         p = p->pleft;
13     }
14
15     while(!mystack.empty())
16     {
17         p = mystack.top();
18         mystack.pop();
19         cout << p->val << ‘\t‘;        //访问根节点
20         p = p->pright;        //遍历右子树
21         while(p)
22         {
23             mystack.push(p);
24             p = p->pleft;
25         }
26     }
27 }

3、非递归二叉树后续遍历

二叉树的后续遍历时先遍历左子树,然后遍历右子树,最后访问根节点。那么利用非递归方式对二叉树进行遍历的难点在于如何确定我们是否遍历过根节点的右子树。我们从二叉树的前序中序遍历的代码中可以看到,当我们将节点从栈中取出后直接将其pop()掉,因为前序遍历中我们存入该节点时已经对其进行访问,而中序遍历中我们取出该节点时对其访问。但由于后续遍历时最后访问跟节点的,所以我们只有遍历完根节点的左右子树后才能将其从栈中pop(),也就是我们需要一个标志来标志是否访问过该节点的右子树(无论是前序、中序还是后续遍历,我们的while循环都是遍历左子树,所以当节点存入栈中时已经遍历过其左子树)。这样我们就需要引入一个新的结构。

1、遍历根节点的左子树,将其存入栈中。

2、判断该节点是否遍历过右子树,若没有遍历过则遍历其右子树

3、若遍历过右子树,则访问该节点,并将其从栈中删除

具体代码如下:

struct newNode        //新节点,两个public数据成员,一个节点指针,另一个bool值判断其右节点是否被遍历过
{
    BinaryTreeNode *pNode;
    bool tag;
    newNode(){    //默认构造函数
    }
    newNode(BinaryTreeNode *p, bool Tag):pNode(p), tag(Tag){    //带参数构造函数
    }
};

void postorderWithOutRecursion(BinaryTreeNode *proot)
{
    BinaryTreeNode *p = proot;
    if(p == NULL)
    {
        return;
    }

    newNode *tmp;

    stack<newNode*> mystack;
    while(p)                         //保存左节点
    {

        mystack.push(new newNode(p, false));  //遍历左子树,里面存的是新节点,初始tag值为false
        p = p->pleft;
    }

    while(!mystack.empty())
    {
        tmp = mystack.top();

        if(tmp->pNode->pright && !tmp->tag)       //查看该节点是否存在右节点及该节点是否被遍历过
        {
            tmp->tag = true;                //遍历其右子树,并将tag设为true
            p = tmp->pNode->pright;             //遍历右子树

            while(p)
            {
                mystack.push(new newNode(p, false));
                p = p->pleft;
            }
        }
        else        //如果该节点不存在右子树或者该节点右子树已经访问过则访问该节点
        {
            cout << tmp->pNode->val << ‘\t‘;
            mystack.pop();
        }
    }
}

对二叉树的非递归遍历主要是借助于栈来实现的,无论是前序中序还是后序遍历都是先遍历根节点的左子树,然后遍历右子树。唯一不同的是访问根节点的时机。前序遍历是先访问根节点再遍历子树,中序遍历是先遍历左子树再访问根节点,后序遍历是最后访问跟节点。相比于前序和中序遍历,后序遍历稍微麻烦点,因为我们需要设置标志位来标志是否遍历过其右节点。

时间: 2024-10-24 08:46:35

非递归二叉树的遍历的相关文章

学习日志---非递归二叉树游标遍历(前中后层序)

实现: //二叉树类 public class MyBiTree { private MyBiTreeNode  root;//根节点 MyBiTree() { this.root = null; } MyBiTree(Object data,MyBiTree left,MyBiTree right) { MyBiTreeNode l,r; if(left==null) { l = null; } else {    l=left.root;  } if(right==null) { r = n

非递归的方法遍历二叉树

//非递归遍历一棵树 需要借助栈 #include<stdio.h> #include<stdlib.h> struct Tree { int nValue; Tree *pLeft; Tree *pRight; }; struct Stack { Tree *root; Stack *pNext; }; Stack *pStack = NULL; void push(Tree *root) { Stack *temp = (Stack*)malloc(sizeof(Stack))

完全二叉树的链式存储结构的转化 &amp; 非递归中序遍历二叉树

1 /* 2 * 二叉树 3 * 4 * (将完全二叉树的数组形式改为链表形式) 5 * 6 * 1 7 * 2 3 8 * 4 5 6 7 9 * 8 10 * 11 */ 12 #include <iostream> 13 #define MAX 10 14 using namespace std; 15 16 typedef struct btnode{ 17 int data; 18 struct btnode * lchild; 19 struct btnode * rchild;

【LeetCode-面试算法经典-Java实现】【145-Binary Tree Postorder Traversal(二叉树非递归后序遍历)】

[145-Binary Tree Postorder Traversal(二叉树非递归后序遍历)] [LeetCode-面试算法经典-Java实现][所有题目目录索引] 原题 Given a binary tree, return the postorder traversal of its nodes' values. For example: Given binary tree {1,#,2,3}, 1 2 / 3 return [3,2,1]. Note: Recursive soluti

每天刷个算法题20160518:非递归二叉树遍历

版权所有.所有权利保留. 欢迎转载,转载时请注明出处: http://blog.csdn.net/xiaofei_it/article/details/51502254 为了防止思维僵化,每天刷个算法题.已经刷了几天了,现在贴点代码. 2002年我初中二年级,开始学习BASIC语言.2004年中考之后,开始参加NOIP,系统学习算法.一直非常喜欢算法,但工作后几乎不再碰这些东西.现在准备重新捡起来. 我已经建了一个开源项目,每天的题目都在里面: https://github.com/Xiaofe

非递归后序遍历二叉树(1)

1 void postOrder3(BinTree *root) //非递归后序遍历 2 { 3 stack<BinTree*> s; 4 BinTree *cur; //当前结点 5 BinTree *pre=NULL; //前一次访问的结点 6 s.push(root); 7 while(!s.empty()) 8 { 9 cur=s.top(); 10 if((cur->lchild==NULL&&cur->rchild==NULL)|| 11 (pre!=N

借树的遍历一题,尝试非递归三种遍历

#include <iostream> #include <cstdio> #include <cstdlib> #include <stack> using namespace std; int z[30],h[30]; class Tree { public: int data; Tree *lchild; Tree *rchild; Tree() { lchild=NULL; rchild=NULL; } }*root; Tree *CreatNode

面试之路(11)-java递归和非递归二叉树前序中序后序遍历

二叉树的遍历 对于二叉树来讲最主要.最基本的运算是遍历. 遍历二叉树 是指以一定的次序访问二叉树中的每个结点.所谓 访问结点 是指对结点进行各种操作的简称.例如,查询结点数据域的内容,或输出它的值,或找出结点位置,或是执行对结点的其他操作.遍历二叉树的过程实质是把二叉树的结点进行线性排列的过程.假设遍历二叉树时访问结点的操作就是输出结点数据域的值,那么遍历的结果得到一个线性序列. 从二叉树的递归定义可知,一棵非空的二叉树由根结点及左.右子树这三个基本部分组成.因此,在任一给定结点上,可以按某种次

非递归二叉树遍历

算法导论:10.4-3 给定一个 n 二叉树结点,写一个 O(n) 非递归处理时间,树中的每个节点keyword出口.堆栈可以用作辅助数据结构. 堆栈实现参考这里. #ifndef _BINARY_TREE_USE_STACK_H_ #define _BINARY_TREE_USE_STACK_H_ /************************************************** 算法导论:10.4-3 给定一个 n 结点的二叉树,写出一个 O(n) 时间的非递归过程.将该