数据结构Java版:二叉树(基础篇)

相关

数据结构Java版:二叉树(题目篇)

简介

  • 前序遍历:访问根节点 左子树 右子树

  • 中序遍历:访问左子树 根节点 右子树

  • 后序遍历:访问左子树 右子树 根节点

    1.二叉树示例

         /*
      *               1
      *             /   \
      *           2      3
      *         /  \    /
      *        4    5  6
      */
    

    2.TreeNode结构

public class TreeNode {
    public int val;
    public TreeNode left;
    public TreeNode right;

    public TreeNode() {
    }

    public TreeNode(int val) {
        this.val = val;
    }

    public TreeNode(int val, TreeNode left, TreeNode right) {
        this.val = val;
        this.left = left;
        this.right = right;
    }
}

一、递归遍历

先序遍历

	// 先序遍历递归
    public static void preOrder(TreeNode root) {
        if (root == null) {
            return;
        }
        System.out.print(root.val + " ");
        preOrder(root.left);
        preOrder(root.right);
    }

中顺遍历

	// 中序遍历递归
    public static void inOrder(TreeNode root) {
        if (root == null) {
            return;
        }
        inOrder(root.left);
        System.out.print(root.val + " ");
        inOrder(root.right);
    }

后续遍历

	// 后序遍历递归
    public static void postOrder(TreeNode root) {
        if (root == null) {
            return;
        }
        postOrder(root.left);
        postOrder(root.right);
        System.out.print(root.val + " ");
    }

二、非递归遍历

先序遍历

	// 先序遍历非递归
    public static void perOrderNonRecur(TreeNode root) {
        if (root == null) {
            return;
        }
        Stack<TreeNode> stack = new Stack<>();
        TreeNode curNode = root;
        stack.push(curNode);
        while (!stack.empty()) {
            // 先处理当前元素
            curNode = stack.pop();
            System.out.print(curNode.val + " ");
            // 右孩子先进栈,左孩子后进栈 左孩子先出栈被处理
            if (curNode.right != null) {
                stack.push(curNode.right);
            }
            if (curNode.left != null) {
                stack.push(curNode.left);
            }
        }
    }

    /**
     * 以下 先中后序遍历 一致保持指针移动思路 接近看到一个二叉树,手动移动指针跟随节点变化的过程
     * 前序遍历个人偏好 perOrderNonRecur 的写法,故都列了出来
     */
    // 先序遍历非递归
    public static void perOrderNonRecur02(TreeNode root) {
        if (root == null) {
            return;
        }
        Stack<TreeNode> stack = new Stack<>();
        TreeNode curNode = root;
        while (curNode != null || !stack.empty()) {
            while (curNode != null) {
                System.out.print(curNode.val + " ");
                stack.push(curNode);
                curNode = curNode.left;
            }
            curNode = stack.pop();
            curNode = curNode.right;
        }
    }

中序遍历

	// 中序遍历非递归
    public static void inOrderNonRecur(TreeNode root) {
        if (root == null) {
            return;
        }
        Stack<TreeNode> stack = new Stack<>();
        TreeNode curNode = root;
        // 先处理左孩子
        while (curNode != null || !stack.empty()) {
            while (curNode != null) {
                stack.push(curNode);
                curNode = curNode.left;
            }
            curNode = stack.pop();
            System.out.print(curNode.val + " ");
            curNode = curNode.right;
        }
    }

后续遍历

	// 后续遍历非递归
    /*
                  1
                /   \
               2     3
                    /  \
                   4    5
        --> 1进栈
            --> 2进栈
                judge(2是否有右孩子||右孩子未处理) N --> 2出栈 ----------------------------------------------> 2
                    judge(1是否有右孩子||右孩子未处理)
                        | Y
                        | --> 3进栈
                            --> 4进栈
                                judge(4是否有右孩子||右孩子未处理) N --> 4出栈 ------------------------------> 4
                                    judge(3是否有右孩子||右孩子未处理)
                                        | Y
                                        | --> 5进栈
                                            judge(5是否有右孩子||右孩子未处理) N --> 5出栈 preNode=5 --------> 5
                                                judge(3是否有右孩子||右孩子未处理) N --> 3出栈 preNode=3 ----> 3
                                                    judge(3是否有右孩子||右孩子未处理) N --> 1出栈 ----------> 1
     */
    public static void postOrderNonRecur(TreeNode root) {
        if (root == null) {
            return;
        }
        Stack<TreeNode> stack = new Stack<>();
        TreeNode curNode = root;
        // 记录前置节点 为空 || 栈顶元素的右孩子
        TreeNode preNode = null;
        while (curNode != null || !stack.empty()) {
            while (curNode != null) {
                stack.push(curNode);
                curNode = curNode.left;
            }
            curNode = stack.peek();
            /*
            因为要先处理当前节点的右孩子,思考什么情况下选择pop元素
                1、没有右孩子
                2、右孩子已经被处理了
                    所以需要做标记,判断右孩子是否已经被处理
             */
            if (curNode.right == null || curNode.right == preNode) { // 右孩子为空或者已被处理(避免重复处理)
                curNode = stack.pop();
                System.out.print(curNode.val + " ");
                preNode = curNode;
                curNode = null; // 避免重复处理当前节点
            } else { // 右孩子非空且未被处理
                curNode = curNode.right;
            }
        }
    } 

层次遍历

	// bfs 层次遍历
    public static void levelOrder(TreeNode root) {
        if (root == null) {
            return;
        }
        Queue<TreeNode> queue = new LinkedList<>();
        TreeNode curNode = root;
        queue.add(curNode);
        int size; // 记录每一层的元素个数
        while (!queue.isEmpty()) {
            size = queue.size();
            while (size-- > 0) { // 遍历一层的元素
                curNode = queue.poll();
                System.out.print(curNode.val + " ");
                if (curNode.left != null) {
                    queue.add(curNode.left);
                }
                if (curNode.right != null) {
                    queue.add(curNode.right);
                }
            }
            System.out.println();
        }
    }

三、结果调试

  • 程序入口
	public static void main(String[] args) {
        TreeNode root = mockTree();

        System.out.println("===> 递归遍历 ===>");
        System.out.print("先序遍历: ");
        preOrder(root);
        System.out.println();

        System.out.print("中序遍历: ");
        inOrder(root);
        System.out.println();

        System.out.print("后序遍历: ");
        postOrder(root);
        System.out.println();

        System.out.println("===> 非递归遍历 ===>");
        System.out.print("先序遍历: ");
        perOrderNonRecur(root);
        System.out.println();
        System.out.print("先序遍历: ");
        perOrderNonRecur02(root);
        System.out.println();

        System.out.print("中序遍历: ");
        inOrderNonRecur(root);
        System.out.println();

        System.out.print("后序遍历: ");
        postOrderNonRecur(root);
        System.out.println();

        System.out.println("===> 层次遍历 ===>");
        levelOrder(root);
    }
 
 
    public static TreeNode mockTree() {
        TreeNode root = new TreeNode(1);
        TreeNode two = new TreeNode(2);
        TreeNode three = new TreeNode(3);
        TreeNode four = new TreeNode(4);
        TreeNode five = new TreeNode(5);
        TreeNode six = new TreeNode(6);

        /*
         *               1
         *             /   \
         *           2      3
         *         /  \    /
         *        4    5  6
         */
        root.left = two;
        root.right = three;
        two.left = four;
        two.right = five;
        three.left = six;

        return root;
    }
  • 结果预览

     ===> 递归遍历 ===>
     先序遍历: 1 2 4 5 3 6 
     中序遍历: 4 2 5 1 6 3 
     后序遍历: 4 5 2 6 3 1 
     ===> 非递归遍历 ===>
     先序遍历: 1 2 4 5 3 6 
     先序遍历: 1 2 4 5 3 6 
     中序遍历: 4 2 5 1 6 3 
     后序遍历: 4 5 2 6 3 1 
     ===> 层次遍历 ===>
     1 
     2 3 
     4 5 6 
    
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值