打印二叉树特定节点x的所有祖先节点
算法思路
二叉树的后序遍历顺序为左、右、根,递归写法为
postOrderTraversal(root->left);
postOrderTraversal(root->right);
cout<<root->val;
递归的边界为
if(!root){
return;
}
可以很清楚的看出递归栈的变化,即
树从根结点向左到叶子结点,沿途结点全部入栈,从栈中出栈访问结点p->left后回溯到其父结点p,再对以p->right为根结点的子树重复上述过程,当p结点的左右子树遍历完成后p出栈再回溯到p节点的父节点......以此类推直至最后root->right遍历完成后回溯到root节点递归结束。
把递归栈的变化模拟出来就可以知道:当访问到结点x时,要么x的右子树还未开始遍历入栈,要么x的所有子结点都已经访问出栈完成。无论哪种情况,当访问到x时的栈内剩余结点均为x的祖先结点。
维护一个栈,显示地将递归过程中栈的变化模拟出来。
这里我们要注意后序遍历跟前中序遍历的区别。由于前中序遍历根结点的访问都是在右子结点之前的,因此前中序遍历在入栈子树右子结点时根结点是直接出栈的。后序遍历的根结点的访问次序在最后,因此对于每棵子树根结点只有在以下两种情况才会出栈
- 无右子结点
- 右子结点已访问完成
因此每次向上回溯时要判断根结点是否应该访问出栈,使用指针prev记录上次访问结点,以此来判断子树根结点的右子结点是否已经访问。即
root->right==nullptr || root->right == prev
算法代码
// 打印x节点的所有祖先节点
void PrintAncestor(TreeNode* root, int x) {
stack<TreeNode*> stk;
TreeNode* prev;
while(root || !stk.empty()) {
while(root && root->val != x) {
stk.push(root);
root = root->left;
}
if(root==nullptr) {
root = stk.top();
stk.pop();
}
// 找到x后直接输出当前栈中所有节点算法结束
if(root->val == x) {
while(!stk.empty()) {
cout<<stk.top()->val<<" ";
stk.pop();
}
return;
}
if(root->right == nullptr || root->right == prev) {
prev = root;
root = nullptr;
}
else {
stk.push(root);
root = root->right;
}
}
}
ps:以上仅为个人理解,如有错误之处还请批评指正

浙公网安备 33010602011771号