二叉树之非递归遍历

1、二叉树的遍历

为什么要有遍历操作:将线性结构-------->非线性结构;

将递归程序-------->非递归程序;

2、二叉树的三种递归遍历:

先序遍历:先访问根(父)结点,在访问左分支,最后访问右分支;

中序遍历:先访问左分支,在根结点,最后右分支;

后序遍历:先访问左分支,在访问右分支,最后访问根节点;

所有程序皆正确测试过,后面将给完整程序和测试程序,测试结果。

以下就是递归遍历,先序,中序,后序:

下面的都是在类外定义的函数,所以为模板函数:

//先序遍历
template<typename Type>
void BinTree<Type>::prevOrder(BinTreeNode<Type> *t)const{
    if(t == NULL){
        return;
    }else{
        cout<<t->data<<" ";
        prevOrder(t->leftChild);
        prevOrder(t->rightChild);
    }
}
//中序遍历
template<typename Type>
void BinTree<Type>::inOrder(BinTreeNode<Type> *t)const{
    if(t == NULL){
        return;
    }else{
        inOrder(t->leftChild);
        cout<<t->data<<" ";
        inOrder(t->rightChild);
    }
}
//后序遍历
template<typename Type>
void BinTree<Type>::endOrder(BinTreeNode<Type> *t)const{
    if(t == NULL){
        return;
    }else{
        endOrder(t->leftChild);
        endOrder(t->rightChild);
        cout<<t->data<<" ";
    }
}

3、二叉树的4种非递归遍历

(1)、深度优先用栈

先序的非递归遍历:栈先入后出,根结点入栈,栈不空,出栈访问,此时将右孩子入栈,在将左孩子入栈,栈不空,出栈访问,就是循环了;

代码如下:

template<typename Type>
void BinTree<Type>::prevOrder_1(BinTreeNode<Type>* t)const{
    stack<BinTreeNode<Type> *> st;  //栈里面放的是指向节点的指针
    BinTreeNode<Type> *tmp;

    if(t != NULL){   //根不为空
        st.push(t);  //根入栈
        while(!st.empty()){  //栈非空
            tmp = st.top();  //读栈顶元素
            st.pop();        //出栈
            cout<<tmp->data<<" ";  //访问
            if(tmp->rightChild){    //右孩子存在
                st.push(tmp->rightChild);  //入栈
            }
            if(tmp->leftChild){     //左孩子存在
                st.push(tmp->leftChild);  //入栈
            }
        }
    }
}

中序的非递归遍历:就是先把根及左分支一直压栈,栈不空,出栈访问,再看右孩子,有的话,压栈,结束条件想清楚就行。

代码如下:

template<typename Type>
void BinTree<Type>::inOrder_1(BinTreeNode<Type>* t)const{
    stack<BinTreeNode<Type> *> st;  //栈里面放的是指向节点的指针
    BinTreeNode<Type> *p = t;
                     //用的是do while()循环
    do{
        while(p != NULL){  //将根和左子树一直入栈
            st.push(p);
            p = p->leftChild;
        }
        if(!st.empty()){  //栈不空,
            p = st.top();  //读栈顶元素
            st.pop();      //出栈
            cout<<p->data<<" ";  //访问
            p = p->rightChild;   //此时往刚才栈顶元素的右孩子走;
        }             //中序遍历时,当root出栈时,此时栈空,没有p!=NULL的话,将出错。
    }while(p != NULL || !st.empty()); //为根的时候右边还要入栈。
}

后序的非递归遍历:思想就是要有一个标志,当为右边回来的时候才能访问根节点!!!

代码如下:

typedef enum{L, R}Tag;   //枚举定义新的类型
template<typename Type>  //定义一个类,为的是做标志
class stkNode{
public:
    stkNode(BinTreeNode<Type> *p = NULL) : ptr(p), tag(L){}
public:                  //数据成员为公有,便于访问
    BinTreeNode<Type> *ptr;  
    Tag                   tag; //L R
};
template<typename Type>
void BinTree<Type>::endOrder_1(BinTreeNode<Type>* t)const{
    stkNode<Type> n;
    stack<stkNode<Type>> st;  //此时栈中存放的是对象!
    BinTreeNode<Type> *p = t;
    
    do{
        while(p != NULL){  //不为空,一路向左入栈
            n.ptr = p;    //将指针给过去
            n.tar = L;    //记为左边入栈
            st.push(n);
            p = p->leftChild;
        }
        bool isRun = true;  //是否继续的标志
        while(isRun && !st.empty()){  
            n = st.top();  //读栈顶
            st.pop();     //出栈

            switch(n.tag){  //根据L和R选择
            case L:
                p = n.ptr; 
                n.tag = R;  //更改为R
                st.push(n);  //压入栈
                p = p->rightChild;  //看有没有右孩子,有的话,结束循环,要入栈的;
                isRun = false;  //特别重要,保证了右孩子的入栈!
                break;
            case R:
                cout<<n.ptr->data<<" ";
                break;
            }
        }
    }while(!st.empty());//不用p1=NULL,因为当栈空时,最后一个节点刚好被访问完成。
}

画图跟踪后序如下:

(2)、广度优先用队列

层次遍历:根结点入队列,队列非空,出队访问,在将左右孩子入队,非空,访问,构成循环;

代码如下:

template<typename Type>
void BinTree<Type>::levelOrder(BinTreeNode<Type>* t)const{
    queue<BinTreeNode<Type> *> qu;  //队列里面放的是指向节点的指针
    BinTreeNode<Type> *p;

    if(t != NULL){ //根非空
        qu.push(t);  //根入队
        while(!qu.empty()){  //队列非空
            p = qu.front();  //读队首
            qu.pop();        //出队
            cout<<p->data<<" "; //访问
            if(p->leftChild){  //左孩子存在
                qu.push(p->leftChild); //入队
            }
            if(p->rightChild){   //右孩子存在
                qu.push(p->rightChild);  //入队
            }
        }
    }
}
时间: 2024-11-10 00:45:36

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

二叉树的非递归遍历--京东2015笔试回忆

题目回忆: C/C++研发试卷:偏重于数据结构的考察,编程题有2题+1题附加题: 1.输入整数n,求m,m>9,m中各个数位的乘积=n的最小整数;如n=36,m=49; 2.二叉树前序遍历的非递归实现(本文的总结) 3.求第n个数,这个序列满足(2^i)*(3^j)*(5^k),前7个为:2,3,4,5,6,8,10 .... 小题有基本的数据结构.程序运行结果.SQL题目. 4.删除表格用DROP命令,死锁产生的条件: 4.1互斥使用(资源独占) 一个资源每次只能给一个进程使用 4.2.不可强

二叉树的非递归遍历及算法分析

二叉树介绍 二叉树是一类重要的数据结构.二叉树常被用于实现二叉查找树和二叉堆.通常子树被称作"左子树"(left subtree)和"右子树"(right subtree). 一种二叉树结点定义: struct bit_node { chardata; structbit_node *lchild,*rchild; }; 遍历是对树的一种最基本的运算,所谓遍历二叉树,就是按一定的规则和顺序走遍二叉树的所有结点,使每一个结点都被访问一次,而且只被访问一次.由于二叉树是

好久没更新了,哪里不对!更新二叉树的非递归遍历

#include <iostream> #include <stack> using namespace std; typedef struct Node { Node* lchild; Node* rchild; int data; }BNode,BTree; void visit(Node*); void inorder(BTree *root) { BNode * p = root; stack<Node*> s; if(p||!s.empty()) { s.pu

二叉树的非递归遍历(转)

原文地址 二叉树的非递归遍历 二叉树是一种非常重要的数据结构,很多其它数据结构都是基于二叉树的基础演变而来的.对于二叉树,有前序.中序以及后序三种遍历方法.因为树的定义本身就是递归定义,因此采用递归的方法去实现树的三种遍历不仅容易理解而且代码很简洁.而对于树的遍历若采用非递归的方法,就要采用栈去模拟实现.在三种遍历中,前序和中序遍历的非递归算法都很容易实现,非递归后序遍历实现起来相对来说要难一点. 一.前序遍历 前序遍历按照“根结点-左孩子-右孩子”的顺序进行访问. 1.递归实现 void pr

二叉树的非递归遍历C语言实现

腾讯面试中被问到二叉树的非递归遍历实现,当时记得不太清楚,回来专门复习了非递归的实现,整理代码如下: //采用二叉链表存储方式的二叉树,非递归中序遍历C语言实现代码 #include<stdio.h> #include <malloc.h> //函数结果状态代码 #define TRUE 1 #define FALSE 0 #define OK 1 #define ERROR 0 #define INFEASIBLE -1 #define OVERFLOW -2 //Status是

(转)二叉树的非递归遍历

转自: 二叉树的非递归遍历 http://www.cnblogs.com/dolphin0520/archive/2011/08/25/2153720.html 二叉树的非递归遍历 二叉树是一种非常重要的数据结构,很多其它数据结构都是基于二叉树的基础演变而来的.对于二叉树,有前序.中序以及后序三种遍历方法.因为树的定义本身就是递归定义,因此采用递归的方法去实现树的三种遍历不仅容易理解而且代码很简洁.而对于树的遍历若采用非递归的方法,就要采用栈去模拟实现.在三种遍历中,前序和中序遍历的非递归算法都

二叉树的非递归遍历(转载)

二叉树的非递归遍历 二叉树是一种非常重要的数据结构,很多其它数据结构都是基于二叉树的基础演变而来的.对于二叉树,有前序.中序以及后序三种遍历方法.因为树的定义本身就是递归定义,因此采用递归的方法去实现树的三种遍历不仅容易理解而且代码很简洁.而对于树的遍历若采用非递归的方法,就要采用栈去模拟实现.在三种遍历中,前序和中序遍历的非递归算法都很容易实现,非递归后序遍历实现起来相对来说要难一点. 一.前序遍历 前序遍历按照“根结点-左孩子-右孩子”的顺序进行访问. 1.递归实现 void preOrde

二叉树的非递归遍历(先序、中序、后序和层序遍历)

[前文] 二叉树的非递归遍历有 先序遍历.中序遍历 .后续遍历 和 层序遍历. 非递归算法实现的基本思路:使用堆栈.而层序遍历的实现:使用队列. 如下图所示的二叉树: 前序遍历顺序为:ABCDE (先访问根节点,然后先序遍历其左子树,最后先序遍历其右子树) 中序遍历顺序为:CBDAE (先中序遍历其左子树,然后访问很节点,最后中序遍历其右子树) 后续遍历顺序为:CDBEA (先后序遍历其左子树,然后后续其右子树,最后访问根节点) 层序遍历顺序为:ABECD (由上至下.从左到右遍历二叉树) [准

[算法]二叉树的非递归遍历算法

1.二叉树的非递归中序遍历算法 二叉树的中序遍历方法是:左中右,因此一开始会顺着根节点的左孩子一直往下(这点和先序遍历一样,这也是二者前面部分代码很相似的原因),到最后一个左孩子时尝试把它的右孩子塞进栈内,然后顺着它的的左孩子而下,直到不能访问为止.利用的栈FILO的特性,对每个节点都进行顺左孩子而下即可. 上代码: 1 void inOrder(TreeNode* root,vector<int>& inOrder) 2 { 3 stack<TreeNode*>st; 4