#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();
}
三叉链表的创健以及前序+中序构造二叉树+二叉树前中后序的非递归遍历
最新推荐文章于 2022-02-09 00:20:24 发布