题目
题目描述
按中序遍历和后序遍历给出一棵二叉树,现在有如下操作:
UPDATE A B,将中序遍历中A位置(从1开始编号的下标)对应的在二叉树中的节点的权值改为B
QUERY,询问树上所有节点的权值,以及从根节点到该节点的路径权值之和
STOP,停止操作,STOP操作一定出现在最后
中序遍历和后序遍历的输入保证叶子节点的权值各不相同。但是,之后如果存在UPDATE操作,则UPDATE操作可能会使得两个或两个以上的叶子节点的权值相同。
输入
测试数据有多组
对于每组测试数据,
第一行输入这棵二叉树中序遍历的结果
第二行输入这棵二叉树后序遍历的结果
接下来每一行输入一种操作,直到输入STOP操作时结束本组测试数据的输入。其中,QUERY操作次数 <= 2,总操作数 <= 104
输入一直处理到文件尾(EOF)
输出
对于每组测试数据:
对于QUERY操作,按中序遍历输出节点的权值,以及从根节点到该节点路径权值之和。这里,我们认为根节点到其本身的路径权值之和为根节点的权值
样例输入
3 2 1 4 5 7 6
3 1 2 5 6 7 4
UPDATE 5 99
UPDATE 6 123
UPDATE 1 37
QUERY
UPDATE 1 36
QUERY
STOP
7 8 11 3 5 16 12 18
8 3 11 7 16 18 12 5
QUERY
STOP
255
255
STOP
样例输出
37 43
2 6
1 7
4 4
99 226
123 127
6 133
36 42
2 6
1 7
4 4
99 226
123 127
6 133
7 12
8 31
11 23
3 26
5 5
16 33
12 17
18 35
代码
#include<iostream>
#include<string>
#include<vector>
using namespace std;
struct Node {
int data;
int pos;
Node* left;
Node* right;
Node() :left(nullptr), right(nullptr) {}
Node(int theData) :left(nullptr), right(nullptr), data(theData) {}
};
class biTree {
private:
Node* root;
Node* createBiTree(vector<int>& inorder, vector<int>& postorder) {
// 第一步
if (postorder.size() == 0)
return nullptr;
// 第二步,后序遍历数组最后一个元素,就是当前中间节点
int rootValue = postorder[postorder.size() - 1];
Node* t = new Node(rootValue);
// 叶子节点
if (postorder.size() == 1)
return t;
// 第三步,找切割点
int delimiterIndex;
for (delimiterIndex = 0; delimiterIndex < inorder.size(); delimiterIndex++) {
if (inorder[delimiterIndex] == rootValue)
break;
}
// 第四步,切割中序数组,得到 中序左数组和中序右数组
vector<int> leftInorder(inorder.begin(), inorder.begin() + delimiterIndex);
vector<int> rightInorder(inorder.begin() + delimiterIndex + 1, inorder.end());
// 第五步,切割后序数组,得到 后序左数组和后序右数组
postorder.resize(postorder.size() - 1);
vector<int> leftPostorder(postorder.begin(), postorder.begin() + leftInorder.size());
vector<int> rightPostorder(postorder.begin() + leftInorder.size(), postorder.end());
// 第六步
t->left = createBiTree(leftInorder, leftPostorder);
t->right = createBiTree(rightInorder, rightPostorder);
return t;
}
public:
biTree() : root(nullptr) {}
~biTree() {
delete[] root;
}
Node* getRoot() const {
return root;
}
void createTree(vector<int>& inorder, vector<int>& postorder) {
root = createBiTree(inorder, postorder);
}
void inOrder(Node* t, int sum) {
if (t == nullptr)
return;
sum += t->data;
inOrder(t->left, sum);
cout << t->data << " " << sum << endl;
inOrder(t->right, sum);
}
void setTree(Node* t, int& thePos) {
if (t == nullptr)
return;
setTree(t->left, thePos);
t->pos = thePos++;
setTree(t->right, thePos);
}
void changeTree(Node* t, int pos, int theData) {
if (t == nullptr)
return;
if (t->pos == pos)
t->data = theData;
else {
changeTree(t->left, pos, theData);
changeTree(t->right, pos, theData);
}
}
};
int main() {
int pos, newData;
string str, op;
while (getline(cin, str)) {
vector<int> inorder;
vector<int> postorder;
biTree bitree;
int len = str.length();
for (int i = 0; i < len; i++) {
if (str[i] != ' ') {
int key = 0;
while (str[i] != ' ' && i < len)
key = key * 10 + (str[i++] - '0');
inorder.push_back(key);
}
}
getline(cin, str);
len = str.length();
for (int i = 0; i < len; i++) {
if (str[i] != ' ') {
int key = 0;
while (str[i] != ' ' && i < len)
key = key * 10 + (str[i++] - '0');
postorder.push_back(key);
}
}
bitree.createTree(inorder, postorder);
Node* t = bitree.getRoot();
int pos = 1;
bitree.setTree(t, pos);
while (cin >> op && op != "STOP") {
if (op == "UPDATE") {
cin >> pos >> newData;
bitree.changeTree(t, pos, newData);
}
else if (op == "QUERY")
bitree.inOrder(t, 0);
}
getchar();
cout << endl;
}
return 0;
}
总结
首先这道题的第一个难点是如何处理多组数据,我们可以使用getline
读取一行字符串。
然后第二个难点是根据中序遍历和后序遍历的结果创建一个二叉树总的思想就是以后序数组最后一个元素位切割点,先切中序数组,然后根据中序数组,再切割后序数组,每次后序数组最后一个元素就是当前节点元素。
一开始我我以为每次UPDATAE时,都要修改二叉树指定位置的权值,有点麻烦。所以我想,既然这样,不如每次UPDATE时,同时修改中序数组和后续数组,然后遇到QUERY操作时,根据当前中序数组和后序数组创建二叉树,再中序遍历输出结果。不过样例虽然过了,但是运行错误抛出了异常terminate called after throwing an instance of '
。
由于学校oj没有给出完整的异常信息,此路不通,所以还是老老实实创建树之后,在原来树的基础上修改吧。
既然每次UPDATE时要修改指定pos的权值,所以我给节点添加了pos成员变量,用来记录当前节点是中序遍历的第几个节点。