二叉树非递归深度优先DFS算法

二叉树可以递归遍历,实现简洁,易于理解。这里介绍二叉树的非递归的三种遍历,以下图二叉树为例讲解。

先前声明

#define ELEMENTTYPE char
typedef struct node* pnode;
typedef struct node* PBintree;

struct node{
    ELEMENTTYPE n;
    pnode lchild;
    pnode rchild;
};

先序遍历非递归实现

上图的先序遍历顺序为:ABDECF

思路:

1)从二叉树的根结点开始,将其压入栈

2)当栈不为空时,取栈顶元素作为当前树(左子树或右子树),赋值给p并弹出;否则,遍历结束

3)如果p不为空,访问p并将p的右子树、左子树(可能为空树)依次(优先访问左子树)压入栈中

4)返回 2)

 

C++实现:

void pre_order(PBintree t)
{
    if(t==NULL) return;
    stack<pnode> s;
    pnode p = t;
    s.push(p);
    while(!s.empty()){
        p=s.top();
        s.pop();
        if(p){
            cout<<p->n;
            s.push(p->rchild);
            s.push(p->lchild);
        }
    }
}

 

中序遍历非递归算法

上图的中序遍历顺序为:DBEAFC

 

思路:

1)从二叉树的根结点开始,将其赋值给p作为当前结点

2)不断将p及p的左子树压入栈,直到p为空

3)取栈顶元素并弹出,赋值给p作为当前结点,访问p

4)将p的右子树赋值给p作为当前结点

5)如果栈不为空(遍历结束) 或者 p不为空,返回2)

 

C++实现: 

void in_order(PBintree t)
{
    if(t==NULL) return;
    stack<pnode> s;
    pnode p = t;
    while(p || !s.empty()){
        while(p){
            s.push(p);
            p=p->lchild;
        }
        p=s.top();
        s.pop();
        cout<<p->n;
        p=p->rchild;
    }
}

 

后序遍历非递归算法

上图的后序遍历顺序为:DEBFCA

遍历方法:

首先由该二叉树找到其左子树,遍历其左子树,遍历完返回到这颗二叉树;

然后由该二叉树找到其右子树,遍历其右子树,遍历完再次返回这颗二叉树,此时才能访问该二叉树的根结点。

 

思路:

从上面可分析出,在后序遍历二叉树时,一棵二叉树可能要进、出栈各两次,只有它第二次出栈后才能访问其根结点。因此,为了区分同一颗二叉树的两次出栈,需要给各结点增加一个标示量tag,用来记录是第一次还是第二次出栈。如果是第一次,先不访问二叉树的根结点;如果是第二次,则访问。

可以改进思路,为了节省空间,取消标示量tag;为了节省时间,每颗二叉树只进栈和出栈一次。为此,需要在二叉树出栈时增加判断:如果是栈顶二叉树的左子树回来,直接遍历右子树。如果是从栈顶二叉树的右子树回来,直接执行出栈,并访问根结点。算法步骤:

 

1)从二叉树的根结点开始,将其置为当前子树p

2)将p压入栈,如果p有左子树,则将p的左子树置为当前p,将p压入栈

3)如果p没有左子树,但是有右子树,则将p的右子树置为当前p,将p压入栈,重复2),直到p没有左子树也没有右子树

4)取栈顶元素并弹出,置为当前p,访问p

5)如果栈不为空,而且此时栈顶元素的左子树就是p(从左子树退回),则进入栈顶元素右子树;如果此时栈顶元素的右子树不 是p(从右子树返回),则返回 4),直到栈为空而且p为空(遍历结束)

 

C++实现:

void aft_order(PBintree t){
    stack<pnode> s;
    PBintree p = t;
    while(p||!s.empty()){
        while(p){
            s.push(p);
            p=p->lchild?p->lchild:p->rchild;
        }                                        //循环到当前处理的点
        p=s.top();                               //访问栈顶二叉树的根
        s.pop();
        cout<<p->n;
        if(!s.empty() && p==(s.top())->lchild)   //栈不为空,且从左子树退回
            p=(s.top())->rchild;                 //直接进入栈顶元素的右子树
        else
            p=NULL;                              //从右子树回来,退到上一层处理
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值