二叉树的后序遍历


二叉树的三种遍历方式,其中每一种遍历方式都有三种实现方式。

节点定义:

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;
            }
        }
    }
}

附:二叉树的先序遍历

二叉树的先序遍历

附:二叉树的中序遍历

二叉树的中序遍历

附:二叉树的后序遍历

二叉树的后序遍历

附:二叉树的三种遍历对比及用图片展现说明

二叉树的三种遍历对比及用图片展现说明

### 使用后序遍历和中序遍历构建二叉树的算法实现 通过后序遍历和中序遍历来重建二叉树的核心思想在于利用两种遍历的特点。后序遍历序列的最后一个元素总是当前子树的根节点,而中序遍历可以通过找到这个根节点的位置将其划分为左右两部分,分别对应左子树和右子树。基于此特性,可以采用递归的方式逐步构建整棵树。 以下是具体的 Python 实现代码: ```python class TreeNode: def __init__(self, val=0, left=None, right=None): self.val = val self.left = left self.right = right def buildTree(postorder, inorder): if not postorder or not inorder: return None # 后序遍历的最后一个元素是根节点 root_val = postorder[-1] root = TreeNode(root_val) # 找到根节点在中序遍历中的索引 index = inorder.index(root_val) # 划分左右子树 left_inorder = inorder[:index] right_inorder = inorder[index + 1:] # 根据划分后的中序遍历计算对应的后序遍历范围 left_postorder = postorder[:len(left_inorder)] right_postorder = postorder[len(left_inorder):-1] # 递归构造左右子树 root.left = buildTree(left_postorder, left_inorder)[^1] root.right = buildTree(right_postorder, right_inorder)[^1] return root ``` #### 解释 1. **终止条件**:如果 `postorder` 或 `inorder` 的列表为空,则表示没有更多的节点需要处理,返回 `None`。 2. **确定根节点**:从后序遍历序列中提取最后一个元素作为当前子树的根节点,并创建一个新的 `TreeNode` 节点。 3. **分割中序遍历**:通过根节点值在中序遍历序列中的位置,将中序遍历序列分成两个部分——左边的部分代表左子树,右边的部分代表右子树。 4. **分割后序遍历**:根据中序遍历得到的左右子树大小,进一步切割后序遍历序列,从而获得左子树和右子树对应的后序遍历序列。 5. **递归构建**:对左右子树分别递归调用相同的逻辑,最终完成整个二叉树的构建[^2]。 --- ###
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

、工藤新一

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值