二叉树继续由前序得到层序遍历
接上一篇:
二叉树由后序(LRD)和中序(LDR)得到前序(DLR)
程序运行
题目思路和源代码
/*给定一棵二叉树的后序遍历和中序遍历,
请你输出其层序遍历的序列。这里假设键值
都是互不相等的正整数。
输出格式:
在一行中输出该树的层序遍历的序列。数字间以1个空格分隔,行首尾不得有多余空格。
输入样例:
7
2315764 后序
1234567 中序
输出样例:
4163572 层序
*/
/*
DCBHKGFEA 后序
BDCAEHGKF 中序
ABCDEFGHK 前序
ABECFDGHK 层序
思路:根据后序找根节点->分割中序->在分割出来的中序里继续找根节点(这样得到前序,再把前序按照层数归类,就是层序).............
*/
#include<iostream>
#include<string>
using namespace std;
struct Node
{
char _ch;//某个节点的值
Node *_next;
Node(char ch, Node *next = nullptr)
{
_ch = ch;
_next = next;
}
};
//一个链表用来记录二叉树某一层的节点,因为由后序中序构建前序的时候是先左子树,后右子树,所以在层序遍历里面的位置也是没问题的
class LinkList
{
public:
LinkList()
{
_head = new Node(' ');
}
bool AddatTail(char ch)
{
Node *p = _head;
while (p->_next!= nullptr)//找尾巴
{
p = p->_next;
}
p->_next = new Node(ch);
return true;
}
void showLinkList()
{
Node *p = _head;
while (p != nullptr)
{
cout << p->_ch;
p = p->_next;
}
cout << endl;
}
~LinkList()
{
Node *q = _head->_next;
while (q != nullptr)
{
_head->_next = q->_next;
delete q;
q = _head->_next;
}
delete _head;//释放最后一个节点
}
private:
Node *_head;
};
int depth = 0;//全局变量 记录二叉树的深度(层数)的,在递归调用时改变
void MidSplitToTwoArray(const int mid, const string zhongxv, string &midleft, string &midright)//分割中序字符串
{
for (int i = 0; i < zhongxv.size(); i++)
{
if (i < mid)
midleft = midleft + zhongxv[i];
if (i > mid)
midright = midright + zhongxv[i];
}//切割中序
}
void HouSplitToTwoArray(const int houxvleftsize, const string houxv, string &houleft, string &houright)//切割后序字符串
{
for (int i = 0; i <= houxv.size() - 2; i++)//因为最后一位是已经求出来了的根节点
{
if (i < houxvleftsize)
houleft = houleft + houxv[i];
if (i >= houxvleftsize)
houright = houright + houxv[i];
}//切割后序
}
//每次都找出根节点,一批一批的找,好像一不小心写成了得到前序的代码(本来还不知道中序后序得到前序是怎么写的...)
//获得树的深度 并且得到并输出先序遍历的结果
void finddepth(string houxv, string zhongxv, int nowdepth)
{
//后序找根节点,中序分割出两个数组
//cout << "当前后序:" << houxv<< endl;
//cout << "当前中序:" << zhongxv<< endl;
int num = houxv.size();
cout << houxv[num - 1];//输出根节点
nowdepth = nowdepth + 1;
if (nowdepth > depth)//记录树的深度
depth = nowdepth;
//cout << " 根节点" << houxv[num - 1]<< endl;//输出根节点
if (num > 1)//还可以继续分割,没结束
{
int mid = -1;
for (int i = 0; i < num; i++)
{
if (zhongxv[i] == houxv[num - 1])//找到中序里面的分割点
{
mid = i;
break;
}
}
string midleft = "";//左子树中序
string midright = "";//右子树中序
string houleft = "";//左子树后序
string houright = "";//右子树后序
MidSplitToTwoArray(mid, zhongxv, midleft, midright);//切割中序
int houxvleftsize = midleft.size();
HouSplitToTwoArray(houxvleftsize, houxv, houleft, houright);//切割后序
//cout << "houleft:" << houleft << " midleft:" << midleft << endl;
//cout << "houright:" << houright << " midright:" << midright << endl;
//cout << endl;
if (midleft.size() != 0 && houleft.size() != 0)//因为有时候输的后序和中序是不对的 就会出现分割长度不匹配的情况
//在剩余的节点中重新找根节点
finddepth(houleft, midleft,nowdepth);
if (midright.size() != 0 && houright.size() != 0)
finddepth(houright, midright,nowdepth);
}
}
//每次都找出根节点,一批一批的找,好像一不小心写成了得到前序的代码(本来还不知道中序后序得到前序是怎么写的...)
//填充层序得的链表数组
void findRoot(string houxv, string zhongxv, LinkList *cengxv, int nowdepth = 0)
{
//后序找根节点,中序分割出两个数组
//cout << "当前后序:" << houxv<< endl;
//cout << "当前中序:" << zhongxv<< endl;
int num = houxv.size();
//cout<< houxv[num - 1];//输出根节点
//cout <<houxv[num-1]<<"层数"<<nowdepth<<endl;
cengxv[nowdepth].AddatTail(houxv[num - 1]);//写到层序数组里面(比如第一层的 就添加到nowdepth[0]链表里)
nowdepth = nowdepth + 1;
//if (nowdepth > depth)//记录树的深度
//depth = nowdepth;
//cout << " 根节点" << houxv[num - 1]<< endl;//输出根节点
if (num>1)//还可以继续分割,没结束
{
int mid=-1;
for (int i = 0; i < num; i++)
{
if (zhongxv[i] == houxv[num - 1])//找到中序里面的分割点
{
mid = i;
break;
}
}
string midleft="";//左子树中序
string midright="";//右子树中序
string houleft="";//左子树后序
string houright="";//右子树后序
MidSplitToTwoArray(mid,zhongxv,midleft,midright);//切割中序
int houxvleftsize = midleft.size();
HouSplitToTwoArray(houxvleftsize,houxv,houleft,houright);//切割后序
//cout << "houleft:" << houleft << " midleft:" << midleft << endl;
//cout << "houright:" << houright << " midright:" << midright << endl;
//cout << endl;
if (midleft.size() != 0 && houleft.size() != 0)//因为有时候输的后序和中序是不对的 就会出现分割长度不匹配的情况
//在剩余的节点中重新找根节点
findRoot(houleft, midleft, cengxv, nowdepth);
if (midright.size()!=0 && houright.size()!= 0)
findRoot(houright, midright, cengxv,nowdepth);
}
}
int main()
{
string houxv;
string zhongxv;
cout << "请输入二叉树的后序遍历:";
getline(cin, houxv);
cout << "请输入二叉树的中序遍历:";
getline(cin, zhongxv);
if (houxv != "" && zhongxv != "" && houxv.size() == zhongxv.size())
{
int nowdepth = 0;//当前节点所在二叉树的深度
cout << "得到的先序遍历:";
//感觉不知不觉写出了 由 后序 中序 得到前序遍历...
finddepth(houxv, zhongxv, nowdepth);//获得树的深度(层数)
cout << endl << "二叉树的深度为:" << depth << endl;
LinkList *cengxv = new LinkList[depth];//装很多个链表的数组,每个数组元素是一个链表的头指针,包含二叉树某一层的全部节点
findRoot(houxv, zhongxv, cengxv, 0);//填充层序数组(其实是前序 按层分类是没问题的 是能保证从左到右的)
cout << "层序遍历结果:" << endl;
for (int ceng = 0; ceng < depth; ceng++)
{
cengxv[ceng].showLinkList();
}
delete [] cengxv;
}
cin.get();
return 0;
}
总结
1.这几天写了二叉树的创建和遍历
2.二叉树又后序中序得到前序
3.二叉树由前序得到层序
总体顺序应该就是 中序+前序 —> 前序,前序—>层序