Map集合以及它的实现类们

news2024/11/22 11:28:01

Map集合

Map集合的概念理解

在现实生活中,我们经常会碰见一对一标识的例子:如身份证号与个人、IP地址与主机名等。这些一一对应的关系就是映射。在Java之中也能为我们的对象添加一个“一”的对应关系—Map<K,V>集合,位于java.util.Map<K,V>包下。里面的K代表该集合中唯一对应的那个身份,也叫做键。里面的V代表该集合中的元素值,也就是我们要存储的数据。

集合分为单列集合双列集合

  • 单列集合:主要指的就是Collection<E>系列的集合,里面存储的是一个一个的元素。这些数据结合在一起就成了一组数据,也就是集合。里面的每一个元素都是孤立存在的。
  • 双列集合:主要指的是Map<K,V>系列的集合,里面存储的是一对一对的键-值对,其中键不能重复,值可以重复。

Map常用方法

Map<K,V>是map系列集合的根接口,Map<K,V>接口中提供了一些简单操作map集合的方法让子类去重写。

添加操作

  • V put(K key,V value):添加一组映射关系,往集合中添加一组数据
  • void putAll(Map<? extends K,? extends V> m):将指定map集合m中的所有映射关系添加现有map集合中,为当前map集合添加另外一个m集合的所有元素。

删除操作

  • V remove(Object key):判断map集合中是否包含键key,如果包含将该key-value映射关系移除,并返回移除的key的value值
  • default boolean remove(Object key,Object value):判断当前map集合中是否包含映射关系key-value,如果包含返回true,并将该映射关系移除,如果不包含返回false。
  • void clear():清除该map中的所有映射关系

修改操作(了解即可)使用put()同样可以完成修改操作

  • defalut V replace(K key,V value):替换指定键key的值为value。返回值为key位置修改之前的值
  • default boolean replace(K key,V oleValue,V newValue):替换指定键key的oldValue为newValue。返回值为true或false

查询操作

  • V get(Object key):查询map集合中指定键key的值并返回。
  • boolean containsKey(Object key):判断map集合中是否含有指定键key。
  • boolean containsValue(Object value):判断map集合中是否含有指定值value。

元视图操作的方法(用于获取遍历集合的方法)

  • Set<K> keySet():返回该map集合中所有的键所组成的Set集合。(键不可重复)
  • Set<Map.Entry<K,V>> entrySet():返回map集合中所有的键值对组成的Set集合。Entry指Map中的内部接口
  • Collection<V> values():返回map集合中所有的value值组成的Collection集合。(值可以重复)

其他操作

  • int size():返回该map集合中的键值对数量。如果值为空或键为空仍会计算在内,如果值和键都为空不会计算在内。
  • boolean isEmpty():判断该map集合是否为空。如果值为空或键为空或都为true,结果都不为空。

代码测试:

public class MapTest {

    public static void main(String[] args) {
        Map<Integer,Object> map = new HashMap<>();

        map.put(1,"map");
        map.put(2,"hashMap");
        map.put(3,"treeMap");
        System.out.println("map = " + map); //map = {1=map, 2=hashMap, 3=treeMap}

        Map<Integer,Object> mapNew = new HashMap<>();
        mapNew.put(4,"linkedHashMap");
        mapNew.put(5,"hashTable");
        System.out.println("mapNew = " + mapNew); //{4=linkedHashMap, 5=hashTable}

        map.putAll(mapNew);
        System.out.println("map = " + map); //map = {1=map, 2=hashMap, 3=treeMap, 4=linkedHashMap, 5=hashTable}

        Object remove = map.remove(4);
        System.out.println("remove = " + remove); //remove = linkedHashMap
        System.out.println("map = " + map); //map = {1=map, 2=hashMap, 3=treeMap, 5=hashTable}

        boolean b1 = map.remove(6, "123");
        boolean b = map.remove(5, "hashTable");
        System.out.println("b1 = " + b1); //b1 = false
        System.out.println("b = " + b); //b = true
        System.out.println("map = " + map); //map = {1=map, 2=hashMap, 3=treeMap}

        mapNew.clear();
        System.out.println("mapNew = " + mapNew); //mapNew = {}

        //map.put(1,"hashTable");
        //System.out.println("map = " + map); //map = {1=hashTable, 2=hashMap, 3=treeMap}
        Object table = map.replace(1, "hashTable");
        System.out.println("table = " + table); //table = map
        System.out.println("map = " + map); //map = {1=hashTable, 2=hashMap, 3=treeMap}

        boolean replace = map.replace(1, "hashTable", "map");
        System.out.println("replace = " + replace); //replace = true
        System.out.println("map = " + map); //map = {1=map, 2=hashMap, 3=treeMap}

        Object o = map.get(1);
        System.out.println("o = " + o); //o = map
        boolean containsKey = map.containsKey(3);
        System.out.println("containsKey = " + containsKey); //containsKey = true
        boolean hashMap = map.containsValue("hashMap");
        System.out.println("hashMap = " + hashMap); //hashMap = true

        Set<Integer> keySet = map.keySet();
        for (Integer integer : keySet) { // 1 2 3
            System.out.print(" " + integer);
        }
        System.out.println();
        Collection<Object> values = map.values();
        for (Object value : values) { // map hashMap treeMap
            System.out.print(" " + value);
        }
        System.out.println();
        Set<Map.Entry<Integer, Object>> entrySet = map.entrySet();
        for (Map.Entry<Integer, Object> entry : entrySet) { // 键1的值:map 键2的值:hashMap 键3的值:treeMap
            Integer key = entry.getKey();
            Object value = entry.getValue();
            System.out.print("键"+key+"的值:"+value+" ");
        }
        System.out.println();

        System.out.println("map = " + map); //map = {1=map, 2=hashMap, 3=treeMap}
        map.put(null,"null"); //4
        map.put(7,null); //5
        map.put(null,null); //5
        int size = map.size();
        System.out.println("size = " + size); //size = 5
        boolean empty = map.isEmpty(); //false
        boolean newEmpty = mapNew.isEmpty(); //true
        //mapNew.put(null,"null"); //false
        //newEmpty = mapNew.isEmpty();
        //mapNew.put(9,null); //false
        //newEmpty = mapNew.isEmpty();
        mapNew.put(null,null); //false
        newEmpty = mapNew.isEmpty();
        System.out.println("empty = " + empty); //empty = false
        System.out.println("newEmpty = " + newEmpty); //newEmpty = false
    }

}

结果演示:

Map集合方法演示
注意:
如果使用put方法时,如果是第一次添加该元素,即原来map集合中没有键为添加元素的键,也就表示没有这个键对应的值,返回null,并把新的元素放到map集合中。

如果map集合中含有该键,则会先将这个键对应的value值返回,再修改该键的值为新的值。

Map集合遍历方式

在单列集合Collection中可以通过Iterator对象进行遍历或增强for循环进行遍历。但是Map集合中没有实现获取iterator()的方法,所以不能使用获取迭代器对象的方法进行遍历,Map集合也没有继承java.lang.Iterable<T>接口,所以也不能使用增强for循环进行遍历。

Map集合可以借助Collection集合进行遍历。简单的遍历主要分为以下三种:

  • 单独遍历所有的key:使用keySet()方法
  • 单独遍历所有value:使用values()方法
  • 成对的遍历Map系列的集合中的每一对Map.Entry子接口的实现类对象:使用entrySet()方法。

Map.Entry接口
代码测试:

public class GetMapElementTest {

    public static void main(String[] args) {
        Map<Integer,Object> map = new HashMap<>();
        map.put(1001,"map");
        map.put(1002,"hashMap");
        map.put(1003,"treeMap");
        System.out.println("map = " + map); //map = {1001=map, 1002=hashMap, 1003=treeMap}

        Set<Integer> keySet = map.keySet();
        for (Integer integer : keySet) { //键:1001,值:map  键:1002,值:hashMap  键:1003,值:treeMap
            System.out.println("键:"+integer+",值:"+map.get(integer));
        }
        System.out.println("=======================================");
        Collection<Object> values = map.values();
        for (Object value : values) { //map hashMap treeMap 
            System.out.print(value+" ");
        }
        System.out.println();
        System.out.println("==================================================");
        Set<Map.Entry<Integer, Object>> entrySet = map.entrySet();
        for (Map.Entry<Integer, Object> entry : entrySet) { //键:1001,值:map  键:1002,值:hashMap  键:1003,值:treeMap
            Integer key = entry.getKey();
            Object value = entry.getValue();
            System.out.println("键:"+key+",值:"+value);
        }
    }
}

结果演示:

map迭代结果演示

Map集合的实现类

Map接口是双列集合的父接口,而实现了Map接口的实现类也常常被叫做map集合。Map接口的常用的实现类有:HashMapLinkedHashMapTreeMapProperties等。其中使用最多的是HashMap

HashMap集合

HashMap的底层实现与扩容机制:
HashMap在JDK1.8之前:底层实现是数组+链表,扩容机制是当table中元素的个数已经达到阈值(table.length*0.75)时并且新添加[index]桶已经是非空,那么table.length需要扩容为2倍。

HashMap在JDK1.8之后:底层实现是数组+链表/红黑树,扩容机制(1)是当table中元素的个数已经达到阈值(table.length*0.75)时并且新添加[index]桶已经是非空,那么table需要扩容为2倍。(2)当添加到[index]下时,发现[index]下的链表结点个数已经达到8个,而table的长度未达到64,此时table.length也会扩容为2倍

HashMap构造方法:

  • ​ HashMap();
  • ​ HashMap(int initialCapacity);//指定初始化容量

HashMap和Hashtable的区别

(1)线程安全性不同
HashMap 是线程不安全的,HashTable 是线程安全的,其中的方法是 Synchronize 的,在多线程并发的情况下,可以直接使用 HashTable,但是使用 HashMap 时必须自己增加同步处理。
(2)是否提供 contains 方法
HashMap 只有 containsValue 和 containsKey 方法;HashTable 有 contains、containsKey 和 containsValue 三个方法,其
中 contains 和 containsValue 方法功能相同。
(3)key 和 value 是否允许 null 值
Hashtable 中,key 和 value 都不允许出现 null 值。HashMap 中,null 可以作为键,这样的键只有一个;可以有一个或多个键所对应的值为 null。
(4)数组初始化和扩容机制
HashTable 在不指定容量的情况下的默认容量为 11,而 HashMap 为 16,Hashtable 不要求底层数组的容量一定要为2 的整数次幂,而 HashMap 则要求一定为 2 的整数次幂。Hashtable 扩容时,将容量变为原来的 2 倍加 1,而 HashMap 扩容时,将容量变为原来的 2倍。

代码:

public static void main(String[] args) {
    HashMap<String,Double> map = new HashMap<>();
    map.put("张三", 10000.0);
    //key相同,新的value会覆盖原来的value
    //因为String重写了hashCode和equals方法
    map.put("张三", 12000.0);
    map.put("李四", 14000.0);
    //HashMap支持key和value为null值
    String name = null;
    Double salary = null;
    map.put(name, salary);

    Set<Entry<String, Double>> entrySet = map.entrySet();
    for (Entry<String, Double> entry : entrySet) {
        System.out.println(entry);
    }
}

LinkedHashMap

LinkedHashMap 是 HashMap 的子类。此实现与 HashMap 的不同之处在于,后者维护着一个运行于所有条目的双重链接列表。此链接列表定义了迭代顺序,该迭代顺序通常就是将键插入到映射中的顺序(插入顺序)。

public static void main(String[] args) {
		LinkedHashMap<String,Double> map = new LinkedHashMap<>();
		map.put("张三", 10000.0);
		//key相同,新的value会覆盖原来的value
		//因为String重写了hashCode和equals方法
		map.put("张三", 12000.0);
		map.put("李四", 14000.0);
		String name = null;
		Double salary = null;
		map.put(name, salary);
		
		Set<Entry<String, Double>> entrySet = map.entrySet();
		for (Entry<String, Double> entry : entrySet) {
			System.out.println(entry);
		}
	}

TreeMap

基于红黑树(Red-Black tree)的 NavigableMap 实现。该映射根据其键的自然顺序进行排序,或者根据创建映射时提供的 Comparator 进行排序,具体取决于使用的构造方法。

代码:

public class TestTreeMap {
	@Test
	public void defaultComparableTest() {
		TreeMap<String,Integer> map = new TreeMap<>();
		map.put("Jack", 11000);
		map.put("Alice", 12000);
		map.put("zhangsan", 13000);
		map.put("baitao", 14000);
		map.put("Lucy", 15000);
		
		//String实现了Comparable接口,默认按照Unicode编码值排序
		Set<Entry<String, Integer>> entrySet = map.entrySet();
		for (Entry<String, Integer> entry : entrySet) {
			System.out.println(entry);
		}
	}
	@Test
	public void selfComparatorTest() {
		//指定定制比较器Comparator,按照Unicode编码值排序,但是忽略大小写
		TreeMap<String,Integer> map = new TreeMap<>(new Comparator<String>() {

			@Override
			public int compare(String o1, String o2) {
				return o1.compareToIgnoreCase(o2);
			}
		});
		map.put("Jack", 11000);
		map.put("Alice", 12000);
		map.put("zhangsan", 13000);
		map.put("baitao", 14000);
		map.put("Lucy", 15000);
		
		Set<Entry<String, Integer>> entrySet = map.entrySet();
		for (Entry<String, Integer> entry : entrySet) {
			System.out.println(entry);
		}
	}
}

Set集合与Map集合的关系

Set集合的底层实际上都维护了一个Map集合,Set集合中不能重复的特点就是来源于Map集合的Key不能重复。HashSet的底层是一个HashMap,LinkedHashSet的底层是一个LinkedHashMap,TreeSet的底层就是一个TreeMap。

源码分析:

  • HashSet的源码分析:
public HashSet() {
        map = new HashMap<>();
    }

    public HashSet(Collection<? extends E> c) {
        map = new HashMap<>(Math.max((int) (c.size()/.75f) + 1, 16));
        addAll(c);
    }

    public HashSet(int initialCapacity, float loadFactor) {
        map = new HashMap<>(initialCapacity, loadFactor);
    }

    public HashSet(int initialCapacity) {
        map = new HashMap<>(initialCapacity);
    }

	//这个构造器是给子类LinkedHashSet调用的
    HashSet(int initialCapacity, float loadFactor, boolean dummy) {
        map = new LinkedHashMap<>(initialCapacity, loadFactor);
    }
  • LinkedHashSet的源码分析:
 public LinkedHashSet(int initialCapacity, float loadFactor) {
        super(initialCapacity, loadFactor, true);//调用HashSet的某个构造器
    }

    public LinkedHashSet(int initialCapacity) {
        super(initialCapacity, .75f, true);//调用HashSet的某个构造器
    }

    public LinkedHashSet() {
        super(16, .75f, true);
    }

    public LinkedHashSet(Collection<? extends E> c) {
        super(Math.max(2*c.size(), 11), .75f, true);//调用HashSet的某个构造器
        addAll(c);
    }
  • TreeSet的源码分析
public TreeSet() {
        this(new TreeMap<E,Object>());
    }

    public TreeSet(Comparator<? super E> comparator) {
        this(new TreeMap<>(comparator));
    }

    public TreeSet(Collection<? extends E> c) {
        this();
        addAll(c);
    }

    public TreeSet(SortedSet<E> s) {
        this(s.comparator());
        addAll(s);
    }

Set集合的存储分析:

private static final Object PRESENT = new Object();
public boolean add(E e) {
    return map.put(e, PRESENT)==null;
}
public Iterator<E> iterator() {
    return map.keySet().iterator();
}

Map的表结构与HashMap底层分析

Hash表:

在1.8之前的Hash表的底层是一个动态数组+链表,在1.8之后Hash改成了动态数组+链表/红黑树存储数据

当存入一个数据时进行二次hash运算选择到数组中对应的槽位上,当第二次运算进入到相同的槽位,就会在该槽位上进行尾插法(1.7之前是头插法)形成链表的某一个节点,这样避免了hash冲突。而为什么在1.8之后加上了红黑树,主要是查询性能的提升,从原来的 O(n)到 O(logn)。使用红黑树来替代超过 8 个节点的链表, 通过 hash 碰撞,让 HashMap 不断产生碰撞,那么相同的 key 的位置的链表就会不断增长,当对这个 Hashmap 的相应位置进行查询的时候,就会循环遍历这个超级大的链表,性能就会下降,所以改用红黑树
Hash表结构红黑树

HashMap底层分析(重点)

HashMap底层分析图

一.创建对象后成员变量的变化
      // 默认的初始容量
      static final int DEFAULT_INITIAL_CAPACITY = 1 << 4
      // 底层数组最大容量
      static final int MAXIMUM_CAPACITY = 1 << 30;
      // 默认的加载因子/负载因子 扩容使用
      static final float DEFAULT_LOAD_FACTOR = 0.75f;
      // 树化阈值
      static final int TREEIFY_THRESHOLD = 8;
      // 反树化阈值
      static final int UNTREEIFY_THRESHOLD = 6;
      // 树化底层顺序表最小长度
      static final int MIN_TREEIFY_CAPACITY = 64;
      // 底层数组的类型
      transient Node<K,V>[] table;
      // 键值对数量
      transient int size;
      // 阈值 长度*负载因子
      int threshold;
      // 加载因子
      final float loadFactor;

       static class Node<K,V> implements Map.Entry<K,V> {
           final int hash;
           final K key;
           V value;
           Node<K,V> next;
       }

    第一次创建对象 将默认的负载因子的值 赋值给 成员变量
      public HashMap() {
            this.loadFactor = DEFAULT_LOAD_FACTOR; // all other fields defaulted
        }

二.添加数据
   2.1 首次添加 key 为null
            给底层数组开辟空间 长度为16
            threshold=12
            直接将元素放到指定的位置
   2.2 指定位置第一次添加 key 不为null
            直接添加
   2.3 指定位置非第一次添加 hash相同 key 不相同
           七上八下:
           jdk7:后续添加元素在原有数据的上面(尾部)
           jdk8:后续添加元素在原有数据的下面(尾部)

   2.4 指定位置非第一次添加 hash相同 key 相同
         新的value 替换旧的value 并将旧的value返回

   2.5 扩容和树化
       扩容:size>threshold进行扩容
            数组长度*2
            阈值*2
       树化:
           1.节点数量>=8
           2.底层数组长度>=64

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

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

相关文章

113.(cesium篇)cesium卷帘分屏效果

地图之家总目录(订阅之前必须详细了解该博客) 地图之家:cesium+leaflet+echart+地图数据+地图工具等相关内容的介绍 文章末尾处提供保证可运行完整代码包,运行如有问题,可“私信”博主。 效果如下所示: cesium卷帘分屏效果 下面献上完整代码,代码重要位置会做相应解释…

实战演练Python数据分析[pandas]

文章目录 [TOC](文章目录) 前言一、MoviesLens数据集二、美国1880-2010年的婴儿名字三、美国农业部视频数据库四、2012年联邦选举委员会数据库总结 前言 本篇文章出自于《利用Python进行数据分析》示例数据 请结合提供的示例数据&#xff0c;分析代码的功能&#xff0c;并进行…

微服务优雅上下线的实践方法

导语 本文介绍了微服务优雅上下线的实践方法及原理&#xff0c;包括适用于 Spring 应用的优雅上下线逻辑和服务预热&#xff0c;以及使用 Docker 实现无损下线的 Demo。同时&#xff0c;本文还总结了优雅上下线的价值和挑战。 作者简介 颜松柏 腾讯云微服务架构师 拥有超过…

Win10下安装TensorRT

Win10下安装TensorRT 前言相关介绍Win10下安装TensorRT查看cuda版本下载tensorrt8.xx版本&#xff0c;适用于Windows的cuda11.x的版本解压下载好的压缩包使用pip下载wheel文件遇到新问题解决方法 测试TensorRT是否安装成功 参考 前言 由于本人水平有限&#xff0c;难免出现错漏…

WAS 9.0 ND 命令行安装-基于LINUX 8

WAS 9.0 安装文件准备如下&#xff1a; gtk.x86_64_1.8.9004.20190423_2015.zip ----IM安装源文件 sdk.repo.8035.java8.linux.zip ----JAVA安装源文件 was.repo.90501.nd.zip ----WAS安装源文件 …

深度学习(27)——YOLO系列(6)

深度学习&#xff08;27&#xff09;——YOLO系列&#xff08;6&#xff09; 嗨&#xff0c;好久不见&#xff0c;昨天结束了yolov7的debug过程&#xff0c;真的在尽力句句理解&#xff0c;我想这应该是我更新的yolo系列的最后一篇&#xff0c;但是仅限于yolo&#xff0c;dete…

Day43: 123.买卖股票的最佳时机III,188.买卖股票的最佳时机IV

目录 123.买卖股票的最佳时机III 思路 188.买卖股票的最佳时机IV 思路 123.买卖股票的最佳时机III 123. 买卖股票的最佳时机 III - 力扣&#xff08;LeetCode&#xff09; 思路 1. 确定dp数组及其下标含义 一天一共就有五个状态&#xff0c; 没有操作 &#xff08…

白皮书精彩章节:从冬奥会看我们如何做到与“双碳”目标偕行

以下案例来自于《数字孪生世界白皮书&#xff08;2023版&#xff09;》 领取方式&#xff1a;公众号「EasyV数字孪生」后台回复「白皮书」即可领取&#xff01; 一、“双碳”提出背景 1、正式提出 在2020年9月22日75届联合国大会上&#xff0c;中国首次在国际公开场合提出…

Vue计算属性与监听器

文章目录 计算属性配置项 computedHTML 结构Vue 实例数据方法计算属性绑定数据和方法完整代码 监听器配置项 watch简单类型写法深度监听写法 计算属性配置项 computed 使用 Vue 实现一个商品价格计算器&#xff0c;设置一个初始单价&#xff0c;初始数量为 1&#xff0c;用户可…

开源外卖点餐系统源码:提升餐饮行业数字化转型

随着数字化时代的到来&#xff0c;餐饮行业正积极寻求数字化转型的方式来适应市场需求。开源外卖点餐系统源码成为推动餐饮行业数字化转型的有力工具。本文将介绍一个开源外卖点餐系统的源码&#xff0c;并解析其中的关键代码&#xff0c;展示如何利用开源源码来提升餐饮行业的…

漏洞攻击 --- TCP -- 半开攻击、RST攻击

TCP半开攻击&#xff08;半连接攻击&#xff09; --- syn攻击 &#xff08;1&#xff09;定义&#xff1a; sys 攻击数据是DOS攻击的一种&#xff0c;利用TCP协议缺陷&#xff0c;发送大量的半连接请求&#xff0c;耗费CPU和内存资源&#xff0c;发生在TCP三次握手中。 A向B…

2023年为何最卷的IT行业仍是很多人的首选?

最近这段时间&#xff0c;“IT行业崩盘了”、“前端已死&#xff0c;后端已亡”这些言论在网络中甚嚣尘上&#xff0c;引起了激烈的讨论。 对此&#xff0c;小编只想说&#xff1a;别再看了&#xff01;这不妥妥的传播焦虑吗&#xff1f;他们怎么只告诉你IT行业完了&#xff…

前端预览pdf文件

在前端开发中&#xff0c;很多时候我们需要进行pdf文件的预览操作&#xff0c;下面给出几种常见的预览pdf文件的方法&#xff1a; 一&#xff1a;直接浏览器打开 如果项目对pdf的预览功能要求不高&#xff0c;只是要求能够看的话&#xff0c;可以直接在浏览器上打开pdf文件的…

浅谈 java 虚拟机 JVM

前言 小亭子正在努力的学习编程&#xff0c;接下来将开启JavaEE的学习~~ 分享的文章都是学习的笔记和感悟&#xff0c;如有不妥之处希望大佬们批评指正~~ 同时如果本文对你有帮助的话&#xff0c;烦请点赞关注支持一波, 感激不尽~~ 目录 前言 JVM中的内存划分 JVM的类加载机制…

今天我们要向您介绍的是一款来自厂家的劲道半干面 - 味尚拉面

尊敬的顾客您好&#xff0c;感谢您选择我们的电商平台。今天我们要向您介绍的是一款来自厂家的劲道半干面 - 味尚拉面。 味尚拉面是一款经典的面食品牌&#xff0c;以选用高品质面粉和精选优质食材为特点&#xff0c;采用独特工艺制作而成。其中&#xff0c;味尚拉面的半干面更…

ChatGPT 最佳实践指南之:给 GPT 足够的时间“思考”

Give GPTs time to "think" 给予 GPT 足够的时间“思考” If asked to multiply 17 by 28, you might not know it instantly, but can still work it out with time. Similarly, GPTs make more reasoning errors when trying to answer right away, rather than ta…

Modbus TCP/BACnet IP/MQTT物联网网关IOT-810介绍及其典型应用

伴随着计算机技术以及互联网的发展&#xff0c;物联网这个概念已经逐渐进入我们的日常生活&#xff0c;例如智能泊车&#xff0c;智能家居&#xff0c;智能照明&#xff0c;智能楼宇等。智能楼宇是将传统的楼宇自控系统与物联网技术相融合&#xff0c;把系统中常见的传感器、设…

克服 ClickHouse 运维难题:ByteHouse 水平扩容功能上线

前言 对于分析型数据库产品&#xff0c;通过增加服务节点实现集群水平扩容&#xff0c;并提升集群性能和容量&#xff0c;是运维的必要手段。 但是对于熟悉 ClickHouse 的工程师而言&#xff0c;听到“扩容”二字一定会头疼不已。开源 ClickHouse 的 MPP 架构导致扩容成本高&…

【前缀和优化DP】ABC 222D

虽然很简单&#xff0c;但是统一一下板子&#xff0c;以防写错 D - Between Two Arrays (atcoder.jp) 题意&#xff1a; 思路&#xff1a; 直接DP即可 Code&#xff1a; #include <bits/stdc.h>#define int long longusing namespace std;const int mxn3e310; const…

ASP.NET Website 项目 .NET Framework 4.0 ~ .NET Framework 4.8支持c#哪些版本(Website)

本文讲的是Website网站项目&#xff0c;由于维护老项目Website .net framework4.0&#xff0c;遇到c#6.0语法不支持。便做了点记录 ASP.NET Website 项目 .NET Framework 4.0、 .NET Framework 4.5、 .NET Framework 4.6、 .NET Framework 4.8都支持c#哪些版本&#xff1f; 下面…