精华内容
下载资源
问答
  • 算法思想:后序非递归遍历二叉树是先访问左子树,再访问右子树,最后访问根节点。 ①若根节点有左孩子,则左孩子以此入栈,直到左孩子为空,然后读取栈顶元素,若其右孩子不为空且未被访问过,则对右子树执行①。...

    算法思想:后序非递归遍历二叉树是先访问左子树,再访问右子树,最后访问根节点。 ①若根节点有左孩子,则左孩子以此入栈,直到左孩子为空,然后读取栈顶元素,若其右孩子不为空且未被访问过,则对右子树执行①。否则栈顶元素出栈并访问。

    例:

    image.png
    对上图进行后序遍历。

    代码:

    #include <bits/stdc++.h>
    using namespace std;
    
    typedef struct TreeNode{
        char data;
        struct TreeNode *lchild,*rchild;
        int tag;
    }TreeNode ,*Tree;
    
    
    // 递归构造二叉树
    void createTree(Tree &t){
        char ch;
        ch = getchar();
        if (ch=='#') t=NULL;
        else{
            t = (TreeNode *)malloc(sizeof(TreeNode));
            t->data = ch;
            t->tag = 0;
            t->lchild =NULL;
            t->rchild = NULL;
            createTree(t->lchild);
            createTree(t->rchild);
             
    
        }
    }
    
    
    void back(Tree t){
        struct TreeNode *stack[30];
        int top = -1;
        TreeNode *p = t;
        TreeNode *x;
    //若p存在或者栈不为空则可继续进行
        while(p||top!=-1){
        
    	//若p存在则入栈并将p指向左孩子结点
            if(p){
                top++;
                stack[top]=p;
                p=p->lchild;
            }
    	//p不存在,则将p指向栈顶元素。
            else{
                p=stack[top];
    //判断是否有右孩子并且有没有被访问。
                if(p->rchild&&p->rchild->tag == 0){
                    p=p->rchild;
    
                }else{
                    p=stack[top];
                    top--;
                    cout<<p->data<<" ";
                    p->tag = 1;
                    p=NULL;
                }
    
    
    
            }
    
        }
    }
    
    
    
    int main(){
        Tree t;
        createTree(t);
        back(t);
        return 0;
    }
    // ABD##E##C##
    
    展开全文
  • 如果要求以递归的方式遍历二叉树,还是蛮简单的。只需要在树非空的情况下,依次递归调用传参(左子树),(右子树),再访问结点(或者是进行一些具体的操作,比如删除、修改等) 但是,非递归的后序遍历就要考虑...

    首先,后序遍历是按照左右根(LRN)的顺序遍历的。如果要求以递归的方式遍历二叉树,还是蛮简单的。只需要在树非空的情况下,依次递归调用传参(左子树),(右子树),再访问结点(或者是进行一些具体的操作,比如删除、修改等)

    但是,非递归的后序遍历就要考虑很多了。后序遍历的非递归实现是四种遍历方法中最难的。因为在后序遍历中,要保证做孩子和右孩子都被访问了,才能访问根节点(即LRN)。

    基本算法思路分析:从根节点开始,将结点入栈,然后沿着左子树一直往下搜索,直到搜索到没有左孩子的结点;接着判断还有没有右孩子剩下,如果有,继续访问LR这样的顺序,直到进行不下去了(最左下方的右叶子结点)。如果要出栈,需要保证待出栈的结点的左子树早已被访问完了,并且右子树刚访问完,则弹出栈顶结点;继续重复以上操作。

    void PostOrder(BiTree T)
    {
    	InitStack(S);			//初始化栈
    	BiTreeNode *p = T, *r = NULL;
    	while(p!=NULL || IsEmpty(S))
    	{
    		if(p != NULL)		//走到了最左边
    		{
    			push(S, p);		//入栈
    			p = p->lchild;
    		}
    		//此时可以保证已经把最L都走到底了,准备检查R
    
    		else
    		{
    			GetTop(S, p);	//获取栈顶元素,非出栈
    			
    			if(p->rchild!=NULL && p->rchild!=r)
    			{
    				//如果右子树存在,且没有被访问过,是新鲜的结点
    				p = p->rchild;	//继续R
    			}
    			else
    			{
    				//说明左边右边都差不多可以了,该到N出场了
    				pop(S, p);		//出栈
    				visit(p->data);
    				r = p;			//相当于一个尾巴,永远跟着刚处理完的结点
    				p = NULL;		//刚刚遍历完了以p为根的小子树,下次遍历的时候,只要p!=r,就说明底下的还没访问过
    			}
    		}
    	}
    }
    

    我们使用r尾随指针来区别,子树是否访问过,也可以用一个更简单的办法,改一下二叉树ADT

    typedef struct BiTree

    {

    ElemType value;

    BiTreeNode* lchild, *rchild;

    bool isVisited = 0; //如果访问过了,改成1

    }BiTreeNode;

    展开全文
  • 二叉树后序遍历

    千次阅读 2021-04-03 13:41:32
    二叉树后序遍历的记忆法则是“左右根",即先遍历左子树节点,再遍历右子树节点,最后遍历根节点。 以上图为例,后序遍历的结果是【D, E, B, F, G, C, A】 一、解题思路:递归 递归是我们实现前中后序遍历最常用的...

    二叉树文章系列:

    1. 二叉树的前序遍历
    2. 二叉树的中序遍历
    3. 二叉树的后序遍历
    4. 二叉树的层序遍历
    5. 二叉树的前序、中序、后序、层序遍历【解法完整版】


    二叉树的后序遍历的记忆法则是“左右根",即先遍历左子树节点,再遍历右子树节点,最后遍历根节点。

    以上图为例,后序遍历的结果是【D, E, B, F, G, C, A】

    一、解题思路:递归

    递归是我们实现前中后序遍历最常用的方法。

    什么问题可以采用递归求解呢?

    需要满足三个条件:

    1. 一个问题的解可以分解为若干个子问题的解;
    2. 这个问题与分解的子问题,除了数据规模不同外,求解思路相同
    3. 存在递归终止条件。

    那么在知道一个问题可以采用递归实现之后,如何写出递归代码呢?

    关键在于能写出递归公式,找到终止条件。

    在二叉树的前序遍历问题上,它的递归公式是:

    preorder(node) = preorder(node->left) --> preorder(node->right) —> print node

    它的终止条件是:

    node 是否为空,为空则返回。

    class Solution {
    public:
        vector<int> preorderTraversal(TreeNode* root) {
            vector<int> res;
            preorder(res, root);
            return res;
        }
    
        void preorder(vector<int>& res, TreeNode* root){
            
            if(!root) return;
            res.emplace_back(root->val);
            preorder(res, root->left);
            preorder(res, root->right);
        }
    };
    

    二、解题思路:迭代(方法1)

    我们在使用迭代法来实现后序遍历的时候,通常有两大类思路。第一类是先得到“根右左”,然后对输出列表反序,即得到“左右根”; 第二类是直接求出“左右根”。

    咱们知道,前序遍历是求“根左右”,那么我们可以使用前序遍历的方法,去求得“根右左”。以上图为例,我们求得的“根右左”的结果是【A, C, G, F, B, E, D】。再对这个结果反序,得到【D, E, B, F, G, C, A】。这正是咱们想得到的后序遍历。

    本文第二节和第三节介绍的两种迭代方法,都是采用这种思路来实现。最后第四小节,我们会介绍直接求出后序遍历的思路。


    在递归方法实现过程中,它的底层是基于系统栈的结构来实现的。因此,我们可以使用栈的数据结构来辅助实现基于迭代方式的后序遍历。

    具体思路为:

    • 初始化栈stack,初始化输出列表res
    • 根节点入栈
    • while(栈不为空),在循环体内部:
      • 栈顶元素出栈
      • 栈顶元素添加到输出列表
      • 如果栈顶元素的左子树节点不为空,将左子树节点入栈
      • 如果栈顶元素的右子树节点不为空,将右子树节点入栈
    • 对输出列表res 进行反序
    • 返回输出列表res

    class Solution {
    public:
        vector<int> postorderTraversal(TreeNode* root) {
    
            vector<int> res;
            if(!root) return res;
    
            stack<TreeNode*> s;
            s.push(root);
            while(!s.empty()){
                TreeNode* node = s.top();
                s.pop();
                res.emplace_back(node->val);
                if(node->left) s.push(node->left);
                if(node->right) s.push(node->right);
            }
            reverse(res.begin(), res.end());
            return res;
        }
    };
    

    三、解题思路:迭代(方法2)

    基于迭代方法的第二种思路如下:

    • 初始化栈stack,初始化输出列表res
    • 设置一个变量cur, 表示当前节点。并赋初始值为根节点root
    • while(栈不为空 或者 当前节点cur不为空),在循环体内部:
      • 沿着当前节点的右分支一直走,直到为空。在这个过程中将遍历的节点都入栈,同时添加到输出列表
      • 栈顶元素出栈
      • 更新当前节点cur为栈顶元素的左子树节点。
    • 对输出列表res 进行反序
    • 返回输出列表res

    以图中的二叉树为例,来一步步来展示这个过程:

    初始时,当前节点cur = root ,即节点A

    图片3

    图片4

    图片5

    图片6

    图片7

    图片8

    class Solution {
    public:
        vector<int> postorderTraversal(TreeNode* root) {
    
            vector<int> res;
            if(!root) return res;
    
            stack<TreeNode*> s;
            TreeNode* cur = root;
            while(!s.empty() || cur){
                while(cur){
                    res.emplace_back(cur->val);
                    s.push(cur);
                    cur = cur->right;
                }
                TreeNode* node = s.top();
                s.pop();
                cur = node->left;
            }
            reverse(res.begin(), res.end());
            return res;
        }
    };
    

    四、解题思路:迭代(方法3)

    这次我们要尝试直接得到后序遍历的结果。

    我们知道后序遍历的顺序是”左右根“。那么对于一个根节点,要先遍历它的左子树节点和右子树节点,再回头遍历根节点。

    为了防止遍历根节点的时候,再次遍历到它的左、右子树节点;我们需要一个变量,来表示最后一次出栈的元素。

    class Solution {
    public:
        vector<int> postorderTraversal(TreeNode* root) {
    
            vector<int> res;
            if(!root) return res;
    
            stack<TreeNode* > s;
            s.push(root);
            TreeNode* lastPopNode = root;
            while(!s.empty()){
                TreeNode* node = s.top();
                if(node->left && node->left != lastPopNode && node->right != lastPopNode){
                    s.push(node->left);
                }else if(node->right && node->right != lastPopNode){
                    s.push(node->right);
                }else{
                    res.emplace_back(node->val);
                    s.pop();
                    lastPopNode = node;
                }
            }
            return res;  
        }
    };
    
    展开全文
  • 后序遍历也是深度优先算法,在后顺序遍历中,首先访问左子树,然后访问右子树,最后打印节点或根的值。这就是为什么根值总是在后序遍历中最后打印的原因。与许多树算法一样,实现后序遍历的最简单方法是使用递归。...

    后序遍历也是深度优先算法,在后顺序遍历中,首先访问左子树,然后访问右子树,最后打印节点或根的值。这就是为什么根值总是在后序遍历中最后打印的原因。与许多树算法一样,实现后序遍历的最简单方法是使用递归。实际上,如果您知道如何使用递归编写先序,则可以使用相同的算法稍作调整来实现后序遍历。

    使用递归进行后序遍历

    递归算法很容易理解,因为它与递归preOrder和递归inOrder遍历完全相似。 唯一不同的是访问或遍历左子树,右子树和根的顺序,如下面的代码片段所示。

    private void postOrder(TreeNode node) {

    if (node == null) {

    return;

    }

    postOrder(node.left);

    postOrder(node.right);

    System.out.printf("%s ", node.data);

    }

    在后序遍历中打印二叉树的Java程序

    这里是一个完整的Java程序,用于在后序遍历中打印二叉树的所有节点。

    先创建一个名为BialayTrand的类来表示Java中的二叉树。此类有一个静态嵌套类来表示树节点,称为TreeNode。这类似于map.entry类,用于表示哈希表中的条目。该类只保留对root的引用,Treenode负责照顾左右子项。

    这个类有两个方法postOrder()和postOrder(TreeNode root),第一个是public,第二个是private。实际遍历是在第二种方法中完成的,但由于root是类内部的,客户端无法访问root,因此创建了postOrder()方法来调用私有方法。这是实现递归算法的常用技巧。

    这也使您可以在不影响客户端的情况下更改算法。我们可以将递归算法改为迭代算法,客户端仍然会调用post order方法而不知道现在迭代算法已经到位了。

    按后序打印二叉树节点

    import java.util.Stack;

    /*

    * Java Program to traverse a binary tree

    * using postOrder traversal without recursion.

    * In postOrder traversal first left subtree is visited, followed by right subtree

    * and finally data of root or current node is printed.

    *

    * input:

    *     55

    *    /  \

    *   35   65

    *   / \    \

    *  25  45   75

    *  /  /  \

    * 15 87  98

    *

    * output: 15 25 45 35 87 98 75 65 55

    */public class Main {

    public static void main(String[] args) throws Exception {// construct the binary tree given in questionBinaryTree bt = BinaryTree.create();// traversing binary tree using post-order traversal using recursionSystem.out.println("printing nodes of a binary tree on post order in Java");

    bt.postOrder();

    }

    }

    class BinaryTree {

    static class TreeNode {

    String data;

    TreeNode left, right;

    TreeNode(String value) {

    this.data = value;

    left = right = null;

    }

    boolean isLeaf() {

    return left == null ? right == null : false;

    }

    }// root of binary treeTreeNode root;/**

    * traverse the binary tree on post order traversal algorithm

    */public void postOrder() {

    postOrder(root);

    }

    private void postOrder(TreeNode node) {

    if (node == null) {

    return;

    }

    postOrder(node.left);

    postOrder(node.right);

    System.out.printf("%s ", node.data);

    }/**

    * Java method to create binary tree with test data

    *

    * @return a sample binary tree for testing

    */public static BinaryTree create() {

    BinaryTree tree = new BinaryTree();

    TreeNode root = new TreeNode("55");

    tree.root = root;

    tree.root.left = new TreeNode("35");

    tree.root.left.left = new TreeNode("25");

    tree.root.left.left.left = new TreeNode("15");

    tree.root.left.right = new TreeNode("45");

    tree.root.right = new TreeNode("65");

    tree.root.right.right = new TreeNode("75");

    tree.root.right.right.left = new TreeNode("87");

    tree.root.right.right.right = new TreeNode("98");

    return tree;

    }

    }

    Output

    printing nodes of a binary tree on post order in Java

    15 25 87 98 45 35 75 65 55

    展开全文
  • 文章目录递归法后序遍历中序遍历前序遍历迭代法后续遍历中序遍历前序遍历 递归法 后序遍历 def postorderTraversal(self, root: TreeNode) -> List[int]: res = list() def dfs(r): if not r: return dfs...
  • 用递归方法实现二叉树的中序遍历和后序遍历算法 //用递归方法实现二叉树的中序遍历和后序遍历算法; #include "stdio.h" #include "stdlib.h" #define OK 1 #define ERROR 0 #define OVERFLOW -2 typedef char ...
  • //后序遍历左子树 PostOrderTraverse(T->rchild); //后序遍历右子树 cout; //访问根节点 } } void CreateBiTree(BiTree &T) { //按先序依次输入二叉树中结点的值,创建二叉链表表示的的二叉树 char ch; cin>>ch; if...
  • #endif /************************************************************************/ /* 以下是关于二叉树操作的11个简单算法 */ /************************************************************************/ ...
  • 中序可以和前序、后序、层序的任意一个搭配来构建唯一的二叉树。 若没有中序,其他的序列搭配都无法构建唯一的二叉树,因为先序、后序、层序都用于提供根结点,只有中序才能区分左右子树。 根据中序、后序构造树 ...
  • C语言数据结构之二叉树的非递归后序遍历算法前言:前序、中序、后序的非递归遍历中,要数后序最为麻烦,如果只在栈中保留指向结点的指针,那是不够的,必须有一些额外的信息存放在栈中。方法有很多,这里只举一种,...
  • 我们拿出一个最简单的二叉树,假设我们使用后序遍历递归,就是左子树-右子树-根节点,那么我们需要遍历根节点的左子树,左子树的节点拿到,读取它的值,将它append到开始建立的一个StringBuilder字符串中。...
  • 拆解题目内容: 后序遍历求树高度 + 全局计数器 + 节点平衡定义 + 返回值语义确认 实现方式:递归遍历 + 引用类型做全局计数器 2. 读题 “判断” 属于二叉树的遍历 “是否” 则是遍历中需要做的具体操作 “平衡” ...
  • Java实现二叉树的先序、中序、后序遍历算法 一、构建二叉树的存储结构 一棵二叉树的节点结构主要包括三部分:节点的值域,指向左孩子的指针,指向右孩子的指针。由于Java语言没有指针的定义,这里采用属性的方式实现...
  • #二叉树遍历算法 class Node: def __init__(self,value=None,left=None,right=None): self.value=value self.left=left self.right=right #先序遍历(NLR) def preTraverse(root): if root==None: return ...
  • 满意答案文件 main.cpp 代码如下:#include // malloc()等#include // 标准输入输出头文件,包括EOF(=^Z或F6),NULL等#include // atoi(),exit()#include // 数学函数头文件,包括floor...清空二叉树和销毁二叉树的...
  • } /*递归后序遍历 (3)在上述二叉树的基础上,后序遍历,求解二叉树深度的算法*/ int Depth(BiTree T){ int m,n; if(T==NULL) return FALSE; else { m=Depth(T->lchild); n=Depth(T->rchild); if(m>n) ...
  • 解题思路: 先说一下先,中,后序遍历二叉树是怎么建立的 先序遍历二叉树的操作定义如下: 若二叉树为空,则空操作;否则 (I)访问根结点; (2)先序遍历左子树; (3)先序遍历右子树。 中序遍历二叉树的操作定义如下...
  • 给出一棵树的中序遍历和后序遍历,请构造这颗二叉树 注意: 保证给出的树中不存在重复的节点 思路 思路很容易想,但是能不能顺利写出代码来又是另外一回事。 我使用了开区间 后序遍历的左右子树的区分应该由中序...
  • 二叉树的前中后序递归以及非递归算法以及层序遍历思想做了整合 因为某些书籍上对这类算法,写的非常笼统,所以,这里将从树的链式存储开始,结合整个 链表、栈、队列等结构来完成对树的学习,当然,这里也将会完美...
  • 根据一棵树的中序遍历与后序遍历构造二叉树。注意:你可以假设树中没有重复的元素。 分析:区间的开闭要统一,使用变动索引的方式就无需辅助空间了 #include "_myPrint.cpp" #include "stack" #include "queue" using...
  • 如图 1 中,对此二叉树进行后序遍历的操作过程为:从根节点 1 开始,遍历该节点的左子树(以节点 2 为根节点);遍历节点 2 的左子树(以节点 4 为根节点);由于节点 4 既没有左子树,也没有右子树,此时访问该节点中的...
  • 本文主要讲解如何根据二叉树的中序遍历和后序遍历,构建树。 在写PTA的钻石争霸赛时,在写最后一道题时,刚开始需要根据二叉树的中序遍历和后序遍历,构建二叉树,然后才能继续写题。经过当时向学长学习之后,也完成...
  • 889. 根据前序和后序遍历构造二叉树 前序和中序 道理相同 改变一些细节就可以了,在最后附上了前序中序的代码 题目描述 返回与给定的前序和后序遍历匹配的任何二叉树。 pre 和 post 遍历中的值是不同的正整数。 示例...
  • 思路:用递归把中序遍历的数组划分为左右子树部分,直到没有左右子树(叶子节点)。层序遍历的方法:使用队列。 #include <iostream> #include<vector> #include<queue> using namespace std; #...
  • /*分别使用递归思想与迭代思想实现二叉树的前序遍历、中序遍历、后序遍历*/ //递归思想实现前序遍历、中序遍历、后序遍历 //1、递归思想实现前序遍历 void PreOrderTraverse(BitTree T) { if (T == NULL) return; ...
  • 求一颗树的后序遍历的非递归算法 要求:必须是非递归算法,使用堆栈对象来实现 建树方法采用“先序遍历+空树用0表示”的方法 算法流程: 输入 第一行输入一个整数t,表示有t个测试数据 第二行起输入二叉树...
  • 实现二叉树前序、中序和后序遍历: 目录实现二叉树前序、中序和后序遍历:题目:示例:分析:代码: 题目: 实现二叉树前序、中序和后序遍历 提示:使用递归实现 示例: 示例: 输入: /* 1 2 3 4 5 6 */ ...
  • C++ 二叉树 前序遍历 中序遍历 后序遍历 通过递归代码推出非递归实现 通过遍历规则推出非递归实现
  • 返回与给定的前序和后序遍历匹配的任何二叉树。 pre 和 post 遍历中的值是不同的正整数。 递归: var constructFromPrePost = function(pre, post) { if (!pre.length) return null const root = new TreeNode(pre...
  • 二叉树后序遍历C++二叉树后序遍历基本思想C++二叉树后序遍历代码 C++二叉树后序遍历基本思想 创建两个栈stk和res,先把根节点压入栈中,循环stk不为空,创建一个tmp节点赋值为栈顶元素,弹栈,把tmp压入另一个栈,...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 42,844
精华内容 17,137
关键字:

后序遍历二叉树算法