二叉树相关强化-长期更新

前言:二叉树的遍历、前序、中序、后序、层次遍历、递归写法与循环写法
提示:java编写,以后考虑用c++重写

二叉树的定义

class TreeNode {
    int val = 0;
    TreeNode left = null;
    TreeNode right = null;

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

构建二叉排序树

按顺序递归构建二叉排序树

注:按顺序构建,根节点已经固定
用例:
7
5 3 2 1 6 7 4

public class Main {
    public static void main(String[] args) {
        Scanner sc = new Scanner(System.in);
        while (sc.hasNext()) {
            int n = sc.nextInt();
            int[] arr = new int[n];
            for (int i = 0; i < n; i++) {
                arr[i] = sc.nextInt();
            }
            
            TreeNode root = new TreeNode(arr[0]); // 构建根结点
            for (int i = 1; i < n; i++) {
                sortBinaryTree(root, arr[i]);
            }
            preOrder(root);
            System.out.println();
            
            Arrays.sort(arr); // 先排序
            TreeNode minHeightTree = createMinHeightTree(arr, 0, arr.length - 1);
            preOrder(minHeightTree);
        }
    }

    public static void preOrder(TreeNode node){
        if(node != null){
            System.out.print(node.val + " ");
            preOrder(node.left);
            preOrder(node.right);
        }
    }

    public static TreeNode sortBinaryTree(TreeNode node, int i) {
        if (node == null) {
            node = new TreeNode(i);
            return node;
        } else {
            if (i <= node.val) {
                node.left = sortBinaryTree(node.left, i);
            } else {
                node.right = sortBinaryTree(node.right, i);
            }
            return node;
        }
    }
}

构建最小高度的二叉排序树

注:首先要排序,然后从中间取。递归

    public static TreeNode createMinHeightTree(int[] a, int start, int end){
        if(start > end)
            return null;
        int mid = start + (end - start)/2;
        TreeNode node = new TreeNode(a[mid]);
        node.left = createMinHeightTree(a, start, mid-1);
        node.right = createMinHeightTree(a, mid+1, end);
        return node;
    }

二叉树的遍历相关部分

import java.util.*;

//树的层次遍历
public class Solution {
    public TreeNode createBinaryTree() {
        TreeNode root = new TreeNode(1);
        TreeNode p2 = new TreeNode(2);
        TreeNode p3 = new TreeNode(3);
        TreeNode p4 = new TreeNode(4);
        TreeNode p5 = new TreeNode(5);
        TreeNode p6 = new TreeNode(6);
        TreeNode p7 = new TreeNode(7);
        // 组合  1
        //    2     3
        //   4   5 # 7
        //  # # 6
        root.left = p2;
        root.right = p3;
        p2.left = p4;
        p2.right = p5;
        p3.right = p7;
        p5.left = p6;
        return root;
    }
    
    public static void main(String[] args) {
        Solution solution = new Solution();
        TreeNode root = solution.createBinaryTree();
        // 先序递归遍历
        List<Integer> res = new ArrayList<>();
        System.out.println("*******先序**************************");
        solution.preOrderRecur(root, res);
        System.out.println(res);
        System.out.println("*********************************");
        res = solution.preOrderLoop(root);
        System.out.println(res);
        System.out.println("*******中序**************************");
        res.clear();
        solution.InOrderRecur(root, res);
        System.out.println(res);
        System.out.println("*********************************");
        res = solution.InOrderLoop(root);
        System.out.println(res);
        System.out.println("*******后序**************************");
        res.clear();
        solution.PostOrderRecur(root, res);
        System.out.println(res);
        res = solution.PostOrderLoop(root);
        System.out.println(res);
        System.out.println("*******深度**************************");
        int depth = solution.depth(root);
        System.out.println(depth);
        System.out.println("*******层次遍历**************************");
        res.clear();
        solution.levelOrder(root, res);
        System.out.println(res);
        System.out.println("*******层次遍历从左到右**************************");
        List<List<Integer>> ret = solution.levelOrder(root);
        for (List<Integer> sub : ret)
            System.out.println(sub);
        System.out.println("*******层次遍历之字形**************************");
        ret = solution.Print(root);
        for (List<Integer> sub : ret)
            System.out.println(sub);
    }
}

先序遍历

    // 递归先序
    public void preOrderRecur(TreeNode root, List<Integer> list) {
        if (root == null)
            return;
        list.add(root.val);
        preOrderRecur(root.left, list);
        preOrderRecur(root.right, list);
    }

    // 循环先序, 需要借助栈
    public List<Integer> preOrderLoop(TreeNode root) {
        List<Integer> list = new ArrayList<Integer>();
        if (root == null)
            return list;
        Stack<TreeNode> stack = new Stack<TreeNode>();
        TreeNode p = root;
        while (!stack.isEmpty() || p != null) {
            if (p != null) {
                stack.push(p); // 保存结点的原因是要回退到上一结点
                list.add(p.val); // 保存结点的同时就取值
                p = p.left;
            } else {
                p = stack.pop();
                p = p.right;
            }
        }
        return list;
    }

中序遍历

    // 中序遍历递归
    public void InOrderRecur(TreeNode root, List<Integer> list) {
        if (root == null)
            return;
        InOrderRecur(root.left, list);
        list.add(root.val);
        InOrderRecur(root.right, list);
    }

    // 中序循环,从这里就看出中序循环与先序多么类似
    public List<Integer> InOrderLoop(TreeNode root) {
        List<Integer> list = new ArrayList<>();
        if (root == null)
            return list;
        Stack<TreeNode> stack = new Stack<>();
        TreeNode p = root;
        while (!stack.isEmpty() || p != null) {
            if (p != null) {
                stack.push(p); // 先添加结点
                p = p.left;
            } else {
                p = stack.pop();
                list.add(p.val); // 后才考虑取出结点得出值
                p = p.right;
            }
        }
        return list;
    }

后序遍历

// 后序递归遍历
    public void PostOrderRecur(TreeNode root, List<Integer> list) {
        if (root == null)
            return;
        PostOrderRecur(root.left, list);
        PostOrderRecur(root.right, list);
        list.add(root.val);
    }

    // 后序循环遍历,比前面的循环遍历要麻烦些,仍然使用栈,额外需要辅助:上一个结点、当前节点
    public List<Integer> PostOrderLoop(TreeNode root) {
        List<Integer> list = new ArrayList<>();
        if (root == null)
            return list;
        Stack<TreeNode> stack = new Stack<>();
        TreeNode p = root, pre = null, cur = null;
        while (!stack.isEmpty() || p != null) {
            if (p != null) {
                stack.push(p); // 这里和中序类似
                p = p.left;
            } else {
                cur = stack.peek();
                if (pre != cur.right && cur.right != null) {
                    // 若上一个结点不是当前节点的右结点(必须这样判断),且当前节点的右结点存在
                    // 从左结点往上需要考虑父结点是否存在右子树;从右结点往上直接退,直到当前节点为父结点的左子结点
                    p = cur.right;
                } else {
                    pre = stack.pop(); // 保存上一个结点
                    list.add(pre.val); // 存值
                }
            }
        }
        return list;
    }

数的深度

    // 递归求取深度,但仍存在树太深,递归栈溢出问题
    public int depth(TreeNode root) {
        if (root == null)
            return 0;
        return Math.max(depth(root.left), depth(root.right)) + 1;
    }

层次遍历

    // 层次遍历, 遍历结果加到一个数组
    public void levelOrder(TreeNode root, List<Integer> list) {
        if (root == null)
            return;
        Deque<TreeNode> deque = new ArrayDeque<>();
        deque.offer(root);
        TreeNode p = null;
        while (!deque.isEmpty()) {
            p = deque.poll();
            list.add(p.val);
            if (p.left != null)
                deque.offer(p.left);
            if (p.right != null)
                deque.offer(p.right);
        }
    }

    /*
    * 后续是补充的一些改进方法,有些是剑指offer上,不属于主要遍历方式
    * */

    // 层次遍历,这里改进,每层按之字形
    public List<List<Integer>> Print(TreeNode root) {
        List<List<Integer>> ret = new ArrayList<>();
        if (root == null)
            return ret;
        boolean even = true;
        Deque<TreeNode> deque = new ArrayDeque<>();
        deque.add(root);
        TreeNode p = null;
        int curSize = 0;
        while (!deque.isEmpty()) {
            curSize = deque.size(); // 初始化每层结点个数
            List<Integer> list = new ArrayList<Integer>();
            for (int i = 0; i < curSize; i++) {
                p = deque.poll();
                if (even) {
                    list.add(p.val); // 偶数往后添加
                } else {
                    list.add(0, p.val); // 奇数前插
                }
                if (p.left != null)
                    deque.add(p.left);
                if (p.right != null)
                    deque.add(p.right);
            }
            ret.add(list);
            even = !even; // 转换每层方向
        }
        return ret;
    }

    // 层次遍历, 遍历结果按层存放
    public List<List<Integer>> levelOrder(TreeNode root) {
        List<List<Integer>> res = new ArrayList<>();
        if (root == null)
            return res;
        dfs(res, root, 0); // 第一层为0层
        return res;
    }

    // 辅助的dfs
    private void dfs(List<List<Integer>> res, TreeNode node, int level) {
        if (res.size() < level + 1) {
            res.add(new ArrayList<Integer>()); // 这里有多深就创建了多少层
        }
        res.get(level).add(node.val);
        if (node.left != null) {
            dfs(res, node.left, level + 1);
        }
        if (node.right != null) {
            dfs(res, node.right, level + 1);
        }
    }

平衡二叉树的插入以及删除

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值