二叉树的遍历 -- 非递归实现方式

相关头文件

#include<iostream>
#include<queue>
#include<stack>
#include<vector>
#include<unordered_map>
using namespace std;
unordered_map<int, int> l, r;

这里并没有专门用一个结构体struct或者类class来保存一个节点的信息, 这里简单的用C++用哈希表实现的unordered_map来快速找到每个节点的左右子树节点。

前序遍历

// 前序遍历
auto pre(int root)
{
	if(!root) return;
    stack<int> st;
    st.push(root);
    while(st.size())
    {
        int node = st.top(); st.pop();
        cout << node << " ";                 // 根节点直接输出
        if(r[node]) st.push(r[node]);        // 右节点先入栈/左节点再入栈。 因为出栈顺序是反的
        if(l[node]) st.push(l[node]);
    }
}

中序遍历

auto in(int root)
{
	if(!root) return;
    stack<int> st;
    while(root) {st.push(root); root = l[root];}         
    while(st.size())
    {
        int node = st.top(); st.pop();      
        cout << node << " ";
        if(r[node]) 
        {
            node = r[node];
            while(node) {st.push(node); node = l[node];} 
        }
    }
}

后序遍历 — (一个栈 + 标志位)

代码跟上面的中序遍历很像, 相比于上面多了个标志位判断, 若本次遍历的节点存在右节点,由于右节点要先遍历,故此时遍历的节点不能出栈,先做个标记,表示这个节点已经第一次给遍历过,下次再遍历到说明其右子树也遍历完,所以可以直接输出, 此时应该先遍历完右子树, 故此时将右子树节点及其它左子树节点依次入栈.

auto post_1(int root)
{
	if(!root) return;
    stack<int> st; 
    int pre = -1;      // pre保存上次访问的结点是哪一个结点. 

    while(root) { st.push(root); root = l[root];}
    while(st.size())
    {
        int node = st.top();
        if(r[node] && r[node] != pre)  // 若当前结点存在右子树,且右子树未被遍历完毕
        {
            node = r[node];
            while(node) {st.push(node); node = l[node];}
        }
        else
        {
            pre = node;              // 保存当前访问的结点. 
            cout << node << " "; st.pop();
        }
    }
}

使用了unordered_map存放标志位信息。

auto post_1_2(int root)
{
	if(!root) return;
    stack<int> st; 
    unordered_map<int,bool> m;

    while(root) { st.push(root); root = l[root];}
    while(st.size())
    {
        int node = st.top();
        if(!m[node] && r[node])
        {
            m[node] = true;
            node = r[node];
            while(node) {st.push(node); node = l[node];}
        }
        else
        {
            cout << node << " "; st.pop();
        }
    }
}

后序遍历 — 双栈实现

auto post_2(int root)
{
	if(!root) return;
    stack<int> st1, st2;
    st1.push(root);
    
    while(st1.size())
    {
        int node = st1.top();st1.pop();
        st2.push(node);                // 根节点先入st2栈,说明其在最后面才会遍历
        if(l[node]) st1.push(l[node]); // 左子树节点先入st1栈,右子树节点再入st1栈, 这样右子树会先入栈st2, 左子树再入st2;     
        if(r[node]) st1.push(r[node]);
    }
    while(st2.size()) {cout << st2.top() << " "; st2.pop();} 
}

层序遍历 — 队列实现

(1) 从上到下, 从左到右


// 本质就是bfs ----------------- 宽度优先搜索算法 
auto level_traversal(int root)
{
	if(!root) return;
    queue<int> q;
    q.push(root);
    while(q.size())
    {
        int node = q.front();q.pop();
        cout << node << " ";
        if(l[node]) q.push(l[node]);
        if(r[node]) q.push(r[node]);
    }
}

(2) 从上到下, 从右到左

auto level_traversal(int root)
{
	if(!root) return;
    queue<int> q;
    q.push(root);
    while(q.size())
    {
        int cursize = q.size();
        for(int i = 0; i < cursize; ++i)
        {
            int node = q.front(); q.pop();
            cout << node << " "; 
            if(r[node]) q.push(r[node]);
            if(l[node]) q.push(l[node]);
        }
    }
}

(3) 从下到上,从左到右

// 从下往上遍历 
auto level_traversal(int root)
{
    vector<vector<int>> res; vector<int> vec; 
	if(!root) return;
    queue<int> q;
    q.push(root);
    while(q.size())
    {
        vec.clear();
        int cursize = q.size();
        for(int i = 0; i < cursize; ++i)
        {
            int node = q.front(); q.pop();
            vec.push_back(node); 
            if(l[node]) q.push(l[node]);
            if(r[node]) q.push(r[node]);
        }
        res.push_back(vec);
    }
    
    while(res.size()) 
    {
        for(auto val : res.back()) cout << val << " ";
        res.pop_back();  
    }
}

(4) 从下到上,从右到左

// 这就相当于将(1)情况的队列的输出入栈处理了
auto level_traversal(int root)
{
	if(!root) return;
    queue<int> q;
    stack<int> st;
    q.push(root);
    while(q.size())
    {
        int node = q.front();q.pop();
        st.push(node);
        if(l[node]) q.push(l[node]);
        if(r[node]) q.push(r[node]);
    }
    
    while(st.size())
    {
        cout << st.top() << " ";
        st.pop(); 
    }
}

main函数测试

auto main() -> int
{
    int root = 1; 
    l[1] = 2, r[1] = 3;  
    l[2] = 4, r[2] = 5;  
    l[3] = 6, r[3] = 7;  


    cout << "前序遍历: ";  pre(root);             cout << endl;        
    cout << "层序遍历: ";  level_traversal(root); cout << endl;
    cout << "中序遍历: ";  in(root);              cout << endl;
    cout << "后序遍历: ";  post_1(root);          cout << endl;
    cout << "后序遍历: ";  post_2(root);          cout << endl;

    cout << endl;  
    return 0; 
}

main函数所建立的树
在这里插入图片描述
打印测试结果
在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值