二叉树的后序遍历
Posted 、工藤新一
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了二叉树的后序遍历相关的知识,希望对你有一定的参考价值。
二叉树的三种遍历方式,其中每一种遍历方式都有三种实现方式。
节点定义:
struct TreeNode
{
int val;
TreeNode *left,*right;
TreeNode(int val){
this->val = val;
this ->left = this->right = NULL;
}
};
后序遍历
后序遍历:先访问左孩子,然后访问右孩子,最后访问根节点。
所以,上面遍历的结果是:DAEHSCG。
下面,我们来看看具体代码实现:
1.递归实现
void PostOrder(TreeNode *root){
if (root==NULL)
return;
PostOrder(root->left);
PostOrder(root->right);
cout<<root->val<<endl;
}
2.使用辅助栈
void postOrder(TreeNode *root) {
if(root == NULL)
return;
stack<TreeNode *> stk;
stk.push(root);
TreeNode *prev = NULL;
while(!stk.empty()) {
TreeNode *pNode = stk.top();
if(!prev || prev->left == pNode || prev->right == pNode) { // traverse down
if(pNode->left)
stk.push(pNode->left);
else if(pNode->right)
stk.push(pNode->right);
/* else {
cout << pNode->val << endl;
stk.pop();
}
*/
}
else if(pNode->left == prev) { // traverse up from left
if(pNode->right)
stk.push(pNode->right);
}
/* else if(pNode->right == prev) { // traverse up from right
cout << pNode->val << endl;
stk.pop();
}
*/
else {
cout << pNode->val << endl;
stk.pop();
}
prev = pNode;
}
}
双辅助栈实现思路:
设置两个栈stk, stk2;
将根结点压入第一个栈stk;
弹出stk栈顶的结点,并把该结点压入第二个栈stk2;
将当前结点的左孩子和右孩子先后分别入栈stk;
当所有元素都压入stk2后,依次弹出stk2的栈顶结点,并访问之。
第一个栈的入栈顺序是:根结点,左孩子和右孩子;于是,压入第二个栈的顺序是:根结点,右孩子和左孩子。
因此,弹出的顺序就是:左孩子,右孩子和根结点。
void PostOrder2(TreeNode *root){ //两个栈实现
if (root == NULL)
return;
stack<TreeNode*> stk,stk2;
stk.push(root);
while(!stk.empty()){
TreeNode* pNode = stk.top();
stk.pop();
stk2.push(pNode);// 将根节点压栈
if (pNode->left != NULL) // 如果左孩子不为空,则压栈
{
stk.push(pNode->left);
}
if (pNode->right != NULL) // 如果左孩子不为空,则压栈
{
stk.push(pNode->right);
}
}
while(!stk2.empty()){
cout<<stk2.top()->val<<endl;
stk2.pop();
}
}
3.Morris遍历实现
实现思路:
1.先建立一个临时结点dummy,并令其左孩子为根结点root,将当前结点设置为dummy;
2.如果当前结点的左孩子为空,则将其右孩子作为当前结点;
3.如果当前结点的左孩子不为空,则找到其在中序遍历中的前驱结点,
-如果前驱结点的右孩子为空,将它的右孩子设置为当前结点,将当前结点更新为当前结点的左孩子;
-如果前驱结点的右孩子为当前结点,倒序输出从当前结点的左孩子到该前驱结点这条路径上所有的结点。将前驱结点的右孩子设置为空,将当前结点更新为当前结点的右孩子。
4.重复以上过程,直到当前结点为空。
具体实现:
void reverse(TreeNode* p1,TreeNode *p2){
if (p1 == p2)
return;
TreeNode* x = p1;
TreeNode* y = p1->right;
while(true){
TreeNode* tmp = y->right;
y->right = x;
x = y;
y = tmp;
if (x == p2)
break;
}
}
void printReverse(TreeNode* p1,TreeNode *p2){
reverse(p1,p2);
TreeNode* pNode = p2;
while(true){
cout<<pNode->val<<endl;
if (pNode == p1)
break;
pNode = pNode->right;
}
reverse(p2,p1);
}
void PostOrder3(TreeNode* root){
if(root == NULL)
return;
TreeNode *dummy = new TreeNode(-1);
dummy->left = root;
TreeNode *pNode = dummy;
while(pNode != NULL) {
if(pNode->left == NULL)
pNode = pNode->right;
else {
TreeNode *pPrev = pNode->left;
while(pPrev->right != NULL && pPrev->right != pNode)
pPrev = pPrev->right;
if(pPrev->right == NULL) {
pPrev->right = pNode;
pNode = pNode->left;
}
else {
printReverse(pNode->left, pPrev);
pPrev->right = NULL;
pNode = pNode->right;
}
}
}
}
附:二叉树的先序遍历
附:二叉树的中序遍历
附:二叉树的后序遍历
附:二叉树的三种遍历对比及用图片展现说明
以上是关于二叉树的后序遍历的主要内容,如果未能解决你的问题,请参考以下文章