12树

P79 79_树_树的定义

P80 80_树_树的相关术语

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

# P81 81_树_二叉树定义

在这里插入图片描述
在这里插入图片描述
每一层的结点个数:2^(k-1)
在这里插入图片描述
在这里插入图片描述

P82 82_树_二叉查找树创建_API设计

在这里插入图片描述
在这里插入图片描述
为什么要用泛型?
因为可以存储多个类型的数据。
在这里插入图片描述

P83 83_树_二叉查找树创建_插入方法

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

P84 84_树_二叉查找树创建_获取方法

在这里插入图片描述

P85 85_树_二叉查找树创建_删除方法

P86 86_树_二叉查找树创建_测试

在这里插入图片描述
在这里插入图片描述

删掉后,要找一个结点来替换。12比左子树大,12比右子树小!

把12删掉。
让原来的左子树成为12的左子树,
让原来的右子树成为12的右子树,

在这里插入图片描述

//得找到右子树中最小的结点
if (x.right==null){
    return x.left;
}
//假如删除14,14的右子树为空,直接把12替换14就行了,
//这段代码就是这个意思。

在这里插入图片描述

if (x.left==null){
    return x.right;
}
//假如说要删除25,25左子树为空。
//直接让右子树替换就行。

在这里插入图片描述

14结点的下一个结点(12),再下一个结点为空,把(12)删除

//删除右子树中最小的结点
Node n = x.right;
while(n.left!=null){
    if (n.left.left==null){
        n.left=null;
        //14结点的下一个结点(12),再下一个结点为空,把(12)删除
    }else{
        //变换n结点即可,往下走
        n = n.left;
    }
}

在这里插入图片描述

package tree;

public class BinaryTree<Key extends Comparable<Key>, Value> {
    //记录根结点
    private Node root;
    //记录树中元素的个数
    private int N;

    private class Node {
        //存储键
        public Key key;
        //存储值
        private Value value;
        //记录左子结点
        public Node left;
        //记录右子结点
        public Node right;

        public Node(Key key, Value value, Node left, Node right) {
            this.key = key;
            this.value = value;
            this.left = left;
            this.right = right;
        }
    }

    //获取树中元素的个数
    public int size() {
        return N;
    }

    //向树中添加元素key-value
    public void put(Key key, Value value) {
        root = put(root, key, value);
    }
    //向指定的树x中添加key-value,并返回添加元素后新的树
    private Node put(Node x, Key key, Value value) {
        //如果x子树为空,
        if (x==null){
            N++;
            return new Node(key,value, null,null);
        }

        //如果x子树不为空
        //比较x结点的键和key的大小:

        int cmp = key.compareTo(x.key);
        if (cmp>0){
            //如果key大于x结点的键,则继续找x结点的右子树
            x.right = put(x.right,key,value);

        }else if(cmp<0){
            //如果key小于x结点的键,则继续找x结点的左子树
            x.left = put(x.left,key,value);
        }else{
            //如果key等于x结点的键,则替换x结点的值为value即可
            x.value = value;
        }
        return x;
    }

    //查询树中指定key对应的value
    public Value get(Key key) {
        return get(root,key);
    }

    //从指定的树x中,查找key对应的值
    public Value get(Node x, Key key) {
        //x树为null
        if (x==null){
            return null;
        }

        //x树不为null

        //比较key和x结点的键的大小
        int cmp = key.compareTo(x.key);
        if (cmp>0){
            //如果key大于x结点的键,则继续找x结点的右子树
            return get(x.right,key);

        }else if(cmp<0){
            //如果key小于x结点的键,则继续找x结点的左子树
            return get(x.left,key);
        }else{
            //如果key等于x结点的键,就找到了键为key的结点,只需要返回x结点的值即可
            return x.value;
        }

    }

    //删除树中key对应的value
    public void delete(Key key) {
        delete(root, key);
    }

    //删除指定树x中的key对应的value,并返回删除后的新树
    public Node delete(Node x, Key key) {
        //x树为null
        if (x==null){
            return null;
        }

        //x树不为null
        int cmp = key.compareTo(x.key);
        if (cmp>0){
            //如果key大于x结点的键,则继续找x结点的右子树
            x.right = delete(x.right,key);
            //delete删除后返回的树,作为x的右子树

        }else if(cmp<0){
            //如果key小于x结点的键,则继续找x结点的左子树
            x.left = delete(x.left,key);
            //delete删除后返回的树,作为x的左子树
        }else{
            //如果key等于x结点的键,完成真正的删除结点动作,要删除的结点就是x;

            //让元素个数-1
            N--;
            //得找到右子树中最小的结点
            if (x.right==null){
                return x.left;
            }
            //假如删除14,14的右子树为空,直接把12替换14就行了,
            //这段代码就是这个意思。

            if (x.left==null){
                return x.right;
            }
            //假如说要删除25,25左子树为空。
            //直接让右子树替换就行。

            //左右子树都不为空,找到右子树,后面一直找左边就行了
            Node minNode = x.right;
            while(minNode.left!=null){
                minNode = minNode.left;
            }
            //通过while循环,找到最小的那个节点

            //删除右子树中最小的结点
            Node n = x.right;
            while(n.left!=null){
                if (n.left.left==null){
                    n.left=null;
                }else{
                    //变换n结点即可
                    n = n.left;
                }
            }

            //让x结点的左子树成为minNode的左子树
            minNode.left = x.left;
            //让x结点的右子树成为minNode的右子树
            minNode.right = x.right;
            //让x结点的父结点指向minNode
            x = minNode;
            //为什么可以这样写?
            //因为上面是递归!,返回值就已经赋值为某树的左节点或者右节点。
            // x.left = delete(x.left,key);
            //x.right = delete(x.right,key);
        }
        return x;
    }
}

package test;

import tree.BinaryTree;

public class BinaryTreeTest {
    public static void main(String[] args) {
        //创建二叉查找树对象
        BinaryTree<Integer, String> tree = new BinaryTree<>();

        //测试插入
        tree.put(1,"张三");
        tree.put(2,"李四");
        tree.put(3,"王五");
        System.out.println("插入完毕后元素的个数:"+tree.size());

        //测试获取
        System.out.println("键2对应的元素是:"+tree.get(2));

        //测试删除

        tree.delete(3);
        System.out.println("删除后的元素个数:"+tree.size());
        System.out.println("删除后键3对应的元素:"+tree.get(3));


    }
}

P88 87_树_二叉查找树创建_查找最小键

在这里插入图片描述

P89 88_树_二叉查找树创建_查找最大键

在这里插入图片描述

//查找整个树中最小的键
    public Key min(){
        return min(root).key;
    }

    //在指定树x中找出最小键所在的结点
    private Node min(Node x){

        //需要判断x还有没有左子结点,如果有,则继续向左找,如果没有,则x就是最小键所在的结点
        if (x.left!=null){
            return min(x.left);
        }else{
            return x;
        }
    }

    //在整个树中找到最大的键
    public Key max(){
        return max(root).key;
    }

    //在指定的树x中,找到最大的键所在的结点
    public Node max(Node x){
        //判断x还有没有右子结点,如果有,则继续向右查找,如果没有,则x就是最大键所在的结点
        if (x.right!=null){
            return max(x.right);
        }else{
            return x;
        }
    }

P90 89_树_二叉树_遍历概述

在这里插入图片描述
在这里插入图片描述

P91 90_树_二叉树_前序遍历

ergodic-遍历
在这里插入图片描述

//获取整个树中所有的键
    public Queue<Key> preErgodic(){
        Queue<Key> keys = new Queue<>();
        preErgodic(root, keys);
        return keys;//获取整个树中所有的键,根据键,可以获得值
    }

    //获取指定树x的所有键,并放到keys队列中
    private void preErgodic(Node x,Queue<Key> keys){
        if (x==null){
            return;
        }

        //把x结点的key放入到keys中
        keys.enqueue(x.key);

        //递归遍历x结点的左子树
        if (x.left!=null){
            preErgodic(x.left,keys);
        }

        //递归遍历x结点的右子树
        if (x.right!=null){
            preErgodic(x.right,keys);
        }

    }
package test;

import linear.Queue;
import tree.BinaryTree;

public class BinaryTreeErgodicTest {
    public static void main(String[] args) {
        //创建树对象
        BinaryTree<String, String> tree = new BinaryTree<>();
        //往树中添加数据
        tree.put("E", "5");
        tree.put("B", "2");
        tree.put("G", "7");
        tree.put("A", "1");
        tree.put("D", "4");
        tree.put("F", "6");
        tree.put("H", "8");
        tree.put("C", "3");

        //遍历
        Queue<String> keys = tree.preErgodic();
        for (String key : keys) {
            String value = tree.get(key);
            System.out.println(key+"----"+value);
        }
    }
}

P92 91_树_二叉树_中序遍历

在这里插入图片描述

P93 92_树_二叉树_后序遍历

在这里插入图片描述

//使用中序遍历获取树中所有的键
    public Queue<Key> midErgodic(){
        Queue<Key> keys = new Queue<>();
        midErgodic(root,keys);
        return keys;
    }

    //使用中序遍历,获取指定树x中所有的键,并存放到key中
    private void midErgodic(Node x,Queue<Key> keys){
        if (x==null){
            return;
        }
        //先递归,把左子树中的键放到keys中
        if (x.left!=null){
            midErgodic(x.left,keys);
        }
        //把当前结点x的键放到keys中
        keys.enqueue(x.key);
        //在递归,把右子树中的键放到keys中
        if(x.right!=null){
            midErgodic(x.right,keys);
        }

    }


    //使用后序遍历,把整个树中所有的键返回
    public Queue<Key> afterErgodic(){
        Queue<Key> keys = new Queue<>();
        afterErgodic(root,keys);
        return keys;
    }

    //使用后序遍历,把指定树x中所有的键放入到keys中
    private void afterErgodic(Node x,Queue<Key> keys){
        if (x==null){
            return ;
        }

        //通过递归把左子树中所有的键放入到keys中
        if (x.left!=null){
            afterErgodic(x.left,keys);
        }
        //通过递归把右子树中所有的键放入到keys中
        if (x.right!=null){
            afterErgodic(x.right,keys);
        }
        //把x结点的键放入到keys中
        keys.enqueue(x.key);
    }
public static void main(String[] args) {
        //创建树对象
        BinaryTree<String, String> tree = new BinaryTree<>();
        //往树中添加数据
        tree.put("E", "5");
        tree.put("B", "2");
        tree.put("G", "7");
        tree.put("A", "1");
        tree.put("D", "4");
        tree.put("F", "6");
        tree.put("H", "8");
        tree.put("C", "3");

        //遍历
        Queue<String> keys = tree.afterErgodic();
        for (String key : keys) {
            String value = tree.get(key);
            System.out.println(key+"----"+value);
        }

    }

P94 93_树_二叉树_层序遍历

层序遍历用到广度优先遍历的思想。
前中后序用到深度优先便利的思想。
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

//使用层序遍历,获取整个树中所有的键
    public Queue<Key> layerErgodic(){
        //定义两个队列,分别存储树中的键和树中的结点
        Queue<Key> keys = new Queue<>();
        Queue<Node> nodes = new Queue<>();

        //默认,往队列中放入根结点
        nodes.enqueue(root);

        while(!nodes.isEmpty()){
            //从队列中弹出一个结点,把key放入到keys中
            Node n = nodes.dequeue();
            keys.enqueue(n.key);
            //判断当前结点还有没有左子结点,如果有,则放入到nodes中
            if (n.left!=null){
                nodes.enqueue(n.left);
            }
            //判断当前结点还有没有右子结点,如果有,则放入到nodes中
            if (n.right!=null){
                nodes.enqueue(n.right);
            }
        }
        return keys;
    }

P95 94_树_二叉树_最大深度问题

在这里插入图片描述
在这里插入图片描述

//获取整个树的最大深度
    public int maxDepth(){
        return maxDepth(root);
    }


    //获取指定树x的最大深度
    private int maxDepth(Node x){
        if (x==null){
            return 0;
        }
        //x的最大深度
        int max=0;
        //左子树的最大深度
        int maxL=0;
        //右子树的最大深度
        int maxR=0;

        //计算x结点左子树的最大深度
        if (x.left!=null){
            maxL = maxDepth(x.left);
        }
        //计算x结点右子树的最大深度
        if (x.right!=null){
            maxR = maxDepth(x.right);
        }
        //比较左子树最大深度和右子树最大深度,取较大值+1即可

        max = maxL>maxR?maxL+1:maxR+1;

        return max;
    }
package test;

import tree.BinaryTree;

public class BinaryTreeMaxDepthTest {
    public static void main(String[] args) {
        //创建树对象
        BinaryTree<String, String> tree = new BinaryTree<>();
        //往树中添加数据
        tree.put("E", "5");
        tree.put("B", "2");
        tree.put("G", "7");
        tree.put("A", "1");
        tree.put("D", "4");
        tree.put("F", "6");
        tree.put("H", "8");
        tree.put("C", "3");

        int maxDepth = tree.maxDepth();
        System.out.println(maxDepth);
    }
}

P96 95_树_二叉树_折纸问题

在这里插入图片描述
在这里插入图片描述

在这里插入图片描述
在这里插入图片描述
利用层序遍历的思想。

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值