Map和Set详解

news2024/12/26 22:51:57

一、二叉搜索树搜索树

1.二叉搜索树的概念

二叉搜索树又称二叉排序树,它或者是一棵空树,或者是具有以下性质的二叉树:
若它的左子树不为空,则左子树上所有节点的值都小于根节点的值
若它的右子树不为空,则右子树上所有节点的值都大于根节点的值
它的左右子树也分别为二叉搜索树
在这里插入图片描述

2.二叉搜索树的模拟实现

import sun.reflect.generics.tree.Tree;

public class BinarySearchTree {

    static class TreeNode{
        public int val;
        public TreeNode left;
        public TreeNode right;

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

    public TreeNode root = null;

    public TreeNode find(int val,TreeNode root){
        TreeNode cur = root;
        while(cur != null){
            if(cur.val<val){
                cur = cur.right;
            }
            else if(cur.val>val){
                cur = cur.left;
            }
            else{
                return cur;
            }
        }
        return null;
    }

    public void insert(int val){
        TreeNode newNode = new TreeNode(val);
        if(root == null){
            root = newNode;
            return ;
        }
        TreeNode cur = root;
        TreeNode pre= cur;
        while(cur != null){
            if(cur.val<val){
                pre = cur;
                cur = cur.right;
            }
            else if(cur.val>val){
                pre = cur;
                cur = cur.left;
            }
            else{
                return;
            }
        }
        if(val> pre.val){
            pre.right = newNode;
        }
        if(val<pre.val){
            pre.left = newNode;
        }
    }


    public void delete (int val){
        if(root == null){
            return;
        }
        TreeNode cur = root;
        TreeNode parent= cur;
        while(cur != null){
            if(cur.val<val){
                parent = cur;
                cur = cur.right;
            }
            else if(cur.val>val){
                parent = cur;
                cur = cur.left;
            }
            else{
                remove(parent,cur,val);
            }
        }
    }

    private void remove(TreeNode parent, TreeNode cur, int val) {
        if(cur.left == null){
            if(cur == root){
                root = root.right;
            }
            if(parent.left == cur){
                parent.left = cur.right;
            }
            if(cur == parent.right){
                parent.right = cur.right;
            }
        }else if(cur.right == null){
            if(cur == root){
                root = root.left;
            }
            if(parent.left == cur){
                parent.left = cur.left;
            }
            if(cur == parent.right){
                parent.right = cur.left;
            }
        }
        else{
            TreeNode target = cur.right;
            TreeNode targetParent = cur;
            while(target.left!= null){
                targetParent = target;
                target = target.left;
            }
            cur.val = target.val;
            if(target==targetParent.left){//证明此时taeget没有左子树
                targetParent.left = target.right;
            }else
                targetParent.right = target.right;
        }

    }
}

在这里插入图片描述
实际上在JDK中TreeSet 和TreeMap底层实现用的就是一颗二叉搜索树(红黑树)。

二、Map & Set

Map和set是一种专门用来进行搜索的容器或者数据结构,其搜索的效率与其具体的实例化子类有关。以前常见的 搜索方式有:

  1. 直接遍历,时间复杂度为O(N),元素如果比较多效率会非常慢。
  2. 二分查找,时间复杂度为O(logN),但搜索前必须要求序列是有序的。

上述排序比较适合静态类型的查找,即一般不会对区间进行插入和删除操作了,而现实中的查找比如:

  • 根据姓名查询考试成绩
  • 通讯录,即根据姓名查询联系方式

不重复集合,即需要先搜索关键字是否已经在集合中可能在查找时进行一些插入和删除的操作,即动态查找,那上述两种方式就不太适合了,本节介绍的Map和Set是 一种适合动态查找的集合容器。

一般把搜索的数据称为关键字(Key),和关键字对应的称为值(Value),将其称之为Key-value的键值对,所以 模型会有两种:

  1. 纯 key 模型,比如:
    有一个英文词典,快速查找一个单词是否在词典中
    快速查找某个名字在不在通讯录中
  2. Key-Value 模型,比如:
    统计文件中每个单词出现的次数,统计结果是每个单词都有与其对应的次数:<单词,单词出现的次数>
    梁山好汉的江湖绰号:每个好汉都有自己的江湖绰号
    而Map中存储的就是key-value的键值对,Set中只存储了Key。

2.1 Map

2.1.1关于Map的说明

Map是一个接口类,该类没有继承自Collection,该类中存储的是<K,V>结构的键值对,并且K一定是唯一的,不 能重复。

有一点需要注意,我们知道Map的底层是一个具有其他限制的二叉搜索树(红黑树),而这个二叉搜索树所比较的对象并不是value,而是key.举个例子来说,现在有键值对<“a”,2>、<“b”,1>,那么这两个键值对如果构建一个map的话根节点是<“a”,2>,而<“b”,1>是左子树(注意不是右子树),因为“a”比“b”大。

2.2.2 关于Map.Entry<K, V>的说明

Map.Entry<K, V> 是Map内部实现的用来存放<key, value>键值对映射关系的内部类,该内部类中主要提供了
<key, value>的获取,value的设置以及Key的比较方式。
在这里插入图片描述

2.2.3 Map 的常用方法说明

在这里插入图片描述


import java.util.Map;
import java.util.Set;
import java.util.TreeMap;

public class Test {
    public static void main(String[] args) {
        Map<String,Integer> treeMap = new TreeMap<>();
        treeMap.put("a",0);//添加键值对
        treeMap.put("a",1);//treeMao中key类似于唯一标识符,只能有一个对象的key是a,所以这里实际是将原来a=0改成a=1
        treeMap.put("b",2);
        treeMap.put("c",3);
        treeMap.put("d",4);
        System.out.println(treeMap);//treeMao重写了TosString方法,map输出使用{}
        System.out.println(treeMap.get("a"));//根据key返回value
        //将treeMap中的所有键值对的key都放入Set中
        Set<String> keyset = treeMap.keySet();//set输出使用【】
        System.out.println(keyset);
        //将treeMap中所有的键值对都放入一个set中
        Set<Map.Entry<String,Integer>> set = treeMap.entrySet();
        System.out.println(set);
        for (Map.Entry<String,Integer> entry:set) {
            System.out.println("key="+entry.getKey()+"   value="+entry.getValue());
        }
        System.out.println(treeMap.getOrDefault("e",1));
        //如果treeMap中有"e“就返回value,如果没有就返回1

    }
}

在这里插入图片描述

注意:

  1. Map是一个接口,不能直接实例化对象,如果要实例化对象只能实例化其实现类TreeMap或者HashMap
  2. Map中存放键值对的Key是唯一的,value是可以重复的
  3. 在TreeMap中插入键值对时,key不能为空,否则就会NullPointerException异常,value可以为空。但是HashMap的key和value都可以为空。
  4. Map中的Key可以全部分离出来,存储到Set中来进行访问(因为Key不能重复)。
  5. Map中的value可以全部分离出来,存储在Collection的任何一个子集合中(value可能有重复)。
  6. Map中键值对的Key不能直接修改,value可以修改,如果要修改key,只能先将该key删除掉,然后再来进行重新插入。

2.2 Set 的说明

Set与Map主要的不同有两点:Set是继承自Collection的接口类,Set中只存储了Key。
在这里插入图片描述
注意:

  1. Set是继承自Collection的一个接口类

  2. Set中只存储了key,并且要求key一定要唯一

  3. TreeSet的底层是使用Map来实现的,其使用key与Object的一个默认对象作为键值对插入到Map中的
    在这里插入图片描述

  4. Set最大的功能就是对集合中的元素进行去重

  5. 实现Set接口的常用类有TreeSet和HashSet,还有一个LinkedHashSet,LinkedHashSet是在HashSet的基础上维护了一个双向链表来记录元素的插入次序。

  6. Set中的Key不能修改,如果要修改,先将原来的删除掉,然后再重新插入

  7. TreeSet中不能插入null的key,HashSet可以。

三、哈希表

3.1 概念

顺序结构以及平衡树中,元素关键码与其存储位置之间没有对应的关系,因此在查找一个元素时,必须要经过关键码的多次比较。顺序查找时间复杂度为O(N),平衡树中为树的高度,即O(logN),搜索的效率取决于搜索过程中元素的比较次数.
理想的搜索方法:可以不经过任何比较,一次直接从表中得到要搜索的元素。 如果构造一种存储结构,通过某种函 数(hashFunc)使元素的存储位置与它的关键码之间能够建立一一映射的关系,那么在查找时通过该函数可以很快找到该元素。

当向该结构中:

  • 插入元素
    根据待插入元素的关键码,以此函数计算出该元素的存储位置并按此位置进行存放
  • 搜索元素
    对元素的关键码进行同样的计算,把求得的函数值当做元素的存储位置,在结构中按此位置取元素比较,若 关键码相等,则搜索成功

该方式即为哈希(散列)方法,哈希方法中使用的转换函数称为哈希(散列)函数,构造出来的结构称为哈希表(Hash Table)(或者称散列表)
例如:数据集合{1,7,6,4,5,9};
哈希函数设置为:hash(key) = key % capacity; capacity为存储元素底层空间总的大小。
在这里插入图片描述
用该方法进行搜索不必进行多次关键码的比较,因此搜索的速度比较快 。
那么如果此时我们的key是14,那么14%10==4,发现也是要存放到下标为4的位置的,但是此时下标为4的位置已经有元素了呀?这种现象就叫做冲突。

3.2 冲突-概念

不同关键字通过相同哈希哈数计算出相同的哈希地址,该种现象称为哈希冲突或哈希碰撞。
把具有不同关键码而具有相同哈希地址的数据元素称为“同义词”。

3.2 冲突-避免

首先,我们需要明确一点,由于我们哈希表底层数组的容量往往是小于实际要存储的关键字的数量的,这就导致一 个问题,冲突的发生是必然的,但我们能做的应该是尽量的降低冲突率。

3.2.1哈希函数设计

引起哈希冲突的一个原因可能是:哈希函数设计不够合理。
哈希函数设计原则:

  1. 哈希函数的定义域必须包括需要存储的全部关键码,而如果散列表允许有m个地址时,其值域必须在0到m-1之间
  2. 哈希函数计算出来的地址能均匀分布在整个空间中
  3. 哈希函数应该比较简单

常见哈希函数

  • 直接定址法–(常用)
    取关键字的某个线性函数为散列地址:
    Hash(Key)= A*Key + B
    优点:简单、均匀 缺点:需要事先知道关键字的分布情况
    使用场景:适合查找比较小且连续的情况
    面试题:字符串中第一个只出现一次字符
    https://editor.csdn.net/md/?articleId=130651358
  • 除留余数法–(常用)
    设散列表中允许的地址数为m,取一个不大于m,但最接近或者等于m的质数p作为除数,
    按照哈希函数: Hash(key) = key% p(p<=m),将关键码转换成哈希地址
  • 平方取中法–(了解)
    假设关键字为1234,对它平方就是1522756,抽取中间的3位227作为哈希地址; 再比如关键字为4321,对 它平方就是18671041,抽取中间的3位671(或710)作为哈希地址 平方取中法比较适合:不知道关键字的分布,而位数又不是很大的情况
  • 折叠法–(了解)
    折叠法是将关键字从左到右分割成位数相等的几部分(最后一部分位数可以短些),然后将这几部分叠加求和, 并按散列表表长,取后几位作为散列地址。
    折叠法适合事先不需要知道关键字的分布,适合关键字位数比较多的情况
  • 随机数法–(了解)
    选择一个随机函数,取关键字的随机函数值为它的哈希地址,即H(key) = random(key),其中random为随机数函数。
    通常应用于关键字长度不等时采用此法
  • 数学分析法–(了解)
    设有n个d位数,每一位可能有r种不同的符号,这r种不同的符号在各位上出现的频率不一定相同,可能在某 些位上分布比较均匀,每种符号出现的机会均等,在某些位上分布不均匀只有某几种符号经常出现。可根据 散列表的大小,选择其中各种符号分布均匀的若干位作为散列地址。
    例如:
    假设要存储某家公司员工登记表,如果用手机号作为关键字,那么极有可能前7位都是 相同的,那么我们可以 选择后面的四位作为散列地址,如果这样的抽取工作还容易出现 冲突,还可以对抽取出来的数字进行反转(如 1234改成4321)、右环位移(如1234改成4123)、左环移位、前两数与后两数叠加(如1234改成12+34=46)等方 法。数字分析法通常适合处理关键字位数比较大的情况,如果事先知道关键字的分布且关键字的若干位分布较均 匀的情况

3.3冲突-避免-负载因子调节(重点)

散列表的载荷因子定义为: α = 填入表中的元素个数/散列表的长度
α 是散列表装满程度的标志因子。由于表长是定值,α 与“填入表中的元素个数”成正比,所以,α 越大,表明填入表中的元素越多,产生冲突的可能性就越大;反之,α 越小,标明填入表中的元素越少,产生冲突的可能性就越小。实际上,散列表的平均查找长度是载荷因子α 的函数,只是不同处理冲突的方法有不同的函数。

对于开放定址法,荷载因子是特别重要因素,应严格限制在0. 7-0. 8以下。超过0. 8,查表时的CPU缓存不命中( cachemissing)按照指数曲线上升。因此,一些采用开放定址法的hash库,如Java的 系统库限制了荷载因子为0.75,超过此值将resize散列表。

在这里插入图片描述所以当冲突率达到一个无法忍受的程度时,我们需要通过降低负载因子来变相的降低冲突率。
已知哈希表中已有的关键字个数是不可变的,那我们能调整的就只有哈希表中的数组的大小。

3.4 冲突-解决

3.4.1闭散列(开放定址法)

当发生哈希冲突时,如果哈希表未被装满,说明在哈希表中必然还有空位置,那么可以 把key存放到冲突位置中的“下一个” 空位置中去。那如何寻找下一个空位置呢?

  1. 线性探测
    比如上面的场景,现在需要插入元素44,先通过哈希函数计算哈希地址,下标为4,因此44理论上应该插在该 位置,但是该位置已经放了值为4的元素,即发生哈希冲突。
    线性探测:从发生冲突的位置开始,依次向后探测,直到寻找到下一个空位置为止,插入
    通过哈希函数获取待插入元素在哈希表中的位置,如果该位置中没有元素则直接插入新元素,如果该位置中有元素发生哈希冲突,使用线性探测找到 一个空位置,插入新元素。
    在这里插入图片描述

注意:
采用闭散列处理哈希冲突时,不能随便物理删除哈希表中已有的元素,若直接删除元素会影响其他 元素的搜索。比如删除元素4,如果直接删除掉,44查找起来可能会受影响。因此线性探测采用标 记的伪删除法来删除一个元素。

  1. 二次探测
    线性探测的缺陷是产生冲突的数据堆积在一块,这与其找下一个空位置有关系,因为找空位置的方式就是挨着往后逐个去找,因此二次探测为了避免该问题,找下一个空位置的方法为
    在这里插入图片描述
    或者:
    在这里插入图片描述

其中:i = 1,2,3…, H0是通过散列函数Hash(x)对元素的关键码 key 进行计算得到的位置, m是表的大小。 对于3.3.1中如果要插入44,产生冲突,使用解决后的情况为:
在这里插入图片描述
闭散列最大的缺陷就是空间利用率比较低,这也是哈希的缺陷。

3.4.2冲突-解决-开散列/哈希桶(重点掌握)

开散列法又叫链地址法(开链法),首先对关键码集合用散列函数计算散列地址,具有相同地址的关键码归于同一子 集合,每一个子集合称为一个桶,各个桶中的元素通过一个单链表链接起来,各链表的头结点存储在哈希表中。如下图
在这里插入图片描述

实际上,开散列的方式是链表+数组+红黑树的配置。
红黑树体现在:当链表长度>=8,并且数组长度>=64时,底层会直接重新组织数据,形成红黑树。java的hashMap就是这种结构
开散列,可以认为是把一个在大集合中的搜索问题转化为在小集合中做搜索了,时间复杂度可以认为是O(1)(因为数组是随机访问,我们认为链表的长度是一个常数)

3.5 HashCode

我们之前所讲的哈希表的值都是整型的,但是实际上当用到HashMap或者HashSet的时候,他里面存的可能是String类型,可能是一个我们定义的对象,那么我们怎么将其映射到我们的哈希表里呢?这就用到了HashCode.
在java中,我们每生成一个对象,他的地址是唯一的,所以我们可以通过地址来映射出每一个对象的唯一标识HashCode,HashCode,我们就可以根据这个对象的HashCode值结合散列函数和一系列解决、避免冲突的方法,将其映射到哈希表中从而达到我们的目的。
关于hashcode,可以去看这篇博客
https://blog.csdn.net/qq_46940224/article/details/124384187


```java
import java.util.Set;
import java.util.TreeSet;

public class Test2 {
    public static void main(String[] args) {
        Person person1 = new Person("张三",4);
        Person person2 = new Person("李四",5);
        System.out.println(person1.hashCode());
        System.out.println(person2.hashCode());
    }
    static class Person{

        String name;
        int age;

        public Person(String name, int age){
            this.name = name;
            this.age = age;
        }
    }
}

在这里插入图片描述
面试题:两个对象,hashCode一样,equals也一样吗:equals一样,hashCode一样吗?
首先要要注意的是equals如果是引用类型调用的话,比较的是这两个引用类型的地址;hashcode相同只能说明地址经过映射之后的值相同,不能说明地址相同,也就不能说equals相同了。如果equals相同(没有重写)了,那么证明地址相同,本身就是同一对象,那么当然hashcode当然相同了。

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

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

相关文章

你见过最厉害的软件测试工程师是怎样的?

最厉害的测试工程师&#xff0c;可以在研发设计评审时发现潜在的bug&#xff0c;提出风险点&#xff0c;而不是等研发已经把代码写好了&#xff0c;部署完了&#xff0c;再用测试的方式去发现这个bug。举两个真实例子。 我们为上层业务提供算法算子&#xff0c;算子本身可能有…

shell 05(shell索引数组变量)

一、数组 shell 支持数组 (Array)&#xff0c;数组是若干数据的集合&#xff0c;其中的每一份数据都称为数组的元素. 注意Bash shell 只支持一维数组&#xff0c;不支持多维数组。 在 Shell 中&#xff0c;用括号( )来表示数组&#xff0c;数组元素之间用空格来分隔. 语法为&…

无涯教程-PHP - 常量数组

现在可以使用 define()函数定义数组常量。在PHP 5.6中&#xff0c;只能使用 const 关键字定义它们。 <?php//define a array using define functiondefine(animals, [dog,cat,bird]);print(animals[1]); ?> 它产生以下浏览器输出- cat PHP - 常量数组 - 无涯教程网无…

32、启用 HTTP 响应压缩和编程式配置Web应用

★ 启用HTTP压缩 就是前端页面如果改动的比较多&#xff0c;那么响应就会比较慢&#xff0c;可以通过设置HTTP响应压缩来提高响应&#xff0c;如果前端改动少&#xff0c;那么就不需要启动这个响应压缩。 目的&#xff1a;为了提高HTTP响应数据在网络上的传输效率。▲ 设置如…

UE学习记录03----UE5.2 使用MVVM示例

1.打开ue5.2新建C项目 2.项目中通过类导向新建C类&#xff0c;父类选择为UMVVMViewModelBase&#xff0c;创建完成会自动打开vs 3.在VS中对新建的类进行宏定义 使用 C 类向导 创建的类声明自动通过 UCLASS() 宏进行处理。 UCLASS() 宏使得引擎意识到这个类的存在&#xff0c;并…

opencv进阶19-基于opencv 决策树cv::ml::DTrees 实现demo示例

opencv 中创建决策树 cv::ml::DTrees类表示单个决策树或决策树集合&#xff0c;它是RTrees和 Boost的基类。 CART是二叉树&#xff0c;可用于分类或回归。对于分类&#xff0c;每个叶子节点都 标有类标签&#xff0c;多个叶子节点可能具有相同的标签。对于回归&#xff0c;每…

基于matlab的lorenz混沌系统仿真与分析

目录 1.算法运行效果图预览 2.算法运行软件版本 3.部分核心程序 4.算法理论概述 5.算法完整程序工程 1.算法运行效果图预览 2.算法运行软件版本 matlab2022a 3.部分核心程序 ..................................................................................... l…

控制台实现家庭记账本功能

需求&#xff1a; 在控制台实现家庭记账本的小功能&#xff0c;功能如下 参考代码如下&#xff1a; import java.util.Scanner;/*** <p>家庭账本-综合案例</p>** author 波波老师(weixin : javabobo0513)*/ public class Demo24 {public static void main(Strin…

虚拟机密码忘了如何解决?

很久以前使用过的虚拟机&#xff0c;因为太久时间没有密码忘了&#xff0c;在网上查询了一种好的方法进行解决&#xff0c;写篇博客记录一下&#xff01;&#xff01;&#xff01; 打开虚拟机&#xff0c;让虚拟机启动 启动中疯狂按Esc&#xff0c;使得页面出现下图&#xff1…

【ES6】—【必备知识】—箭头函数

一、定义函数 1. ES5 1. 普通函数预定义&#xff0c;再调用 console.log(sum(1, 2)) function sum (x, y) {return x y } console.log(sum(1, 2))2. 函数表达式 按代码顺序定义 console.log(sum(1, 2)) // sum is not a function // sum不是一个函数 var sum function (x…

linux常会用到的命令

查看gpu上运行的进程&#xff1a; nvidia-smi 查看进程的完整信息 ps -f -p 进程号 搜索含有指定字符的进程信息&#xff0c;如radar ps -ef|grep radar 复制文件时排除某个文件夹&#xff0c;如从源路径中排除data rsync -av --excludedata/ 源路径 目标路径查看磁盘占用…

<kernel>kernel 6.4 USB-之-hub_port_init()分析

&#xff1c;kernel&#xff1e;kernel 6.4 USB-之-hub_port_init()分析 kernel 6.4 USB系列文章如下&#xff1a; &#xff1c;kernel&#xff1e;kernel 6.4 USB-之-hub_event()分析 &#xff1c;kernel&#xff1e;kernel 6.4 USB-之-port_event()分析 &#xff1c;kernel&…

快速搭建 Linux 学习平台

最近换了一个新的笔记本电脑&#xff0c;原来的学习环境没了&#xff0c;所以就重新搭建一下&#xff0c;顺便把这个过程给记录下来&#xff0c;希望可以帮助有需要的人。一个学习环境最主要的目的是简化学习需要准备的时间&#xff0c;不需要花费太多的时间在哪些不必要的细枝…

【ownCloud】添加信任域

在我进行使用mysql:5.6和 owncloud 镜像&#xff0c;构建一个个人网盘后 我的虚拟机更改了ip地址导致出现下列状况 报错&#xff1a;您正在访问来自不信任域名的服务器。 please contact your administrator. if you are an administrator of this instance, configure the &q…

重叠率控制(算法详细介绍含SCL和梯形图源代码)

产品包装和线缆保护材料的包覆都需要进行材料包装重叠率的控制,这篇博客和大家详细介绍重叠率控制算法。阅读本篇博客之前大家需要对比例随动运动控制系统以及收卷排线控制有所了解,这样大家会更容易理解包材重叠率控制,相关文章链接如下: 运动控制比例随动系统_正运动随动…

JavaScript 闭包是什么:最佳实践指南

闭包是指在一个函数内部创建另一个函数&#xff0c;并且内部函数可以访问外部函数的变量、参数以及其他内部函数&#xff0c;即使外部函数已经执行完毕。这种机制使得内部函数保留了对外部作用域的引用&#xff0c;即使外部作用域已经不再活跃。 为什么闭包重要&#xff1f; 闭…

CTFhub-sqli注入-Referer注入

在最后添加 Referer: (注意 R 大写&#xff0c; Referer后面是 &#xff1a;&#xff0c;Content-Length: 与 Referer: 之间没有空行) 1 2 3 1 union select 1,database() -1 union select 1,database() -1 union select 1,group_concat(table_name)from information_sche…

【Java 高阶】一文精通 Spring MVC - 转发重定向(四)

&#x1f449;博主介绍&#xff1a; 博主从事应用安全和大数据领域&#xff0c;有8年研发经验&#xff0c;5年面试官经验&#xff0c;Java技术专家&#xff0c;WEB架构师&#xff0c;阿里云专家博主&#xff0c;华为云云享专家&#xff0c;51CTO 专家博主 ⛪️ 个人社区&#x…

框架分析(3)-Vue.js

框架分析&#xff08;3&#xff09;-Vue.js 专栏介绍Vue.js核心特点响应式数据绑定组件化开发虚拟DOM模板语法插件系统 对比总结优缺点优点简单易学响应式数据绑定组件化开发虚拟DOM生态系统和社区支持 缺点生态系统相对较小文档和教程相对较少适用于中小型项目 专栏介绍 link…

Skywalking Kafka Tracing实现

背景 Skywalking默认场景下&#xff0c;Tracing对于消息队列的发送场景&#xff0c;无法将TraceId传递到下游消费者&#xff0c;但对于微服务场景下&#xff0c;是有大量消息队列的业务场景的&#xff0c;这显然无法满足业务预期。 解决方案 Skywalking的官方社区中&#xf…