点:二叉树边界技巧
题意:一个任意的二叉树,可以不是二叉排序树,或者部分子树是二叉排序的,打印这个二叉树中符合二叉搜索树性质的子树中,节点最多的子树
程序员代码面试指南面试题
思路:二叉排序树的性质就是:父节点比左节点大,比右节点小。依赖这个性质思考:
首先,这个适合后续遍历,因为后续遍历能得到左右子树的执行结果再去判断计算自己的结果,
然后,随便画一个二叉树
1、每个符合二叉排序性质的子树的节点个数,等于左子树个数加上右子树个数加上1(自己),这便于整体统一遍历计算
2、对于叶子节点,可以认为这种单节点也是一个子树,且节点个数是左节点个数0加上右节点个数0加上1,等于1
3、非叶子节点都这样类推,如果发现不符合二叉排序性质,返回1
同时,入栈一个最大值的标志变量和一个最大搜索子树根节点变量随递归入栈,当发现某节点的节点数超限时更新这个变量,更重要的是要更新最大搜索子树的根节点为当前节点,这样递归结束后就会得到最大搜索子树的根节点。
代码实现禁掉了根节点作为最大搜索子树的根节点,注意这个是个trick。
代码:
#include <iostream>
#include <queue>
template<class T> struct Node {
Node<T> *left;
Node<T> *right;
T val;
Node(T _val):val(_val), left(nullptr), right(nullptr){}
};
template<class T> class Btree {
Node<T> *root;
public:
Btree():root(nullptr) {}
void Free (Node<T> *cur) {
if (cur) {
Free(cur->left);
Free(cur->right);
delete cur;
cur = nullptr;
}
}
~Btree() {
Free(root);
}
void Add (T val) {
if (!root) {
root = new Node<T>(val);
return;
}
Node<T> *cur = root;
while (cur) {
if (cur->val > val) {
if (!cur->left) {
Node<T> *newnode = new Node<T>(val);
cur->left = newnode;
break;
} else {
cur = cur->left;
}
} else if (cur->val < val) {
if (!cur->right) {
Node<T> *newnode = new Node<T>(val);
cur->right = newnode;
break;
} else {
cur = cur->right;
}
} else {
break;
}
}
}
void Update (T val, T newval) {
if (root) {
Node<T> *cur = root;
while (cur) {
if (cur->val > val) {
if (cur->left) {
cur = cur->left;
} else {
break;
}
} else if (cur->val < val) {
if (cur->right) {
cur = cur->right;
} else {
break;
}
} else {
cur->val = newval;
break;
}
}
}
}
void level_traverse (Node<T> *subroot) {
if (!subroot) {
return;
}
std::queue<Node<T> *> q1, q2;
q1.push(subroot);
while (!q1.empty()) {
while (!q1.empty()) {
std::cout << q1.front()->val << "\t";
if (q1.front()->left) {
q2.push(q1.front()->left);
}
if (q1.front()->right) {
q2.push(q1.front()->right);
}
q1.pop();
}
while (!q2.empty()) {
q1.push(q2.front());
q2.pop();
}
std::cout << std::endl;
}
}
int FindBiggestSearchSubtree (Node<T> *cur, int &max, Node<T> *&subroot) {
if (cur) {
int cnt_l = FindBiggestSearchSubtree(cur->left, max, subroot);
int cnt_r = FindBiggestSearchSubtree(cur->right, max, subroot);
int res;
if (((cur->left && cur->val <= cur->left->val) ||
(cur->right && cur->val >= cur->right->val))) {
res = 1;
} else {
res = cnt_l + cnt_r + 1;
}
if (max < res) {
max = res;
if (cur != root) {
subroot = cur;
}
}
return res;
} else {
return 0;
}
}
void FindBiggestSearchSubtree () {
int max = 1;
Node<T> *subroot = root;
FindBiggestSearchSubtree(root, max, subroot);
level_traverse(subroot);
}
};
int main () {
Btree<int> bt;
bt.Add(10);
bt.Add(7);
bt.Add(12);
bt.Add(5);
bt.Add(9);
bt.Add(11);
bt.Add(20);
bt.Add(0);
bt.Add(6);
bt.Add(8);
bt.Add(15);
bt.Add(25);
bt.Add(14);
bt.Add(18);
bt.Add(22);
bt.Add(28);
bt.Update(11, 111);
bt.FindBiggestSearchSubtree();
return 0;
}