有这样一道题目,给出二叉树的前序遍历顺序和中序遍历顺序,让你求(1)它的广度优先遍历顺序。(2) 它的后续遍历顺序。
(1)在http://soj.sysu.edu.cn/1935 (2)在http://acm.zju.edu.cn/onlinejudge/showProblem.do?problemCode=1944
二道题目的做法都差不多,关键是要根据前序和中序遍历构建出这棵二叉树。
通过观察,我们可以发现,前序遍历的第一个元素是整棵树的根节点,在中序遍历中找到这个元素对应的位置i,i左边的就是左子树(0~i-1),i右边的就是右子树(i~n-1)。同理,前序遍历的第二个元素是左子树的根节点,可以继续将左子树进行划分。当左边不存在分区时,返回上一级,对右边进行划分,构建右子树,直到全部都划分完毕。用递归实现。
我自己写的根据前序和中序遍历构造二叉树的代码的一种写法如下
void build(Tree*&t, string pre, string mid)
{
t = new Tree(pre[0]);
int r = mid.find(pre[0]);
if (r > 0)
{
string lpre = pre.substr(1,r);
string lmid = mid.substr(0,r);
build(t->left, lpre, lmid);
}
if (r < mid.length() - 1)
{
string rpre = pre.substr(r+1,pre.length()-1);
string rmid = mid.substr(r+1,mid.length()-1);
build(t->right, rpre, rmid);
}
}
(1)的代码如下所示,因为mac下不能使用关键字index,我就改名为index1了。
#include<iostream>
#include<queue>
#include<string>
#include"string.h"
using namespace std;
string pre,in;
int index1,len;
struct Tree
{
Tree * left;
Tree * right;
char data;
Tree(char ch = 0)
{
left = right = NULL;
data = ch;
}
};
void rebuild(Tree *& root, int st, int ed)
{
if (st>ed || index1 >= pre.size()) return;
root = new Tree(pre[index1]);
int root_index = in.find(pre[index1++]);
rebuild(root->left, st, root_index-1);
rebuild(root->right, root_index+1, ed);
}
int main()
{
int t;
cin >> t;
while (t--)
{
cin >> pre >> in;
len = pre.size();
index1 = 0;
Tree *root = new Tree();
rebuild(root, 0, len-1);
queue<Tree*>q;
q.push(root);
while (!q.empty())
{
Tree* tmp = q.front();
q.pop();
cout << tmp->data;
if (tmp->left) q.push(tmp->left);
if (tmp->right) q.push(tmp->right);
}
cout << endl;
}
return 0;
}
(2)的代码如下所示:
#include<iostream>
#include<queue>
#include<string>
#include"string.h"
using namespace std;
string pre,in;
int index1,len;
struct Tree
{
Tree * left;
Tree * right;
char data;
Tree(char ch = 0)
{
left = right = NULL;
data = ch;
}
};
void rebuild(Tree *& root, int st, int ed)
{
if (st>ed || index1 >= pre.size()) return;
root = new Tree(pre[index1]);
int root_index = in.find(pre[index1++]);
rebuild(root->left, st, root_index-1);
rebuild(root->right, root_index+1, ed);
}
void postOrder(Tree * root)
{
if (root)
{
postOrder(root->left);
postOrder(root->right);
cout << root->data;
}
}
int main()
{
while(cin >> pre >> in)
{
len = pre.size();
index1 = 0;
Tree *root = new Tree();
rebuild(root, 0, len-1);
postOrder(root);
cout << endl;
}
return 0;
}
其实细细一想,该题还可以继续扩展一下,就是根据中序和后续遍历构造二叉树,其实思路也是差不多的,读者可以稍微思考一下。
下面我再给出不用建树的方法直接求出遍历顺序
#include <iostream>
#include <string>
using namespace std;
int find(const string &str, char c)
{
for (int i = 0; i < str.size(); ++ i)
if (c == str[i])
return i;
return -1;
}
bool PreMid(const string &pre, const string &mid)
{
if (pre.size() == 0)
return false;
if (pre.size() == 1)
{
cout << pre;
return true;
}
//根节点是第一个元素
int k = find(mid, pre[0]);
string pretmp = pre.substr(1, k);
string midtmp = mid.substr(0, k);
PreMid(pretmp, midtmp);
pretmp = pre.substr(k + 1, pre.size() - k - 1);
midtmp = mid.substr(k + 1, mid.size() - k - 1);
PreMid(pretmp, midtmp);
//变成后序遍历要最后输出节点的值
cout << pre[0];
}
bool BackMid(const string &back, const string &mid)
{
if (back.size() == 0)
return false;
if (back.size() == 1)
{
cout << back;
return true;
}
//根节点是最后一个元素
int k = find(mid, back[back.size() - 1]);
//变成前序遍历要先输出节点的值
cout << back[back.size() - 1];
string backTmp = back.substr(0, k);
string midTmp = mid.substr(0, k);
BackMid(backTmp, midTmp);
backTmp = back.substr(k, back.size() - k - 1);
midTmp = mid.substr(k + 1, mid.size() - k - 1);
BackMid(backTmp, midTmp);
}
int main()
{
string pre, mid;
while (cin >> pre >> mid)
{
PreMid(pre, mid);
cout << endl;
}
}
参考
http://324012406.iteye.com/blog/738304