树(基础部分)

news2024/9/22 13:36:03

章节目录:

    • 一、二叉树
      • 1.1 为什么要使用树?
      • 1.2 树的常用术语
      • 1.3 二叉树概念
      • 1.4 二叉树应用
    • 二、顺序存储二叉树
      • 2.1 概述
      • 2.2 基本应用
    • 三、线索化二叉树
      • 3.1 问题引出
      • 3.2 概述
      • 3.3 基本应用
    • 四、结束语

一、二叉树

1.1 为什么要使用树?

  • 数组存储方式:

    • 优点:通过下标方式访问元素,速度快,并且对于有序数组,还可使用二分查找提高检索速度。
    • 缺点:如果要检索具体某个值,或者插入值(按一定顺序)会整体移动效率较低
  • 链式存储方式:

    • 优点:在一定程度上对数组存储方式有优化,比如:插入一个数值节点,只需要将插入节点,链接到链表中即可,删除效率也很好
    • 缺点:在进行检索时,效率仍然较低,比如:检索某个值,需要从头节点开始遍历
  • 存储方式:

    • 能提高数据存储,读取的效率,比如利用二叉排序树(Binary Sort Tree),既可以保证数据的检索速度,同时也可以保证数据的插入,删除,修改的速度

    • 示意图

在这里插入图片描述

  • 总结:不难看出,上面通过二叉排序树来存储数据,效率相较于数组及链式都有了一定程度的提升。

1.2 树的常用术语

在这里插入图片描述

  • 节点:树中的一个连接点

  • 根节点仅有一个):非空树中无前驱节点的节点,称之为根节点。

  • 父节点:若一个节点含有子节点,则这个节点成为其子节点的父节点。

  • 子节点:一个节点含有的子树的根节点成为该节点的子节点。

  • 叶子节点 (没有子节点的节点):一棵树中没有子节点的节点成为叶子节点。

  • 节点的权:节点的具体值

  • 路径(从 root 节点找到该节点的路线):从根节点到某一个具体节点所走过的路。

  • :根节点在1层,其它任一节点的层数是其父节点的层数加1

  • 子树:只要包含了一个节点,就得包含这个节点下的所有节点。

  • 树的高度(最大层数):树内所有节点高度的最大值,也就是根节点的高度,也就是树的层数。

  • 森林 (多颗子树构成森林):森林是由若干棵树组成,可以将森林中的每棵树的根节点看作是兄弟。

1.3 二叉树概念

树有很多种,每个节点最多只能有两个子节点的一种形式称为二叉树

在这里插入图片描述

  • 二叉树的子节点分为节点和节点。

在这里插入图片描述

  • 如果该二叉树的所有叶子节点都在最后一层,并且节点总数= 2^n -1 , n 为层数,则我们称为满二叉树

在这里插入图片描述

  • 如果该二叉树的所有叶子节点都在最后一层或者倒数第二层,而且最后一层的叶子节点在左边连续,倒数第二层的叶子节点在右边连续,我们称为完全二叉树

1.4 二叉树应用

需求:使用前序,中序和后序对二叉树进行遍历查找,并编写删除节点方法。

  • 前序遍历: 先输出父节点,再遍历左子树和右子树。(父节点 -> 左子树 -> 右子树)

  • 中序遍历: 先遍历左子树,再输出父节点,再遍历右子树。(左子树 -> 父节点 -> 右子树)

  • 后序遍历: 先遍历左子树,再遍历右子树,最后输出父节点。(左子树 -> 右子树 -> 父节点

  • 小结: 看输出父节点的顺序,就确定是前序,中序还是后序。

  • 代码示例

public class BinaryTreeDemo {

    public static void main(String[] args) {
        // 1.创建一棵二叉树。
        BinaryTree binaryTree = new BinaryTree();

        // 2.创建节点。
        Node root = new Node(1, "data1");
        Node node2 = new Node(2, "data2");
        Node node3 = new Node(3, "data3");
        Node node4 = new Node(4, "data4");
        Node node5 = new Node(5, "data5");

        // 3.手动给二叉树赋值。
        root.setLeft(node2);
        root.setRight(node3);
        node3.setRight(node4);
        node3.setLeft(node5);
        binaryTree.setRoot(root);

        // 4.测试[遍历]。
        System.out.println("前序遍历结果如下:");
        binaryTree.preOrder();
        // Node:id=1,2,3,5,4

        System.out.println();
        System.out.println("中序遍历结果如下:");
        binaryTree.infixOrder();
        // Node:id=2,1,5,3,4

        System.out.println();
        System.out.println("后序遍历结果如下:");
        binaryTree.postOrder();
        // Node:id=2,5,4,3,1

        // 5.测试[查找]。
        // 前序遍历查找的次数 :4
        System.out.println();
        System.out.println("前序遍历查找结果如下:");
        int id = 5;
        Node res = binaryTree.preOrderSearch(id);
        if (null != res) {
            System.out.printf(
                    "preOrderSearch result: id=[%d], data=[%s]\n",
                    res.getId(),
                    res.getData()
            );
        } else {
            System.out.printf("preOrderSearch not found id=[%d] node.\n", id);
        }

        // 中序遍历查找的次数 :3
        System.out.println();
        System.out.println("中序遍历查找结果如下:");
        Node res1 = binaryTree.infixOrderSearch(id);
        if (null != res1) {
            System.out.printf(
                    "infixOrderSearch result: id=[%d], data=[%s]\n",
                    res1.getId(),
                    res1.getData()
            );
        } else {
            System.out.printf("infixOrderSearch not found id=[%d] node.\n", id);
        }

        // 后序遍历查找的次数 :2
        System.out.println();
        System.out.println("后序遍历查找结果如下:");
        Node res2 = binaryTree.postOrderSearch(id);
        if (null != res2) {
            System.out.printf(
                    "postOrderSearch result: id=[%d], data=[%s]\n",
                    res2.getId(),
                    res2.getData()
            );
        } else {
            System.out.printf("postOrderSearch not found id=[%d] node.\n", id);
        }

        // 6.测试[删除]。
        System.out.println();
        System.out.println("删除前,前序遍历结果如下:");
        binaryTree.preOrder();
        // Node:id=1,2,3,5,4

        // 删除id为5的节点。
        binaryTree.del(id);

        System.out.println("删除后,前序遍历结果如下:");
        binaryTree.preOrder();
        // Node:id=1,2,3,4
    }
}


/**
 * 定义二叉树。
 */
class BinaryTree {

    /**
     * 根节点。
     */
    private Node root;

    public void setRoot(Node root) {
        this.root = root;
    }

    public void preOrder() {
        if (null != this.root) {
            this.root.preOrder();
        } else {
            System.out.println("preOrder error : binary tree is null.");
        }
    }

    public void infixOrder() {
        if (null != this.root) {
            this.root.infixOrder();
        } else {
            System.out.println("infixOrder error : binary tree is null.");
        }
    }

    public void postOrder() {
        if (null != this.root) {
            this.root.postOrder();
        } else {
            System.out.println("postOrder error : binary tree is null.");
        }
    }

    public Node preOrderSearch(int id) {
        if (null != this.root) {
            return root.preOrderSearch(id);
        } else {
            return null;
        }
    }

    public Node infixOrderSearch(int id) {
        if (null != this.root) {
            return root.infixOrderSearch(id);
        } else {
            return null;
        }
    }

    public Node postOrderSearch(int id) {
        if (null != this.root) {
            return this.root.postOrderSearch(id);
        } else {
            return null;
        }
    }

    public void del(int id) {
        if (null != this.root) {
            // 若只有一个根节点时,直接进行判断。
            if (id == this.root.getId()) {
                root = null;
            } else {
                this.root.del(id);
            }
        } else {
            System.out.println("del node error : binary tree is null.");
        }
    }
}


/**
 * 定义节点。
 */
@Setter
@Getter
class Node {
    private int id;
    private Object data;
    private Node left;
    private Node right;

    public Node(int id, Object data) {
        this.id = id;
        this.data = data;
    }

    @Override
    public String toString() {
        return "Node:[id=" + this.id + ", data=" + this.data + "]";
    }

    /**
     * 1.前序遍历。
     */
    public void preOrder() {
        // 输出父节点。
        System.out.println(this);
        if (null != this.left) {
            this.left.preOrder();
        }
        if (null != this.right) {
            this.right.preOrder();
        }
    }

    /**
     * 2.中序遍历。
     */
    public void infixOrder() {
        if (null != this.left) {
            this.left.infixOrder();
        }
        // 输出父节点。
        System.out.println(this);
        if (null != this.right) {
            this.right.infixOrder();
        }
    }

    /**
     * 3.后序遍历。
     */
    public void postOrder() {
        if (null != this.left) {
            this.left.postOrder();
        }
        if (null != this.right) {
            this.right.postOrder();
        }
        // 输出父节点。
        System.out.println(this);
    }

    // -----------分割线-----------

    /**
     * 1.前序查找。
     *
     * @param id id
     * @return {@link Node}
     */
    public Node preOrderSearch(int id) {
        if (id == this.getId()) {
            return this;
        }
        Node res = null;
        // 向左递归。
        if (null != this.left) {
            res = this.left.preOrderSearch(id);
        }

        // 左子树找到。
        if (null != res) {
            return res;
        }

        // 向右递归。
        if (null != this.right) {
            res = this.right.preOrderSearch(id);
        }
        return res;
    }

    /**
     * 2.中序查找。
     *
     * @param id id
     * @return {@link Node}
     */
    public Node infixOrderSearch(int id) {
        // 左递归。
        Node res = null;
        if (null != this.left) {
            res = this.left.infixOrderSearch(id);
        }
        if (null != res) {
            return res;
        }
        // 找到则返回。
        if (id == this.getId()) {
            return this;
        }
        // 右递归。
        if (null != this.right) {
            res = this.right.infixOrderSearch(id);
        }
        return res;
    }

    /**
     * 3.后序查找。
     *
     * @param id id
     * @return {@link Node}
     */
    public Node postOrderSearch(int id) {
        Node res = null;
        if (null != this.left) {
            res = this.left.postOrderSearch(id);
        }
        if (null != res) {
            return res;
        }

        if (null != this.right) {
            res = this.right.postOrderSearch(id);
        }
        if (null != res) {
            return res;
        }

        if (id == this.getId()) {
            return this;
        }
        return res;
    }

    // -----------分割线-----------

    /**
     * 删除节点。
     *
     * <p>
     * 思路分析如下:
     * 1. 因为我们的二叉树是[单向]的,所以我们是判断当前节点的子节点是否需要删除节点,而不能去判断当前这个节点是不是需要删除节。
     * 2. 如果当前节点的左子节点不为空,并且左子节点就是要删除节点,就将this.left = null; 并且就返回(结束递归删除)。
     * 3. 如果当前节点的右子节点不为空,并且右子节点就是要删除节点,就将this.right= null;并且就返回(结束递归删除)。
     * 4. 如果第2和第3步没有删除节点,那么我们就需要向左子树进行递归删除。
     * 5. 如果第4步也没有删除节点,则应当向右子树进行递归删除。
     * <p>
     *
     * @param id id
     */
    public void del(int id) {
        if (null != this.left && id == this.left.getId()) {
            this.left = null;
            return;
        }

        if (null != this.right && id == this.right.getId()) {
            this.right = null;
            return;
        }

        // 向左,向右进行递归删除。
        if (null != this.left) {
            this.left.del(id);
        }
        if (null != this.right) {
            this.right.del(id);
        }
    }
}

二、顺序存储二叉树

2.1 概述

  • 说明:从数据存储来看,数组存储方式和树的存储方式可以相互转换,即数组可以转换成树,树也可以转换成数组

  • 示意图

  • 特点(n : 表示二叉树中的第几个元素):
    • 顺序二叉树通常只考虑完全二叉树
    • 第 n 个元素的子节点为 2 * n + 1
    • 第 n 个元素的子节点为 2 * n + 2
    • 第 n 个元素的节点为 (n-1) / 2

2.2 基本应用

需求: 给定一个数组 {1,2,3,4,5,6,7},要求以二叉树前序遍历的方式进行遍历。 前序遍历的结果应当为1,2,4,5,3,6,7。

public class ArrBinaryTreeDemo {

    public static void main(String[] args) {
        int[] array = {1, 2, 3, 4, 5, 6, 7};
        ArrBinaryTree arrBinaryTree = new ArrBinaryTree(array);
        arrBinaryTree.preOrder();
        // 1,2,4,5,3,6,7
    }

}

class ArrBinaryTree {

    /**
     * 存储数据节点的数组。
     */
    private final int[] array;

    public ArrBinaryTree(int[] array) {
        this.array = array;
    }

    /**
     * 重载 preOrder()。
     */
    public void preOrder() {
        // 固定从下标 0 开始。
        this.preOrder(0);
    }

    /**
     * 前序遍历。
     *
     * @param index 数组的下标
     */
    public void preOrder(int index) {

        if (array == null || array.length == 0) {
            System.out.println("preOrder error : binary tree is null.");
        }

        if (null != array) {
            // 输出当前这个元素。
            System.out.println(array[index]);

            // 向左递归遍历。
            if ((index * 2 + 1) < array.length) {
                preOrder(2 * index + 1);
            }
            // 向右递归遍历。
            if ((index * 2 + 2) < array.length) {
                preOrder(2 * index + 2);
            }
        }
    }
}

三、线索化二叉树

3.1 问题引出

  • 示意图

在这里插入图片描述

  • 当我们对上面的二叉树进行中序遍历时,数列为 {8, 3, 10, 1, 6, 14 }。
  • 但是 6, 8, 10, 14 这几个节点的左右指针,并没有完全的利用上
  • 如果我们希望充分的利用 各个节点的左右指针, 让各个节点可以指向自己的前后节点,怎么办?
  • 解决方案线索二叉树

3.2 概述

  • n 个节点的二叉链表中含有 n+1 (参考公式: 2n-(n-1)=n+1) 个空指针域。利用二叉链表中的空指针域,存放指向该节点在某种遍历次序下的前驱和后继节点的指针(这种附加的指针称为"线索")。
  • 这种加上了线索的二叉链表称为线索链表,相应的二叉树称为线索二叉树(Threaded BinaryTree),根据线索性质的不同,线索二叉树可分为序线索二叉树、序线索二叉树和序线索二叉树三种
  • 一个节点的前一个节点,称为前驱节点。
  • 一个节点的后一个节点,称为后继节点。

3.3 基本应用

需求:将下面的二叉树,进行中序线索二叉树。中序遍历的数列结果为 {8, 3, 10, 1, 14, 6}。

  • 示意图

在这里插入图片描述

  • left 指向的是左子树,也可能是指向的前驱节点。(比如:节点①-left 指向的左子树, 而 节点⑩-left 指向的就是前驱节点。)

  • right 指向的是右子树,也可能是指向的后继节点。(比如:节点①-right 指向的是右子树,而节点⑩-right 指向的是后继节点。)

  • 代码示例

public class ThreadedBinaryTreeDemo {
    
    public static void main(String[] args) {

        // 准备节点。
        Node1 root = new Node1(1, "data1");
        Node1 node3 = new Node1(3, "data3");
        Node1 node6 = new Node1(6, "data6");
        Node1 node8 = new Node1(8, "data8");
        Node1 node10 = new Node1(10, "data10");
        Node1 node14 = new Node1(14, "data14");

        // 手动创建二叉树。
        root.setLeft(node3);
        root.setRight(node6);
        node3.setLeft(node8);
        node3.setRight(node10);
        node6.setLeft(node14);

        // 中序线索化。
        ThreadedBinaryTree threadedBinaryTree = new ThreadedBinaryTree();
        threadedBinaryTree.setRoot(root);
        threadedBinaryTree.threadNodes();

        // 以节点⑩来进行测试。
        int leftId = node10.getLeft().getId();
        int rightId = node10.getRight().getId();
        System.out.println("节点⑩的前驱节点id=[" + leftId + "], 后继节点id=[" + rightId + "]");
        // 节点⑩的前驱节点id=[3], 后继节点id=[1]

        System.out.println();
        System.out.println("使用线索化二叉树遍历结果如下:");
        threadedBinaryTree.foreach();
        // 使用线索化二叉树遍历结果如下:
        // Node1:[id=8, data=data8]
        // Node1:[id=3, data=data3]
        // Node1:[id=10, data=data10]
        // Node1:[id=1, data=data1]
        // Node1:[id=14, data=data14]
        // Node1:[id=6, data=data6]
    }
}


/**
 * 定义线索二叉树。
 */
class ThreadedBinaryTree {

    /**
     * 根节点。
     */
    private Node1 root;

    /**
     * 为了实现线索化,需要创建一个指向当前节点的前驱节点指针。
     * 递归线索化时,pre总是保留前一个节点。
     */
    private Node1 pre = null;

    public void setRoot(Node1 root) {
        this.root = root;
    }


    /**
     * 中序遍历线索化二叉树。
     */
    public void foreach() {
        Node1 cur = root;
        while (null != cur) {
            // 找到线索化后的节点。(第一个找到的是节点⑧)
            // 0:表示指向的[左子树]。
            while (0 == cur.getLeftType()) {
                // 左移。
                cur = cur.getLeft();
            }

            // 输出当前节点。
            System.out.println(cur);

            // 如果当前节点的右指针指向的是后继节点,就一直输出。
            while (1 == cur.getRightType()) {
                // 获取后继节点。
                cur = cur.getRight();
                System.out.println(cur);
            }
            // 替换遍历节点。
            cur = cur.getRight();
        }
    }

    /**
     * 重载线索化方法。(便于调用)。
     */
    public void threadNodes() {
        this.threadNodes(root);
    }

    /**
     * 将树中的节点进行线索化。
     *
     * @param node 节点
     */
    private void threadNodes(Node1 node) {
        if (null == node) {
            return;
        }

        // 1.先线索化[左子树]。
        threadNodes(node.getLeft());

        // 2.线索化[当前节点]。
        // 2.1 先处理当前节点的[前驱节点] --- (此处以节点⑧为例,他的left=null,则leftType=1)。
        if (null == node.getLeft()) {
            // 左指针指向前驱节点,并修改左指针类型,指向前驱节点。
            node.setLeft(pre);
            node.setLeftType(1);
        }

        // 2.2 再处理[后继节点]。
        if (null != pre && null == pre.getRight()) {
            pre.setRight(node);
            pre.setRightType(1);
        }
        // 处理完每一个节点后,让当前节点成为下一个节点的前驱节点。
        pre = node;

        // 3.线索化[右子树]。
        threadNodes(node.getRight());
    }
}


/**
 * 定义节点。
 */
@Setter
@Getter
class Node1 {
    private int id;
    private Object data;
    private Node1 left;
    private Node1 right;

    /**
     * 0 表示指向的[左子树]。
     * 1 表示指向[前驱节点]。
     */
    private int leftType;

    /**
     * 0 表示指向的[右子树]。
     * 1 表示指向[后继节点]。
     */
    private int rightType;

    public Node1(int id, Object data) {
        this.id = id;
        this.data = data;
    }

    @Override
    public String toString() {
        return "Node1:[id=" + this.id + ", data=" + this.data + "]";
    }
}

四、结束语


“-------怕什么真理无穷,进一寸有一寸的欢喜。”

微信公众号搜索:饺子泡牛奶

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/177173.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

MP-2平面烟雾气体传感器介绍

MP-2平面烟雾气体传感器简介MP-2烟雾检测气体传感器采用多层厚膜制造工艺&#xff0c;在微型Al2O3陶瓷基片的两面分别制作加热器和金属氧化物半导体气敏层&#xff0c;封装在金属壳体内。当环境空气中有被检测气体存在时传感器电导率发生变化&#xff0c;该气体的浓度越高&…

【数据库概论】3.1 SQL简述、数据定义和索引

第三章 关系数据库标准语言SQL 目录第三章 关系数据库标准语言SQL3.1 SQL概述3.1.1 产生与发展3.1.2 SQL的特点3.1.3 SQL的基本概念3.2 数据库实例3.3 数据定义3.3.1 模式的定义和删除3.2.2基本表的定义、删除和修改1.常见数据类型2.定义基本表3.修改基本表4.删除基本表5.模式和…

英语学习打卡day3

2023.1.22 1.mariner n.水手 2.formation n.队形;组成;形成 n.形状;形式样式;表格 the formation of landscapes Keep the formation 保持队形 The chairs were arranged in the form of circle. fill in the form 填写表格 formal adj.正式的inform 通知deform 变形uniform 统…

06_平台总线匹配规则,自己搭建总线xbus

总结 bus_register() 自己创建平台总线 /sys/bux/xxx device_register() 对平台总线加入dev /sys/bus/xxx/dev driver_register() 对平台总线加入drv /sys/bus/xxx/drv 两个相匹配的时候 直接调用drv->probe 函数 进行基本的class_create() device_create()等 创建设备文件…

TryHackMe-红队-07_武器化

Weaponization 了解并探索常见的红队武器化技术。您将学习如何使用业内常见的方法来构建自定义有效负载&#xff0c;以获得初始访问权限。 什么是武器化 武器化是网络杀伤链模式的第二阶段。在此阶段&#xff0c;攻击者使用可交付的有效负载&#xff08;如word文档&#xff…

七、python-PySpark篇(黑马程序猿-python学习记录)

1. pyspark定义 2. 下载 点击右下角版本 点击解释器设置 点击号 搜索pyspark 选择pyspark 勾选选项 在输入框中输入 -i https://pypi.tuna.tsinghua.edu.cn/simple 点击安装软件包 提示正在安装 等一两分钟就能安装完毕 3. 获取PySpark版本号 # 导包 from pyspark import Spar…

树,二叉树的认识

1.树概念及结构 1.1树的概念 注意&#xff1a;树形结构中&#xff0c;子树之间不能有交集&#xff0c;否则就不是树形结构 1.2 树的相关概念 1.3 树的表示 树结构相对线性表就比较复杂了&#xff0c;要存储表示起来就比较麻烦了&#xff0c;既然保存值域&#xff0c;也要保存…

(18)go-micro微服务ELK介绍

文章目录一 什么是ELK二 Beats的六种工具三 ELK系统的特点四 ELKbeats系统架构五 ELK优点六 最后一 什么是ELK ELK是三个[开源软件]的缩写&#xff0c;分别表示&#xff1a;Elasticsearch , Logstash, Kibana , 它们都是开源软件&#xff0c;新增了一个Beats。 Elasticsearch …

几种觉排序优劣

冒泡排序 比较相邻的元素。如果第一个比第二个大&#xff0c;就交换他们两个。 对每一对相邻元素做同样的工作&#xff0c;从开始第一对到结尾的最后一对。在这一点&#xff0c;最后的元素应该会是最大的数。 针对所有的元素重复以上的步骤&#xff0c;除了最后一个。 持…

23. 异常处理机制

1. 异常 即便 python 程序的语法是正确的&#xff0c;在运行它的时候&#xff0c;也有可能发生错误。运行期检测到的错误被称为异常。 # int不能与str相加, 触发异常 print(22) # 0 不能作为除数, 触发异常 print(1/0) # sum未定义, 触发异常 print(num)异常以不同的类型出现…

【JavaSE专栏4】关键字、标识符和命名规范

作者主页&#xff1a;Designer 小郑 作者简介&#xff1a;Java全栈软件工程师一枚&#xff0c;来自浙江宁波&#xff0c;负责开发管理公司OA项目&#xff0c;专注软件前后端开发&#xff08;Vue、SpringBoot和微信小程序&#xff09;、系统定制、远程技术指导。CSDN学院、蓝桥云…

k8s部署elk+filebeat。springCloud集成elk+filebeat+kafka+zipkin实现多个服务日志链路追踪聚合到es

一、目的 如今2023了&#xff0c;大多数javaweb架构都是springboot微服务&#xff0c;一个前端功能请求后台可能是多个不同的服务共同协做完成的。例如用户下单功能&#xff0c;js转发到后台网关gateway服务&#xff0c;然后到鉴权spring-sercurity服务&#xff0c;然后到业务…

mysql数据库管理-GTID详解

一、GTID概述 1 sql线程执行的事件也可以通过log_slave_updates系统变量来决定是否写入自己的二进制文件中&#xff0c;这是可以用于级联复制的场景。 GTID是MYSQL5.6新增的特性&#xff0c;GTID&#xff08;Global Transaction Identifier&#xff09;全称为全局事务标示符…

17种编程语言实现排序算法-计数排序

开源地址 https://gitee.com/lblbc/simple-works/tree/master/sort/ 覆盖语言&#xff1a;C、C、C#、Java、Kotlin、Dart、Go、JavaScript(JS)、TypeScript(TS)、ArkTS、swift、PHP。 覆盖平台&#xff1a;安卓(Java、Kotlin)、iOS(SwiftUI)、Flutter(Dart)、Window桌面(C#)、…

力扣sql简单篇练习(五)

力扣sql简单篇练习(五) 1 游戏玩法分析 I 1.1 题目内容 1.1.1 基本题目信息 1.1.2 示例输入输出 1.2 示例sql语句 # 第一次登录平台的日期就代表是时间靠前的日期 # 窗口函数是Mysql8版本后才能使用 SELECT e.player_id,e.event_date first_login FROM (SELECT player_id,e…

五、python-地图可视化篇(黑马程序猿-python学习记录)

黑马程序猿的python学习视频&#xff1a;https://www.bilibili.com/video/BV1qW4y1a7fU/ 目录 1. 基础地图 2. 设置分段 1. 基础地图 from pyecharts.charts import Map # 准备地图对象 map Map() # 准备数据 data[ ("北京",99), ("上海",199), ("…

17种编程语言实现排序算法-堆排序

开源地址 https://gitee.com/lblbc/simple-works/tree/master/sort/ 覆盖语言&#xff1a;C、C、C#、Java、Kotlin、Dart、Go、JavaScript(JS)、TypeScript(TS)、ArkTS、swift、PHP。 覆盖平台&#xff1a;安卓(Java、Kotlin)、iOS(SwiftUI)、Flutter(Dart)、Window桌面(C#)、…

Maplab 2.0发布:多传感器融合的SLAM框架,支持多机器人、语义回环检测功能

摘要 将多种传感器和深度学习集成到SLAM系统中是当前研究的重要领域。多模态是一块跳板&#xff0c;既可以在挑战场景下增强鲁棒性&#xff0c;又可以解决不同传感器配置的多机系统建图问题。Maplab 2.0提供了一个更加通用的开源平台&#xff0c;最初的Maplab用于创建和管理视…

5-3中央处理器-数据通路的功能和基本结构

文章目录一.功能二.基本结构三.数据流向&#xff08;一&#xff09;内部单总线方式1.寄存器之间的数据传送2.主存与CPU之间的数据传送3.执行算术或逻辑运算&#xff08;二&#xff09;专用数据通路方式一.功能 数据在功能部件之间传送的路径称为数据通路。路径上的部件称为数据…

合宙ESP32C3上手使用

概述经典款是有ch343 ttl 转usb 需要安装驱动 GPIO20/21新款使用usb 直连不需要驱动 USB GPIO18/19ESP32C3 是ESP-RISC-V CPU 是基于 RISC-V ISA 的 32 位内核&#xff0c;包括基本整数 (I)&#xff0c;乘法/除法 (M) 和压缩 (C) 标准扩展。ESP-RISC-V CPU 内核具有 4 级有序标…