三叉链表的创健以及前序+中序构造二叉树+二叉树前中后序的非递归遍历

#include <bits/stdc++.h>
using namespace std;
struct node
{
    char val;
    node *l, *r, *parent;
};
class tree
{
private:
    node *root;
    node *pre = nullptr;
    node *create() // 创建三叉链表
    {
        char ch; //按照前序遍历输入 需要#来标记
        cin >> ch;
        node *bt;
        if (ch == '#')
        {
            bt = nullptr;
            return bt;
        }
        bt = new node;
        bt->val = ch;
        bt->parent = pre;
        pre = bt;
        bt->l = create(); //构造每个子树之前一定要重新修改pre
        pre = bt;
        bt->r = create();
        return bt;
    }
    void del(node *bt)
    {
        if (bt == nullptr)
            return;
        del(bt->l);
        del(bt->r);
        delete bt;
    }
    void preoder(node *bt)
    {
        if (bt == nullptr)
            return;
        cout << bt->val << " ";
        preoder(bt->l);
        preoder(bt->r);
    }

public:
    tree()
    {
        root = create();
    }
    ~tree()
    {
        del(root);
    }
    void preoder()
    {
        preoder(root);
    }
};
/*前序遍历顺序为根左右。中序遍历结果为左根右。前序遍历结果与中序遍历结果长度一致。
前序遍历首个为根,找到该根在中序遍历结果中的位置。就可以把树分为左子树与右子树。这样递归调用该函数,
先访问左子树,再访问右子树,最后输出根即可。*/
struct elet
{
   node *pr;
   int flag;
};
struct ercha
{
    node *root;
    string houxv = "";
    void make(string in, string pre)
    {
        root = create(in, pre);
    }
    node *create(string in, string pre) // 这种的不需要#号标志 由中序和前序生成二叉树
    {
        int n = in.length();
        node *bt;
        if (n == 0)
        {
            bt = nullptr;
            return bt;
        }
        bt = new node;
        char rot;
        rot = pre[0];
        bt->val = rot;
        int i;  
        for (i = 0; i < n; i++)
        {
            if (rot == in[i])
                break;
        }
        bt->l = create(in.substr(0, i), pre.substr(1, i)); // 注意i是从开始位置后向后的截取大小  begin到begin+i-1;
        bt->r = create(in.substr(i + 1, n - i - 1), pre.substr(i + 1, n - i - 1));   
        cout << rot << " ";   
        houxv += rot;
        return bt;
    }
    void houxvoder(node *bt)
    {
        if (bt == nullptr)
        {
            return;
        }
        houxvoder(bt->l);
        houxvoder(bt->r);
        cout << bt->val <<" ";
    }
    void hou_xv_oder()
    {
        houxvoder(root);
    }
    node *st[1005];//  非递归遍历 建立栈
    int top = -1;
    void preoder()
    {
        node *bt=root;
        while (bt != nullptr ||top != -1)
        {
            while (bt != nullptr)
            {
                cout << bt->val << " ";
                st[++top] = bt;
                bt = bt->l;
            }
            if (top != -1)
            {
                bt=st[top--];
                bt=bt->r;
            }
        }
    }
    void inoder()
    {
       node *bt=root;
       while(bt!=nullptr||top!=-1)
       {
           while(bt!=nullptr)
           {
               st[++top]=bt;
               bt=bt->l;
           }
           if(top!=-1)
           {
               bt=st[top--];
               cout<<bt->val<<" ";
               bt=bt->r;
           }
       }
    }
    //非递归的后续主要有三种写法  flag标记右子树是否被输出和  pre 表示已经被输出的元素来跟随 以判断一个节点的右子树是否被输出
    // 第三种是设立两个站 
    void houoder()//非递归后序遍历 pre标记节点的右子树是否被输出的写法 左右根 右孩子出后才能出该节点
    {
        node *bt=root;
        node *pre;
        while(bt!=nullptr||top!=-1)
        {
            while(bt!=nullptr)
            {
                st[++top]=bt;
                bt=bt->l;
            }
            if(top!=-1)
            {
                node *ti=st[top];
                if(ti->r==nullptr||ti->r==pre)//pre标记已被输出的元素  若右子树被输出 则输出该节点
                {
                    cout<<ti->val<<" "; 
                    pre=ti;
                    top--;
                }
                else//如果右子树没有被访问过,则访问该元素的右子树。 
                {
                    bt=st[top]->r;
                }
            }
        }
    }
    //  flag标记的写法 
      void houxv2()
    {
        node *bt=root;
        stack<elet>st;
        while(bt!=nullptr||!st.empty())
        {
            while(bt!=nullptr)
            {
                st.push({bt,1});
                bt=bt->l;
            }
            while(!st.empty()&&st.top().flag==2)
            {
                cout<<st.top().pr->val<<endl;
                st.pop();
            }
            if(!st.empty())
            {
                st.top().flag=2;
                bt=st.top().pr->r;
            }
            else bt=nullptr;//确保在栈空时第一时间结束 
        }
    }
    //设立两个站的写法   
    void hou()
    {
        stack<pair<node*,char> >res;
        stack<pair<node*,char> >help;
        help.push({root,(root->val)});
        pair<node*,char>tmp;
        while(!help.empty())
        {
           tmp=help.top();
           help.pop();
           res.push(tmp);
           if(tmp.first->l!=nullptr)
           {
               help.push({tmp.first->l,tmp.first->l->val});
           }
           if(tmp.first->r!=nullptr)
           {
               help.push({tmp.first->r,tmp.first->r->val});
           }
        }
        while(!res.empty())
        {
            cout<<res.top().second<<endl;
            res.pop();
        }
    }
    void cengxv()
    {
        queue<node*>q;
        node *bt=root;
        q.push(bt);
        while(!q.empty())
        {
            cout<<q.front()->val<<" ";
            if(q.front()->l!=nullptr)
            {
                q.push(q.front()->l);
            }
            if(q.front()->r!=nullptr)
            {
                q.push(q.front()->r);
            }
            q.pop();
        }
    }
};
int main()
{
    // string s;
    //cin>>s;
    // cout<<s.substr(4,1);
    string in, pre;
    cin >> in;
    cin >> pre;
    ercha o;
    
    o.make(in, pre);
    cout << endl;
   
    o.hou();
    cout<<endl;

    o.houxv2();
    cout<<endl;
    
    o.houoder();
    cout<<endl;
    
    o.hou_xv_oder();
    cout<<endl;
   
    o.preoder();
    cout<<endl;
    
    o.houoder();
    cout<<endl;
    
    o.cengxv();
    cout<<endl;
    
    tree tr;
    tr.preoder();
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值