Java二叉树的遍历以及最大深度问题

Java学习+面试指南:https://javaxiaobear.cn

1、树的相关概念

1、树的基本定义

树是我们计算机中非常重要的一种数据结构,同时使用树这种数据结构,可以描述现实生活中的很多事物,例如家谱、单位的组织架构、等等。
树是由n(n>=1)个有限结点组成一个具有层次关系的集合。把它叫做“树”是因为它看起来像一棵倒挂的树,也就是说它是根朝上,而叶朝下的。

树具有以下特点:

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

2、相关术语

1、结点的度

一个结点含有的子树的个数称为该结点的度;

2、叶子结点

度为0的结点称为叶结点,也可以叫做终端结点

3、分支结点

度不为0的结点称为分支结点,也可以叫做非终端结点

4、结点的层次

从根结点开始,根结点的层次为1,根的直接后继层次为2,以此类推

5、结点的层序编号

将树中的结点,按照从上层到下层,同层从左到右的次序排成一个线性序列,把他们编成连续的自然数。

6、树的度

树中所有结点的度的最大值

7、树的高度(深度)

树中结点的最大层次

8、森林

m(m>=0)个互不相交的树的集合,将一颗非空树的根结点删去,树就变成一个森林;给森林增加一个统一的根结点,森林就变成一棵树

9、孩子结点

一个结点的直接后继结点称为该结点的孩子结点

10、双亲结点(父结点)

一个结点的直接前驱称为该结点的双亲结点

11、兄弟结点

同一双亲结点的孩子结点间互称兄弟结点

2、二叉树

二叉树就是度不超过2的树(每个结点最多有两个子结点)

1、相关二叉树

1、满二叉树

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

2、完全二叉树

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

2、创建二叉查找树

1、API设计
  • 结点类

    类名Node<Key,Value>
    构造方法Node(Key key, Value value, Node left, Node right):创建Node对象
    成员变量1.public Node left:记录左子结点
    2.public Node right:记录右子结点
    3.public Key key:存储键
    4.public Value value:存储值
  • 二叉树

    类名BinaryTree<Key,value>
    构造方法BinaryTree():创建BinaryTree对象
    成员变量1.private Node root:记录根结点
    2.private int N:记录树中元素的个数
    成员方法1. public void put(Key key,Value value):向树中插入一个键值对
    2.private Node put(Node x, Key key, Value val):给指定树x上,添加键一个键值对,并返回添加后的新树
    3.public Value get(Key key):根据key,从树中找出对应的值
    4.private Value get(Node x, Key key):从指定的树x中,找出key对应的值
    5.public void delete(Key key):根据key,删除树中对应的键值对
    6.private Node delete(Node x, Key key):删除指定树x上的键为key的键值对,并返回删除后的新树
    7.public int size():获取树中元素的个数
1、put方法实现思路
  • 如果当前树中没有任何一个结点,则直接把新结点当做根结点使用

  • 如果当前树不为空,则从根结点开始:

    • 如果新结点的key小于当前结点的key,则继续找当前结点的左子结点;

    • 如果新结点的key大于当前结点的key,则继续找当前结点的右子结点;

    • 如果新结点的key等于当前结点的key,则树中已经存在这样的结点,替换该结点的value值即可。

/**
     * 给指定树x上,添加键一个键值对,并返回添加后的新树
     * @param x 树节点
     * @param key 键
     * @param val 值
     * @return Node
     */
public Node<Key, Value> put(Node<Key,Value> x, Key key, Value val){
    //当树为空时,该节点为根节点
    if(null == x){
        size++;
        return new Node<>(key, val, null, null);
    }
    int compare = key.compareTo(x.key);
    //如果compare > 0 ,则 key > x.key;继续x的右子节点
    if(0 < compare){
        x.right = put(x.right,key,val);
    }else if(0 > compare){
        //如果compare < 0 ,则 key < x.key;继续x的左子节点
        x.left = put(x.left,key,val);
    }else {
        //如果compare = 0 ,则 key = x.key;替换x.value的值
        x.value = val;
    }
    return x;
}
2、get方法实现思路

从根节点开始:

  • 如果要查询的key小于当前结点的key,则继续找当前结点的左子结点;
  • 如果要查询的key大于当前结点的key,则继续找当前结点的右子结点;
  • 如果要查询的key等于当前结点的key,则树中返回当前结点的value。
/**
     * 从指定的树x中,找出key对应的值
     * @param x 节点
     * @param key 键
     * @return 节点
     */
public Value getNode(Node<Key,Value> x, Key key){
    if (null == x){
        return null;
    }
    int compare = key.compareTo(x.key);
    if(0 < compare){
        return getNode(x.right,key);
    }else if(0 > compare){
        return getNode(x.left, key);
    }else {
        return x.value;
    }
}
3、delete方法的实现思路
  • 找到被删除结点;
  • 找到被删除结点右子树中的最小结点minNode
  • 删除右子树中的最小结点
  • 让被删除结点的左子树称为最小结点minNode的左子树,让被删除结点的右子树称为最小结点minNode的右子树
  • 让被删除结点的父节点指向最小结点minNode
/**
     * 删除指定树x中的key对应的value,并返回删除后的新树
     * @param x
     * @param key
     * @return
     */
public Node<Key,Value> delete(Node<Key, Value> x, Key key){
    if (null == x){
        return null;
    }
    int compare = key.compareTo(x.key);
    if(0 < compare){
        x.right = delete(x.right,key);
    }else if(0 > compare){
        x.left = delete(x.left,key);
    }else {
        //个数-1
        size--;
        //新结点的key等于当前结点的key,当前x就是要删除的结点
        if(x.right == null){
            return x.left;
        }if(x.left == null){
            return x.right;
        }
        //左右子结点都存在的情况下,找右子树最小的节点
        Node<Key, Value> minRight = x.right;
        while (null != minRight.left){
            minRight = minRight.left;
        }
        Node<Key, Value> node = x.right;
        while (node.left != null) {
            if (node.left.left == null) {
                node.left = null;
            } else {
                node = node.left;
            }
        }
        //让被删除结点的左子树称为最小结点minNode的左子树,让被删除结点的右子树称为最小结点minNode的右子树
        minRight.left = x.left;
        minRight.right = x.right;
        //让被删除结点的父节点指向最小结点minNode
        x = minRight;
    }
    return x;
}
4、完整代码
package com.xiaobear.BinaryTree;

/**
 * @Author xiaobear
 * @date 2021年07月30日 13:50
 * @Description 二叉树
 */
public class BinaryTree<Key extends Comparable<Key>,Value> {

    /**
     * 根节点
     */
    private Node<Key,Value> root;
    /**
     * 节点数量
     */
    private int size;

    public void put(Key key, Value val){
        root = put(root,key,val);
    }

    /**
     * 给指定树x上,添加键一个键值对,并返回添加后的新树
     * @param x 树节点
     * @param key 键
     * @param val 值
     * @return Node
     */
    public Node<Key, Value> put(Node<Key,Value> x, Key key, Value val){
        //当树为空时,该节点为根节点
       if(null == x){
           size++;
           return new Node<>(key, val, null, null);
       }
       int compare = key.compareTo(x.key);
       //如果compare > 0 ,则 key > x.key;继续x的右子节点
        if(0 < compare){
            x.right = put(x.right,key,val);
        }else if(0 > compare){
            //如果compare < 0 ,则 key < x.key;继续x的左子节点
            x.left = put(x.left,key,val);
        }else {
            //如果compare = 0 ,则 key = x.key;替换x.value的值
            x.value = val;
        }
        return x;
    }

    /**
     * 根据key,从树中找出对应的值
     * @param key 键
     */
    public Value getNode(Key key){
        return getNode(root,key);
    }

    /**
     * 从指定的树x中,找出key对应的值
     * @param x 节点
     * @param key 键
     * @return 节点
     */
    public Value getNode(Node<Key,Value> x, Key key){
        if (null == x){
            return null;
        }
        int compare = key.compareTo(x.key);
        if(0 < compare){
            return getNode(x.right,key);
        }else if(0 > compare){
            return getNode(x.left, key);
        }else {
            return x.value;
        }
    }

    public void delete(Key key){
        root = delete(root, key);
    }

    /**
     * 删除指定树x中的key对应的value,并返回删除后的新树
     * @param x
     * @param key
     * @return
     */
    public Node<Key,Value> delete(Node<Key, Value> x, Key key){
        if (null == x){
            return null;
        }
        int compare = key.compareTo(x.key);
        if(0 < compare){
            x.right = delete(x.right,key);
        }else if(0 > compare){
            x.left = delete(x.left,key);
        }else {
            //个数-1
            size--;
            //新结点的key等于当前结点的key,当前x就是要删除的结点
            if(x.right == null){
                return x.left;
            }if(x.left == null){
                return x.right;
            }
            //左右子结点都存在的情况下,找右子树最小的节点
            Node<Key, Value> minRight = x.right;
            while (null != minRight.left){
                minRight = minRight.left;
            }
            Node<Key, Value> node = x.right;
            while (node.left != null) {
                if (node.left.left == null) {
                    node.left = null;
                } else {
                    node = node.left;
                }
            }
            //让被删除结点的左子树称为最小结点minNode的左子树,让被删除结点的右子树称为最小结点minNode的右子树
            minRight.left = x.left;
            minRight.right = x.right;
            //让被删除结点的父节点指向最小结点minNode
            x = minRight;
        }
        return x;
    }

    public int size(){
        return size;
    }



    /**
     * 节点类
     * @param <Key>
     * @param <Value>
     */
    private class Node<Key,Value>{
        public Key key;

        public Value value;

        public Node<Key,Value> left;

        public Node<Key, Value> right;

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

测试代码

public class BinaryTreeTest {

    public static void main(String[] args) {
        BinaryTree<Integer, String> binaryTree = new BinaryTree<>();
        binaryTree.put(1,"yhx");
        binaryTree.put(2,"love");
        binaryTree.put(3,"lwh");
        System.out.println(binaryTree.size());
        binaryTree.delete(2);
        String node = binaryTree.getNode(2);
        System.out.println(node);
        System.out.println(binaryTree.size());
    }
}

3、查找二叉树中最大/最小的键

1、最小的键
方法描述
public Key min()找出树中最小的键
private Node min(Node x)找出指定树x中,最小键所在的结点
/**
     * 查找树中最小的键
     * @return
     */
public Key minKey(){
    return minKey(root).key;
}

/**
     * 根据二叉树的特点,左子树 < 右子树 so最小的键肯定是位于左边
     * @param x
     * @return
     */
public Node<Key,Value> minKey(Node<Key,Value> x){
    if (x.left != null){
        return minKey(x.left);
    }else {
        return x;
    }
}
2、最大的键
方法描述
public Key max()找出树中最大的键
public Node max(Node x)找出指定树x中,最大键所在的结点
/**
     * 查询树中最大的键
     * @return
     */
    public Key maxKey(){
        return maxKey(root).key;
    }

    /**
     * 根据二叉树的特点,右子树 > 左子树 so最大的键肯定是位于右边
     * @param x
     * @return
     */
    public Node<Key,Value> maxKey(Node<Key,Value> x){
        if(x.right != null){
            return maxKey(x.right);
        }else {
            return x;
        }
    }

3、二叉树的遍历

我们把树简单的画作上图中的样子,由一个根节点、一个左子树、一个右子树组成,那么按照根节点什么时候被访
问,我们可以把二叉树的遍历分为以下三种方式:

  • 前序遍历

    先访问根结点,然后再访问左子树,最后访问右子树

  • 中序遍历

    先访问左子树,中间访问根节点,最后访问右子树

  • 后序遍历

    先访问左子树,再访问右子树,最后访问根节点

1、前序遍历

前序遍历的API

方法描述
public Queue preErgodic()使用前序遍历,获取整个树中的所有键
private void preErgodic(Node x,Queue keys)使用前序遍历,把指定树x中的所有键放入到keys队列中
/**
     * 前序遍历
     * @return
     */
public Queue<Key> preErgodic(){
    Queue<Key> queue = new Queue<>();
    preErgodic(root,queue);
    return queue;
}

/**
     * 前序遍历操作 先访问根结点,然后再访问左子树,最后访问右子树
     * @param x 根节点
     * @param queue 队列
     */
private void preErgodic(Node<Key,Value> x, Queue<Key> queue){
    if (x == null) {
        return;
    }
    //把当前结点的key放入到队列中
    queue.enqueue(x.key);
    //访问左子树
    if(x.left != null){
        preErgodic(x.left,queue);
    }
    //访问右子树
    if(x.right != null){
        preErgodic(x.right,queue);
    }
}

2、中序遍历

中序遍历的API

方法描述
public Queue midErgodic()使用中序遍历,获取整个树中的所有键
private void midErgodic(Node x,Queue keys)使用中序遍历,把指定树x中的所有键放入到keys队列中
/**
     * 中序遍历
     * @return
     */
    public Queue<Key> midErgodic(){
        Queue<Key> queue = new Queue<>();
        midErgodic(root,queue);
        return queue;
    }

    /**
     * 先访问左子树,中间访问根节点,最后访问右子树
     * @param x
     * @param queue
     */
    private void midErgodic(Node<Key,Value> x, Queue<Key> queue){
        if (x == null) {
            return;
        }
        //访问左子树
        if(x.left != null){
            preErgodic(x.left,queue);
        }
        //把当前结点的key放入到队列中
        queue.enqueue(x.key);
        //访问右子树
        if(x.right != null){
            preErgodic(x.right,queue);
        }
    }

3、后序遍历

后序遍历的API

方法描述
public Queue afterErgodic()使用后序遍历,获取整个树中的所有键
private void afterErgodic(Node x,Queue keys)使用后序遍历,把指定树x中的所有键放入到keys队列中
 /**
     * 后序遍历
     * @return
     */
    public Queue<Key> afterErgodic(){
        Queue<Key> queue = new Queue<>();
        afterErgodic(root,queue);
        return queue;
    }

    /**
     * 先访问左子树,再访问右子树,最后访问根节点
     * @param x
     * @param queue
     */
    private void afterErgodic(Node<Key,Value> x, Queue<Key> queue){
        if (x == null) {
            return;
        }
        //访问左子树
        if(x.left != null){
            preErgodic(x.left,queue);
        }
        //访问右子树
        if(x.right != null){
            preErgodic(x.right,queue);
        }
        //把当前结点的key放入到队列中
        queue.enqueue(x.key);
    }

4、测试

public class BinaryTreeErgodicTest {

    public static void main(String[] args) {
        BinaryTree<String, String> bt = new BinaryTree<>();
        bt.put("E", "5");
        bt.put("B", "2");
        bt.put("G", "7");
        bt.put("A", "1");
        bt.put("D", "4");
        bt.put("F", "6");
        bt.put("H", "8");
        bt.put("C", "3");
        //前序遍历
        Queue<String> preErgodic = bt.preErgodic();
        //中序遍历
        Queue<String> midErgodic = bt.midErgodic();
        //后序遍历
        Queue<String> afterErgodic = bt.afterErgodic();
        for (String key : preErgodic) {
            System.out.println(key+"=" +bt.getNode(key));
        }
    }
}

4、层次遍历

所谓的层序遍历,就是从根节点(第一层)开始,依次向下,获取每一层所有结点的值

层次遍历的结果是:EBGADFHC

方法描述
public Queue layerErgodic():使用层序遍历,获取整个树中的所有键实

实现步骤:

  1. 创建队列,存储每一层的结点;
  2. 使用循环从队列中弹出一个结点:
    • 获取当前结点的key
    • 如果当前结点的左子结点不为空,则把左子结点放入到队列中
    • 如果当前结点的右子结点不为空,则把右子结点放入到队列中
/**
     * 层次遍历
     * @return
     */
public Queue<Key> layerErgodic(){
    //存储key
    Queue<Key> keys = new Queue<>();
    //存储node
    Queue<Node<Key,Value>> nodes = new Queue<>();
    //入队头结点
    nodes.enqueue(root);
    while(!nodes.isEmpty()){
        //出队当前节点
        Node<Key,Value> dequeue = nodes.dequeue();
        //当前节点头入队
        keys.enqueue(dequeue.key);
        if(dequeue.left != null){
            nodes.enqueue(dequeue.left);
        }
        if(dequeue.right != null){
            nodes.enqueue(dequeue.right);
        }
    }
    return keys;
}

5、二叉树的最大深度

最大深度(树的根节点到最远叶子结点的最长路径上的结点数)

上面这颗树的最大深度为:E–>B–>D–>C,深度为4

方法描述
public int maxDepth()计算整棵树的最大深度
private int maxDepth(Node x)计算指定树x的最大深度

实现步骤:

  1. 如果根结点为空,则最大深度为0;
  2. 计算左子树的最大深度;
  3. 计算右子树的最大深度;
  4. 当前树的最大深度=左子树的最大深度和右子树的最大深度中的较大者+1
    /**
     * 计算整棵树的最大深度
     * @return
     */
    public int maxDepth(){
        return maxDepth(root);
    }

    /**
     * 计算指定节点的最大深度
     * @param x
     * @return
     */
    private int maxDepth(Node<Key,Value> x){
        if (x == null) {
            return 0;
        }
        int maxRight = 0;
        int maxLeft = 0;
        int maxDepth;
        if(x.left != null){
            maxLeft = maxDepth(x.left);
        }
        if (x.right != null) {
            maxRight = maxDepth(x.right);
        }
        maxDepth = maxLeft > maxRight ? maxLeft + 1 : maxRight + 1;
        return maxDepth;
    }

6、折纸问题

请把一段纸条竖着放在桌子上,然后从纸条的下边向上方对折1次,压出折痕后展开。此时 折痕是凹下去的,即折痕突起的方向指向纸条的背面。如果从纸条的下边向上方连续对折2 次,压出折痕后展开,此时有三条折痕,从上到下依次是下折痕、下折痕和上折痕。
给定一 个输入参数N,代表纸条都从下边向上方连续对折N次,请从上到下打印所有折痕的方向 例如:N=1时,打印: down;N=2时,打印: down down up

分析

我们把对折后的纸张翻过来,让粉色朝下,这时把第一次对折产生的折痕看做是根结点,那第二次对折产生的下折痕就是该结点的左子结点,而第二次对折产生的上折痕就是该结点的右子结点,这样我们就可以使用树型数据结构来描述对折后产生的折痕。

这棵树有这样的特点:

  1. 根结点为下折痕;
  2. 每一个结点的左子结点为下折痕;
  3. 每一个结点的右子结点为上折痕;

实现步骤:

  • 构建节点类
  • 构建深度为n的折痕树
  • 使用中序遍历,打印树中所有节点的内容

构建深度为N的折痕树:

  1. 第一次对折,只有一条折痕,创建根节点
  2. 如果不是第一次对折,则使用队列保存根节点
  3. 循环遍历队列
    • 从队列中拿出一个节点
    • 如果当前节点的左节点不为空,则把这个左节点加入队列中
    • 如果当前节点的右节点不为空,则把这个右节点加入队列中
    • 判断当前结点的左子结点和右子结点都为空,如果是,则需要为当前结点创建一个值为down的左子结点,一个值为up的右子结点。
public class PaperFolding {

    /**
     * 创建折痕树
     * @param size 深度
     */
    public static Node createTree(int size){
        Node root = null;
        for (int i = 0; i < size; i++) {
            //第一次对折,只有一条折痕,创建根节点
            if (0 == i){
                root = new Node("down",null,null);
            }else {
                //如果不是第一次对折,则使用队列保存根节点
                Queue<Node> nodes = new Queue<>();
                nodes.enqueue(root);
                //循环遍历
                while(!nodes.isEmpty()){
                    //从队列中拿出一个节点
                    Node dequeue = nodes.dequeue();
                    //如果当前节点的左节点不为空,则把这个左节点加入队列中
                    if(dequeue.left != null){
                        nodes.enqueue(dequeue.left);
                    }
                    //如果当前节点的右节点不为空,则把这个右节点加入队列中
                    if(dequeue.right != null){
                        nodes.enqueue(dequeue.right);
                    }
                    //判断当前结点的左子结点和右子结点都为空,则需要为当前结点创建一个值为down的左子结点,一个值为up的右子结点。
                    if(dequeue.left == null && dequeue.right == null){
                        dequeue.left = new Node("down",null,null);
                        dequeue.right = new Node("up",null,null);
                    }
                }
            }
        }
        return root;
    }

    /**
     * 采用中序遍历
     * @param root
     */
    public static void printTree(Node root){
        if (root == null) {
            return;
        }
        printTree(root.left);
        System.out.print(root.item+" ");
        printTree(root.right);
    }

    /**
     * 节点类
     */
    private static class Node{
        String item;
        Node left;
        Node right;

        public Node(String item, Node left, Node right) {
            this.item = item;
            this.left = left;
            this.right = right;
        }
    }

    public static void main(String[] args) {
        Node tree = createTree(2);
        printTree(tree);
    }
}
down down up 

在这里插入图片描述

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

C#: 和时间相关,延时、获取系统时间、时间格式转换、定时器 等

说明&#xff1a;本文记录C# 和时间相关&#xff0c;延时、获取系统时间、时间格式转换、定时器 等&#xff0c;应用和代码。 1.延时函数 System.Threading.Thread.Sleep(20); //毫秒 1.1 主线程不卡延时函数 /* 主线程不卡延时函数 */public static void Delay_ms(int mil…

「斗破年番」5位斗宗大战,韩枫献海心焰晋斗宗,菩提涎争夺开战

Hello,小伙伴们&#xff0c;我是拾荒君。 国漫《斗破苍穹年番》第78期超前爆料&#xff0c;本期透露菩提化体涎的背后秘密。天鹰老人抢夺菩提化体涎后&#xff0c;迅速逃匿&#xff0c;却遭到了各路强者的围攻。然而&#xff0c;这位四星斗宗强者并非浪得虚名&#xff0c;他仅…

Defi安全-Monox攻击事件Foundry复现

其它相关内容可见个人主页 Mono攻击事件的介绍见&#xff1a;Defi安全–Monox攻击事件分析–phalconetherscan 1. 前情提要和思路介绍 Monox使用单边池模型&#xff0c;创建的是代币-vCash交易对&#xff0c;添加流动性时&#xff0c;只需添加代币&#xff0c;即可进行任意代…

Docker常用命令Docker命令 docker常用命令

Docker常用命令Docker命令 docker常用命令 Docker常用命令Docker命令 docker常用命令1、拉取镜像2、查看镜像列表3、run命令帮助信息3.1、创建容器并且运行, 最基本的创建运行3.2、创建容器并且运行, 容器端口绑定宿主机端口3.3、创建容器并且运行, 启动容器传递参数3.4、创建容…

Vue3 结合typescript 组合式函数(1)

在App.vue文件中 实现鼠标点击文件&#xff0c;显示坐标值 第一种方法 第二种方法&#xff1a;组合式函数 结果&#xff1a; 官网推荐组合函数&#xff1a;https://vueuse.org

【linux学习笔记】网络

目录 【linux学习笔记】网络检查、监测网络ping-向网络主机发送特殊数据包traceroute-跟踪网络数据包的传输路径netstat-检查网络设置及相关统计数据 【linux学习笔记】网络 检查、监测网络 ping-向网络主机发送特殊数据包 最基本的网络连接命令就是ping命令。ping命令会向指…

初识Linux shell

Linux初探 Linux系统可以划分为4个部分&#xff1a; Linux内核&#xff1a;Linux系统的核心&#xff0c;控制着系统的所有硬件和软件&#xff0c;在必要时分配硬件&#xff0c;并根据需要执行软件。 内核主要功能&#xff1a; 系统内存管理&#xff1a;内核通过硬件上称为交换…

Java项目:108SSM教务管理系统

博主主页&#xff1a;Java旅途 简介&#xff1a;分享计算机知识、学习路线、系统源码及教程 文末获取源码 一、项目介绍 教务管理系统基于SpringSpringMVCMybatis开发&#xff0c;功能和学生成绩管理系统&#xff0c;学生选课管理系统类似&#xff0c;也可以做学生成绩管理系统…

探寻能源未来瞩目储能科技-2024武汉储能产业博览会定挡8月

探寻能源未来瞩目储能科技-2024武汉储能产业博览会定挡8月 2024武汉国际储能产业博览会 同期举办&#xff1a;2024世界汽车制造技术暨智能装备博览会 时间&#xff1a;2024.8.14-16 地点&#xff1a;武汉国际博览中心 邀请函 主办单位&#xff1a;湖北省汽车行业协会、湖…

快速掌握Postman实现接口测试

快速掌握Postman实现接口测试 Postman简介 Postman是谷歌开发的一款网页调试和接口测试工具&#xff0c;能够发送任何类型的http请求&#xff0c;支持GET/PUT/POST/DELETE等方法。Postman非常简单易用&#xff0c;可以直接填写URL&#xff0c;header&#xff0c;body等就可以发…

PiflowX组件-ReadFromUpsertKafka

ReadFromUpsertKafka组件 组件说明 upsert方式从Kafka topic中读取数据。 计算引擎 flink 有界性 Unbounded 组件分组 kafka 端口 Inport&#xff1a;默认端口 outport&#xff1a;默认端口 组件属性 名称展示名称默认值允许值是否必填描述例子kafka_hostKAFKA_HO…

OpenSource - 基于Netty的网络扩展库HServer

文章目录 概述官网Hserver的理念特点原理图代码案例HelloWorld 概述 HServer是一个基于Netty开发网络扩展库.使用插件方式来扩展我们的业务 HServer提供 web,gateway,rpc 等插件 同时用户也可以自定义插件&#xff0c;来完成各种各样的业务场景。 官网 https://gitee.com/HSe…

计算机毕业设计 | SpringBoot+vue移动端音乐网站 音乐播放器(附源码)

1&#xff0c;项目背景 随着计算机技术的发展&#xff0c;网络技术对我们生活和工作显得越来越重要&#xff0c;特别是现在信息高度发达的今天&#xff0c;人们对最新信息的需求和发布迫切的需要及时性。为了满足不同人们对网络需求&#xff0c;各种特色&#xff0c;各种主题的…

一文带你弄懂 V8 数组的快速 / 字典模式

V8 是如何处理数组的&#xff1f; 问题 先抛出一个问题&#xff0c;下面两端代码哪个的效率更高&#xff1f; const arr []; for(let i 0; i < 10000000; i) {arr[i] 1; }const arr []; arr[10000000 - 1] 1; for(let i 0; i < 10000000; i) {arr[i] 1; }答案是…

一文搞定通过UTM 在MAC M1上安装Win11

Why 临近过年&#xff0c;一年一度的抢票大战就要开始。抢票软件要求安装在windows&#xff0c;作为mac资深用户&#xff0c;必须安装个windows虚拟机。 How step by step: follow YouTube。具体step follow YouTube 视频。本文&#xff0c;只说一下&#xff0c;特别容易错…

Unity中Shader面片一直面向摄像机(个性化修改及适配BRP)

文章目录 前言一、个性化修改面向摄像机效果1、把上一篇文章中求的 Z轴基向量 投影到 XoZ平面上2、其余步骤和之前的一致3、在属性面板定义一个变量&#xff0c;控制面片面向摄像机的类型4、效果 二、适配BRP三、最终代码 前言 在上一篇文章中&#xff0c;我们用Shader实现了面…

1.7 day5 IO进程线程

互斥锁 #include <myhead.h> char buf[128];//创建临界资源 pthread_mutex_t mutex;//创建锁 void *task(void *arg)//分支线程 {while(1){pthread_mutex_lock(&mutex);//上锁printf("分支线程:buf%s\n",buf);strcpy(buf,"I Love China");pthre…

mysql基础-表数据操作之查

目录 1.别名 2. 单表查询 2.1 模糊查询 - like 2.2 limit 2.3 order by 2.4 group by 2.5 in 2.6 between and 2.6 is null 2.7 not 2.8 运算符 3. 联表查询 全连接 左连接 右连接 本次分享一下数据的DQL语言。 1.别名 首先分享一下别名的知识。我们在查询的时…

【创建VirtualBox虚拟机并安装openEuler20.03 TLS SP1操作系统】

创建VirtualBox虚拟机并安装openEuler20.03 TLS SP1操作系统 一、环境说明二、安装过程 一、环境说明 虚拟机软件&#xff1a;Virtualbox操作系统&#xff1a;openEuler 20.03 TLS SP1&#xff08;x86&#xff09; 二、安装过程 创新虚拟机 修改虚拟机配置&#xff1a; …

MySQL复习汇总(图书管理系统)

MySQL图书管理系统&#xff08;49-94&#xff09;源码_71.备份book数据库到e盘的mybook.sql文件(备份文件中要求包含建库命令)-CSDN博客 -- 1、 创建一个名称为book的数据库。 -- 2、 打开book数据库 -- 3、 创建数据表分别如下&#xff08;除外键之外&#xff09;…