二叉树非递归遍历的实现——学习笔记

二叉树非递归遍历的实现——学习笔记

前言

学过二叉树的同学一定对二叉树的三种遍历方式印象深刻。前序遍历,中序遍历,后序遍历,用递归来实现不仅代码简单而且结构优美,而且令人心情舒畅。那么假如我们不用递归,用循环来实现又如何呢?一起来看看。

结构体

这里定义最简单的树结构

struct Tree{
    int val;
    Tree* left;
    Tree* right;
};

前序遍历

先看看递归实现,很简单的

//前序遍历
void PrintfTree(Tree* node){
    if(node!=NULL){
        printf("%d ",node->val);
        PrintfTree(node->left);
        PrintfTree(node->right);
    }
}

如果不用递归,我们需要借组栈来实现:

//前序遍历非递归遍历
void PrintfTree(Tree* head){
    Tree* p=head;
    stack<Tree*> s;//没学过stack的朋友可自行搜索用法

    while (p!=NULL||!s.empty()) {
        //先往left节点查找,直到节点为NULL停止,同时将遇到的每个节点都压入栈中
        //压入栈的节点在后面还要查找其right节点
        if (p!=NULL) {
            //前序遍历的特点,先遇到的节点先输出
            printf("%d ",p->val);
            s.push(p);
            p=p->left;
        }else{
            //left节点都搜索完了,转向right节点
            p=s.top()->right;
            s.pop();
        }
    }
}

其实也不难嘛,对吧。

中序遍历

递归实现

//中序遍历
void PrintfTree(Tree* node){
    if(node!=NULL){
        PrintfTree(node->left);
        printf("%d ",node->val);
        PrintfTree(node->right);
    }
}

循环实现,中序遍历和前序遍历很像,来看看:

//中序遍历非递归遍历
void PrintfTree(Tree* head){
    Tree* p=head;
    stack<Tree*> s;

    while (p!=NULL||!s.empty()) {
        //先往left节点搜索,直到节点为NULL停止,同时将遇到的每个节点都压入栈中
        //压入栈的节点在后面还要查找其right节点
        if (p!=NULL) {
            s.push(p);
            p=p->left;
        }else{
            //中序遍历,也就是这里和前序遍历不一致
            //此时是栈顶的值先输出
            printf("%d ",s.top()->val);
            //left节点都搜索完了,转向right节点
            p=s.top()->right;
            s.pop();
        }
    }
}

后序遍历

递归实现

//后序遍历
void PrintfTree(Tree* node){
    if(node!=NULL){
        PrintfTree(node->left);
        PrintfTree(node->right);
        printf("%d ",node->val);
    }
}

后序遍历有点不太一样,要稍微难一点:

//后序遍历
void PrintfTree2(struct Tree* head){
    struct Tree* p=head;
    stack<Tree*> s;
    stack<bool> u;//加标志位,false代表未遍历,true代表已遍历
    
    while (p!=NULL||!s.empty()) {
        if(p!=NULL){
            s.push(p);
            u.push(false);
            //先搜索左子节点
            p=p->left;
        }else{
            //判断是否有右子节点,且该节点是否已遍历。
            //是则搜索右节点,把当前节点标志设置为已遍历
            //否则打印数值并从栈中删除
            if(s.top()->right!=NULL&&!u.top()){
                p=s.top()->right;
                u.pop();
                u.push(true);
            }else{
                printf("%d ",s.top()->val);
                s.pop();
                u.pop();
            }
        }
    }
}

总结

前序遍历、中序遍历的实现还是比较容易理解的,不过后序遍历要稍微多绕一个弯。搞明白以后其实还是蛮简单的。代码作为参考,说的不清楚的地方,希望各位自己多思考或者直接在评论区提问。

发布了63 篇原创文章 · 获赞 73 · 访问量 7万+

猜你喜欢

转载自blog.csdn.net/jjwwwww/article/details/83422106
今日推荐