算法1.2

这篇博客详细介绍了树的基本概念,包括结点的度、层次、子树等,并深入讲解了二叉树的定义、满二叉树和完全二叉树。文章通过递归和迭代两种方式阐述了二叉树的前序、中序、后序遍历以及层序遍历。此外,还讨论了对称二叉树、最大深度、平衡二叉树的判断方法。
摘要由CSDN通过智能技术生成

前言

本篇博客是参考 学习视频 的笔记

1.树

1.什么是树?

树: 由n(n>=1)个有限结点组成一个具有层次关系的集合。

特点:

  • 每个结点有零个或多个子结点;
  • 没有父结点的结点为根结点;
  • 每一个非根结点只有一个父结点;
  • 每个结点及其后代结点整体上可以看做是一棵树,称为当前结点的父结点的一个子树;

相关术语:

  • 结点的度:
    一个结点含有的子树的个数
    A结点的度为6
  • 叶结点(终端结点):
    度为0的结点
    如:B、H、I、J、K、N、O、M
  • 分支结点(非终端结点):
    度不为0的结点
  • 结点的层次:
    从根结点开始,根结点的层次为1,之后每一层+1
    如:A的层次为1,N的层次为4
  • 结点的层序编号:
    将树中的结点,按照从上层到下层,同层从左到右的次序排成一个线性序列,把他们编成连续的自然数
    如:A:0、B:1、H:8
  • 树的度:
    树中所有结点的度的最大值
    此树中A结点的度最大为6,故树的度为6
  • 树的高度(深度):
    树中结点的最大层次
    此树中N、O结点层次最大,为4,故树的高度为4
  • 森林:
    多个互不相交的树的集合。将一个非空树的根节点去掉就形成了森林,给一个森林加一个统一的根节点即形成树
  • 孩子结点:
    一个结点的直接后继结点
    如:I、H都是C的孩子结点
  • 双亲结点(父结点):
    一个结点的直接前驱
    如:C是H、I的双亲结点
  • 兄弟结点:
    同一双亲结点的孩子结点
    如:I、H是兄弟结点

树的表示:
双亲表示法:

孩子表示法1: 不管树的度为多少,都用最大的度来表示(浪费空间)

孩子表示法2: degree表示当前节点的度,有几个度就有几个孩子节点(结构较为复杂)

孩子表示法3: 将所有结点存入顺序链表

孩子兄弟表示法:

2.二叉树

二叉树: 度不超过2的树

满二叉树: 一个二叉树,如果每一个层的结点的度都达到最大值,则这个二叉树就是满二叉树

完全二叉树: 叶节点只能出现在最下层和次下层,并且最下面一层的结点都集中在该层最左边的若干位置的二叉树

完全二叉树的数组表示法:

ABCDEFGHIJ
0123456789

推论1: 对于位置为 k 的结点,左子结点 = 2*k + 1,右子节点 = 2*(k+1)

推论2: 最后一个非叶子结点的位置为 (N/2) - 1N 为数组长度

注意: 只有完全二叉树会用数组表示法,一般的二叉树都是用下列表示方法:

dataleftchildrightchild

3.二叉树的遍历:

前序遍历: 先访问根结点,然后再访问左子树,最后访问右子树
请添加图片描
述
遍历结果:A B D H I E J C F G

中序遍历: 先访问左子树,再访问根节点,最后访问右子树
请添加
图片描述
遍历结果:H D I B J E A F C G

后序遍历: 先访问左子树,再访问右子树,最后访问根节点
请添加图片
描述
遍历结果: H I D J E B F G C A

层序遍历: 从根节点(第一层)开始,依次向下,获取每一层所有结点的值
请添加图片
描述
遍历结果:A B C D E F G H I J

2.习题

二叉树的中序遍历

给定一个二叉树的根节点 root ,返回 它的 中序 遍历 。

思路1——递归实现
左——根——右
先访问玩左子树,再访问根节点,最后访问右子树(很符合递归的思想)。

/**
 * Definition for a binary tree node.
 * public class TreeNode {
 *     int val;
 *     TreeNode left;
 *     TreeNode right;
 *     TreeNode() {}
 *     TreeNode(int val) { this.val = val; }
 *     TreeNode(int val, TreeNode left, TreeNode right) {
 *         this.val = val;
 *         this.left = left;
 *         this.right = right;
 *     }
 * }
 */
class Solution {
    public List<Integer> inorderTraversal(TreeNode root) {
    	//返回结果
        List<Integer> res = new ArrayList<>();
        //递归入口
        accessTree(root,res);
        return res;
        
    }

    public void accessTree(TreeNode root,List<Integer> res){
    	//终止条件
        if (root == null) return;
        //中序遍历: 左-根-右
        accessTree(root.left,res);
        res.add(root.val);
        accessTree(root.right,res);
    }
}

思路2——循环迭代(栈)

内部 while 第一次循环完

将栈内元素存入列表

/**
 * Definition for a binary tree node.
 * public class TreeNode {
 *     int val;
 *     TreeNode left;
 *     TreeNode right;
 *     TreeNode() {}
 *     TreeNode(int val) { this.val = val; }
 *     TreeNode(int val, TreeNode left, TreeNode right) {
 *         this.val = val;
 *         this.left = left;
 *         this.right = right;
 *     }
 * }
 */
class Solution {
    public List<Integer> inorderTraversal(TreeNode root) {
        //存储遍历后的数字
        List<Integer> res = new ArrayList<>();
        //用来辅助中序遍历
        Deque<TreeNode> stack = new LinkedList<>();
        
        while (root != null || !stack.isEmpty()){
            //先将左子树入栈,然后出栈交给list(已经反序)
            while (root != null){
                stack.push(root);
                root = root.left;
            }
            root = stack.pop();
            res.add(root.val);
            //开始遍历右子树(为空的时候,就继续弹出,不然就入栈)
            root = root.right;
        }
        return res;
    }
}

二叉树前序遍历

给你二叉树的根节点 root ,返回它节点值的 前序 遍历。

思路1——递归实现
根——左——右

/**
 * Definition for a binary tree node.
 * public class TreeNode {
 *     int val;
 *     TreeNode left;
 *     TreeNode right;
 *     TreeNode() {}
 *     TreeNode(int val) { this.val = val; }
 *     TreeNode(int val, TreeNode left, TreeNode right) {
 *         this.val = val;
 *         this.left = left;
 *         this.right = right;
 *     }
 * }
 */
class Solution {
    public List<Integer> preorderTraversal(TreeNode root) {
        List<Integer> res = new ArrayList<>();
        accessTree(root,res);
        return res;
        
    }

    public void accessTree(TreeNode root,List<Integer> res){
        if (root == null) return;
        //中序遍历: 根-左-右
        res.add(root.val);
        accessTree(root.left,res);
        accessTree(root.right,res);
    }
    
}

思路2——循环迭代

/**
 * Definition for a binary tree node.
 * public class TreeNode {
 *     int val;
 *     TreeNode left;
 *     TreeNode right;
 *     TreeNode() {}
 *     TreeNode(int val) { this.val = val; }
 *     TreeNode(int val, TreeNode left, TreeNode right) {
 *         this.val = val;
 *         this.left = left;
 *         this.right = right;
 *     }
 * }
 */
class Solution {
    public List<Integer> preorderTraversal(TreeNode root) {
        //存储遍历后的数字
        List<Integer> res = new ArrayList<>();
        //用来辅助中序遍历
        Deque<TreeNode> stack = new LinkedList<>();
        
        while (root != null || !stack.isEmpty()){
            //先将根节点存入链表,再将左子树入栈,然后出栈交给list(已经反序)
            while (root != null){
                res.add(root.val);
                stack.push(root);
                root = root.left;
            }
            root = stack.pop();
            //开始遍历右子树
            root = root.right;
        }
        return res;
    }
}

二叉树的后序遍历

给你一棵二叉树的根节点 root ,返回其节点值的 后序遍历 。

思路1——递归
左——右——根

/**
 * Definition for a binary tree node.
 * public class TreeNode {
 *     int val;
 *     TreeNode left;
 *     TreeNode right;
 *     TreeNode() {}
 *     TreeNode(int val) { this.val = val; }
 *     TreeNode(int val, TreeNode left, TreeNode right) {
 *         this.val = val;
 *         this.left = left;
 *         this.right = right;
 *     }
 * }
 */
class Solution {
    /**
        递归
     */
    public List<Integer> postorderTraversal(TreeNode root) {
        List<Integer> res = new ArrayList<>();
        accessTree(root,res);
        return res;
    }

    private void accessTree(TreeNode root, List<Integer> res){
        if (root == null) return;
        accessTree(root.left,res);
        accessTree(root.right,res);
        res.add(root.val);
    }
}

思路2——循环迭代
与前中序遍历有所不同:访问完左子树后,要访问右子树,但是左子树没有指针直接连接右子树,需要先经过最近的连接着右子树的根节点,再去访问右子树。
有右子树的节点将被反复压栈
因此代码有所不同:

/**
 * Definition for a binary tree node.
 * public class TreeNode {
 *     int val;
 *     TreeNode left;
 *     TreeNode right;
 *     TreeNode() {}
 *     TreeNode(int val) { this.val = val; }
 *     TreeNode(int val, TreeNode left, TreeNode right) {
 *         this.val = val;
 *         this.left = left;
 *         this.right = right;
 *     }
 * }
 */
class Solution {
    public List<Integer> postorderTraversal(TreeNode root) {
        List<Integer> res = new ArrayList<>();
        Deque<TreeNode> stack = new LinkedList<>();
        TreeNode prevAccess = null;//指向前一个节点,判定当前结点右子树是否遍历过了

        while (root != null || !stack.isEmpty()){
            while (root != null){
                stack.push(root);
                root = root.left;
            }

            root = stack.pop();
            //新增判断,若当前节点没有右节点 或 当前右节点是否已经遍历过了,如果都没有 就 将结点值加入链表
            if (root.right == null || root.right == prevAccess){
                res.add(root.val);
                prevAccess = root;
                root = null;//root置空
            }else {//否则就继续压栈,遍历右子树
                stack.push(root);
                root = root.right;
            }
        }

        return res;
    }
}

对称二叉树

给你一个二叉树的根节点 root , 检查它是否轴对称。

思路1——递归

/**
 * Definition for a binary tree node.
 * public class TreeNode {
 *     int val;
 *     TreeNode left;
 *     TreeNode right;
 *     TreeNode() {}
 *     TreeNode(int val) { this.val = val; }
 *     TreeNode(int val, TreeNode left, TreeNode right) {
 *         this.val = val;
 *         this.left = left;
 *         this.right = right;
 *     }
 * }
 */
class Solution {
    public boolean isSymmetric(TreeNode root) {
        if (root == null) return true;
        //递归入口
        return deepCheck(root.left, root.right);
    }

    private boolean deepCheck(TreeNode left, TreeNode right){
        if (left == null && right == null){
            return true;
        }
        if (left == null || right == null){
            return false;
        }
        if (left.val != right.val){
            return false;
        }

        return deepCheck(left.left, right.right) && deepCheck(left.right, right.left);
    } 
}

思路2——循环迭代(队列)
先入队
再取出对比:
请添加图
片描述

/**
 * Definition for a binary tree node.
 * public class TreeNode {
 *     int val;
 *     TreeNode left;
 *     TreeNode right;
 *     TreeNode() {}
 *     TreeNode(int val) { this.val = val; }
 *     TreeNode(int val, TreeNode left, TreeNode right) {
 *         this.val = val;
 *         this.left = left;
 *         this.right = right;
 *     }
 * }
 */
class Solution {
    public boolean isSymmetric(TreeNode root) {
        Queue<TreeNode> q = new LinkedList<>();
        TreeNode u = root.left;
        TreeNode v = root.right;

        if (root == null || (u == null && v == null)){
            return true;
        }

        //入队
        q.offer(u);
        q.offer(v);

        while (!q.isEmpty()){
            //出队
            u = q.poll();
            v = q.poll();

            if (u == null && v == null){
                continue;
            }
            if ((u == null || v == null) || (u.val != v.val)){
                return false;
            }

            //在将该节点的左右子节点入队
            q.offer(u.left);
            q.offer(v.right);

            q.offer(u.right);
            q.offer(v.left);

        }
        return true;
    }
}

二叉树最大深度

给定一个二叉树,找出其最大深度。
二叉树的深度为根节点到最远叶子节点的最长路径上的节点数

思路——递归

/**
 * Definition for a binary tree node.
 * public class TreeNode {
 *     int val;
 *     TreeNode left;
 *     TreeNode right;
 *     TreeNode() {}
 *     TreeNode(int val) { this.val = val; }
 *     TreeNode(int val, TreeNode left, TreeNode right) {
 *         this.val = val;
 *         this.left = left;
 *         this.right = right;
 *     }
 * }
 */
class Solution {
    public int maxDepth(TreeNode root) {
        if (root == null){
            return 0;
        }else {
            return Math.max(maxDepth(root.left),maxDepth(root.right)) + 1;
        }
    }
}
/**
 * Definition for a binary tree node.
 * public class TreeNode {
 *     int val;
 *     TreeNode left;
 *     TreeNode right;
 *     TreeNode() {}
 *     TreeNode(int val) { this.val = val; }
 *     TreeNode(int val, TreeNode left, TreeNode right) {
 *         this.val = val;
 *         this.left = left;
 *         this.right = right;
 *     }
 * }
 */
class Solution {
    public int maxDepth(TreeNode root) {
        if (root == null) return 0;
        Queue<TreeNode> queue = new LinkedList<>();
        queue.offer(root);
        int depth = 0;//深度

        while (!queue.isEmpty()){
            //用来记录本层级的节点是否已经处理完
            int size = queue.size();
            while (size > 0){
                TreeNode node = queue.poll();
                if (node.left != null){
                    queue.offer(node.left);
                }
                if (node.right != null){
                    queue.offer(node.right);
                }
                size--;
            }
            depth++;
        }
        return depth;
    }
}

平衡二叉树

给定一个二叉树,判断它是否是高度平衡的二叉树。

本题中,一棵高度平衡二叉树定义为:
  一个二叉树每个节点 的左右两个子树的高度差的绝对值不超过 1 。

/**
 * Definition for a binary tree node.
 * public class TreeNode {
 *     int val;
 *     TreeNode left;
 *     TreeNode right;
 *     TreeNode() {}
 *     TreeNode(int val) { this.val = val; }
 *     TreeNode(int val, TreeNode left, TreeNode right) {
 *         this.val = val;
 *         this.left = left;
 *         this.right = right;
 *     }
 * }
 */
class Solution {
    public boolean isBalanced(TreeNode root) {
        if (root == null) return true;
        return helper(root) != -1;
        
    }
    public int helper(TreeNode root){
        if (root == null) return 0;

        //统计左树和右树的高度
        int left = helper(root.left);
        int right = helper(root.right);

        if (left == -1 || right == -1 || Math.abs(left - right) > 1){
            return -1;
        }
        
        return Math.max(left,right) + 1;
    }
}

反转二叉树

思路1——递归调用

/**
 * Definition for a binary tree node.
 * public class TreeNode {
 *     int val;
 *     TreeNode left;
 *     TreeNode right;
 *     TreeNode() {}
 *     TreeNode(int val) { this.val = val; }
 *     TreeNode(int val, TreeNode left, TreeNode right) {
 *         this.val = val;
 *         this.left = left;
 *         this.right = right;
 *     }
 * }
 */
class Solution {
    public TreeNode invertTree(TreeNode root) {
        if (root == null) return null;

        invertTree(root.left);
        invertTree(root.right);

        TreeNode tmp = root.left;
        root.left = root.right;
        root.right = tmp;
        return root;
    }
}

3.十大排序算法和七大查找算法推荐阅读

超详细十大经典排序算法总结(java代码)c或者cpp的也可以明白

七大查找算法(Java版)

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

364.99°

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

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

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

打赏作者

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

抵扣说明:

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

余额充值