二叉树的前中后序遍历

数据结构那点事—遍历二叉树

程序=数据结构+算法,研究新技术,中间件,框架的同时,最为基础的东西一定不能落下,灵活运用各种数据结构,根据业务需求可以定制出合适的数据结构,是一个必须掌握的技能

数据结构常见的运算有 1)创建运算.2)清楚运算.3)插入运算.4)删除运算.5)搜索运算.6)更新运算.7)访问运算.8)遍历运算

这里就从二叉树的三种遍历入手,手撕数据结构

所谓遍历,就是按照某种次序,系统地访问数据结构中的元素,是的每个元素恰好被访问一次

简易的树的代码示例

right
A
D
B
E
H
F
J
G
C
K
class Node {
    char val;
    Node left;
    Node right;

    public Node(char val) {
        this.val = val;
    }
}
public class Visit {

    static Node root;
    static {
        Node root = new Node('A');
        Node b = new Node('B');
        Node c = new Node('C');
        Node d = new Node('D');
        Node e = new Node('E');
        Node f = new Node('F');
        Node g = new Node('G');
        Node h = new Node('H');
        Node j = new Node('J');
        Node k = new Node('K');

        root.left = d;
        root.right = b;
        d.left = e;
        e.left = h;
        e.right = f;
        f.left = j;
        f.right = g;
        b.right = c;
        c.left = k;
    }
}

前序遍历

​ 若二叉树为空,则空操作;

​ 否则1)访问根结点;2)先序遍历左子树;3)先序遍历右子树

​ 有了指导思想,采用递归的方式可以轻松写出代码

递归实现
static void preOrder(Node root) {
        if (root != null) {
            // 遍历根结点
            System.out.println(root.val);
          	// 先序遍历左子树
            preOrder(root.left);
            // 先序遍历右子树
            preOrder(root.right);
        }
}
非递归实现
static void preOrder(Node root){
  			Deque<Node> stack = new LinkedList();
  			if(root != null)stack.push(root);
  			while(!stack.isEmpty()){
          		Node node = stack.pop();
          		System.out.println(node.val);
          		if(node.right != null)stack.push(node.left);
          		if(node.left != null)stack.push(node.right);
        }
}

​ 几乎所有的递归都可以转换成循环(特例后面补上),因为栈和递归都有回溯的特性,在非递归实现中,按照先序遍历的次序,是先根结点,然后左子树,再右子树,所以先讲右结点压栈,然后左结点,这样下次循环就会将栈顶的左结点弹出

中序遍历

​ 若二叉树为空,则空操作;

​ 否则1)中序遍历左子树;2)访问根结点;3)中序遍历右子树

递归实现
static void inOrder(Node root) {
        if (root != null) {
          	// 中序遍历左子树
            inOrder(root.left);
            // 遍历根结点
            System.out.println(root.val);
            // 中序遍历右子树
            inOrder(root.right);
        }
}
非递归实现

​ 递归实现有些太简单了,有手就会写,下面给出中序遍历的非递归实现,思路是这样的,先循环遍历左结点,将这些左结点压栈,一条路走到黑,因为中序遍历是左 -根-右的顺序,弹出栈顶的左结点(栈顶的结点已经不存在左孩子结点了),检查其是否有右孩子结点,如果有,将其压栈,如此循环便可

static void inOrderWithLoop(Node root) {
        Deque<Node> stack = new LinkedList<>();
        Node node = root;
        while (!stack.isEmpty() || node != null) {
            // 循环遍历左结点,一条路走到黑
            while (node != null) {
                stack.push(node);
                node = node.left;
            }
            node = stack.pop();
            System.out.println(node.val);
            node = node.right;
        } 
 }

后序遍历

​ 若二叉树为空,则空操作;

​ 否则1)后序遍历左子树;2)后序遍历右子树;3)访问根结点

递归实现
static void postOrder(Node root) {
        if (root != null) {
            postOrder(root.left);
            postOrder(root.right);
            System.out.println(root.val);
        }
}
非递归实现

​ 递归实现简单易懂,但是由于性能问题,递归次数过多函数调用栈会越深,容易出现内存不够用的问题,因此在实际生产中,能转换成循环的尽量转换成循环

static void postVisitWithLoop(Node root) {
        Deque<Node> stack = new LinkedList<>();
        stack.push(root);
        Deque<Node> s = new LinkedList<>();
        while (!stack.isEmpty()) {
            Node node = stack.pop();
            s.push(node);
            if (node.left != null) stack.push(node.left);
            if (node.right != null) stack.push(node.right);
        }
        while(!s.isEmpty()){
            System.out.println(s.pop().val);
        }
}

​ 后续遍历的非递归实现:准备两个栈,姑且叫做栈a和栈b,首先根结点压入到栈a中,然后将其左右结点分别压入栈a,他们入栈b的顺序为先根结点,然后右孩子结点(其实是右子树),左孩子结点;这样栈b的出栈顺序就是左子树,右子树,根结点

小结

​ 没发现特别好的技巧,基础的知识改死记硬背就死记硬背吧

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值