当前位置: 首页 > news >正文

JAVA集合之Map >>HashMap/Hashtable/TreeMap/LinkedHashMap结构

Map 是一种键-值对(key-value)集合,键不可以重复,值可以重复。常见的实现类有:HashMap、Hashtable、TreeMap、LinkedHashMap等。

HashMap&Hashtable

HashMap:数据结构为哈希表,允许使用 null 值和 null 键,线程不同步。Hashtable与HashMap差不多,但是线程同步的,且不可以存入null键null值。

JDK1.7的Hashmap 结构是,数组+链表的形式进行存储的。存入时通过KEY的hashCode % capacity(数组的容量),找到数组位置,每个数组位置保存的都是一个链表结构,用于存储一个或多个对象。

JDK1.8后Hashmap结构进行优化,数组+链表+红黑树。当链表长度达到一定阈值时,链表结构会变为红黑树(当链表阈值长度=8时,会进入红黑树判断:当数组长度<64时,会优先扩容,当数组长度>= 64时才转红黑树),红黑树的优点在于,平衡链表结构的算法,提升查询性能。具体参考:红黑树算法。

JDK1.8为了避免多线程数据冲突及死锁的做了优化(去除了rehash),使用了高低位运算,来迁移数据,低位,直接迁移到原来的位置,高位,迁移到扩容后的位置(i + 原来Hashmap 数组的大小)。

JDK1.8对HashMap Get或Put寻址取模算法(hashCode % capacity)进行了优化,将其改为了hash & (length-1) 这种二进制的位运算进行判断,计算结果等同于取模算法,但是效率高于它。这种运算需要保证length-1的二进制码都为1,才能将元素均匀的分布到数组下标中,所以在hashmap底层代码内,规定了数组的容量必须是2的指数次幂(因为只有2的指数次幂 -1的二进制编码才全部为1),才能保证保存对象不会发生数组越界。具体参考:HashMap 底层源码。

hash碰撞

上面介绍了如何找到对应的下标进行保存对象,但是在操作多个对象时,是有可能在计算后得到相同的数组下标,也就是我们的hash碰撞,这个时候hashmap就会把相同下标的对象以链表的方式进行存储,当链表的长度达到一定的阈值(默认8)时,就会改用红黑树就行保存,红黑树的优点在于,平衡链表结构的算法,提升查询性能。链表查询的时间复杂度为O(n),红黑树的时间复杂的为O(logn)。

加载因子为0.75的作用

Hash存储对象,并不能保证利用率是100%(每个数组下标都能存放数据),所以为了每个对象能均匀散列在数组中,设置了加载因子为0.75(如,HashMap 的初始化容量是16,载因子为0.5,那么当HashMap中有16*0.5=8个元素时,HashMap 就会进行扩容)。0.75是选择了时间,与空间之间选择平衡。如果大于0.75,利用率高了,但是HashMap发生hash碰撞的几率就会变高,hash碰撞就会导致我们的链表或红黑树节点深度更深,所以性能会相对下降。如果小于0.75 ,那么我们的空间的利用率也就会变的更低。所以 hashMap 建议为默认的 0.75 在时间与空间之间的平衡选择。

参考源码:

public class HashMap<K,V> extends AbstractMap<K,V> implements Map<K,V>, Cloneable, Serializable {/*** The default initial capacity - MUST be a power of two.* 翻译:默认初始容量-必须是2的幂*/static final int DEFAULT_INITIAL_CAPACITY = 1 << 4; // aka 16/*** 最大容量 1<<30.*/static final int MAXIMUM_CAPACITY = 1 << 30;/*** The load factor used when none specified in constructor.* 加载因子默认0.75*/static final float DEFAULT_LOAD_FACTOR = 0.75f;/*** 链表转成红黑树的阈值:当链表长度 > 该值时*/static final int TREEIFY_THRESHOLD = 8;/*** 红黑树转为链表的阈值(当原有的红黑树内数量 < 6时,则将红黑树转换成链表)*/static final int UNTREEIFY_THRESHOLD = 6;/*** 最小树形化容量阈值:当哈希表中数组的容量>该值时+链表长度>TREEIFY_THRESHOLD则链表转红黑树*/static final int MIN_TREEIFY_CAPACITY = 64;/*** 记录HashMap的结构修改次数*/transient int modCount;/*** The number of key-value mappings contained in this map.*/transient int size;/*** The next size value at which to resize (capacity * load factor).* 翻译: 记录当map存储了多少个数组元素时开始扩容 (capacity * load factor)*/int threshold;/*** Constructs an empty <tt>HashMap</tt> with the default initial capacity* (16) and the default load factor (0.75).*/public HashMap() {this.loadFactor = DEFAULT_LOAD_FACTOR; // all other fields defaulted}public V put(K key, V value) {return putVal(hash(key), key, value, false, true);}static final int hash(Object key) {int h;return (key == null) ? 0 : (h = key.hashCode()) ^ (h >>> 16);}final V putVal(int hash, K key, V value, boolean onlyIfAbsent,boolean evict) {Node<K,V>[] tab; Node<K,V> p; int n, i;// 第一次操作,先初始化容量 16 if ((tab = table) == null || (n = tab.length) == 0)n = (tab = resize()).length;// 通过hash获取数组元素,如果为空则将元素插入到当前位置if ((p = tab[i = (n - 1) & hash]) == null)tab[i] = newNode(hash, key, value, null);else {Node<K,V> e; K k;// 如果key相同,则e=p ,下面代码中会通过 e 将新元素覆盖掉就旧元素if (p.hash == hash && ((k = p.key) == key || (key != null && key.equals(k))))e = p;// 判断是否是 TreeNode else if (p instanceof TreeNode)e = ((TreeNode<K,V>)p).putTreeVal(this, tab, hash, key, value);else {// 遍历以链表或红黑树方式存放元素for (int binCount = 0; ; ++binCount) {if ((e = p.next) == null) {p.next = newNode(hash, key, value, null);// 如果链表大小>=TREEIFY_THRESHOLD 则进入扩容或转红黑树逻辑if (binCount >= TREEIFY_THRESHOLD - 1) // -1 for 1st//扩容或转红黑树的方法treeifyBin(tab, hash);break;}if (e.hash == hash &&((k = e.key) == key || (key != null && key.equals(k))))break;p = e;}}if (e != null) { // existing mapping for keyV oldValue = e.value;if (!onlyIfAbsent || oldValue == null)e.value = value;afterNodeAccess(e);    //使用LinkHashMap时会进行回调的方法return oldValue;}}++modCount;//当map存储的数组个数大于 threshold(capacity * load factor) 开始扩容if (++size > threshold)resize(); //扩容代码不贴,可以自行源码中参考   afterNodeInsertion(evict); //使用LinkHashMap时会进行回调的方法return null;}/*** 扩容或转红黑树方法逻辑*/final void treeifyBin(Node<K,V>[] tab, int hash) {int n, index; Node<K,V> e;// 数组长度如果小于 MIN_TREEIFY_CAPACITY 则进行扩容if (tab == null || (n = tab.length) < MIN_TREEIFY_CAPACITY)resize();// 转为红黑树else if ((e = tab[index = (n - 1) & hash]) != null) {TreeNode<K,V> hd = null, tl = null;do {TreeNode<K,V> p = replacementTreeNode(e, null);if (tl == null)hd = p;else {p.prev = tl;tl.next = p;}tl = p;} while ((e = e.next) != null);if ((tab[index] = hd) != null)hd.treeify(tab);}}// Create a regular (non-tree) nodeNode<K,V> newNode(int hash, K key, V value, Node<K,V> next) {return new Node<>(hash, key, value, next);}// For conversion from TreeNodes to plain nodesNode<K,V> replacementNode(Node<K,V> p, Node<K,V> next) {return new Node<>(p.hash, p.key, p.value, next);}/*** 一般用户在链表时使用的结构*/static class Node<K,V> implements Map.Entry<K,V> {final int hash;final K key;V value;Node<K,V> next;Node(int hash, K key, V value, Node<K,V> next) {this.hash = hash;this.key = key;this.value = value;this.next = next;}public final K getKey()        { return key; }public final V getValue()      { return value; }public final String toString() { return key + "=" + value; }public final int hashCode() {return Objects.hashCode(key) ^ Objects.hashCode(value);}public final V setValue(V newValue) {V oldValue = value;value = newValue;return oldValue;}public final boolean equals(Object o) {if (o == this)return true;if (o instanceof Map.Entry) {Map.Entry<?,?> e = (Map.Entry<?,?>)o;if (Objects.equals(key, e.getKey()) &&Objects.equals(value, e.getValue()))return true;}return false;}}/*** 转红黑树时使用的结构*/static final class TreeNode<K,V> extends LinkedHashMap.Entry<K,V> {TreeNode<K,V> parent;  // red-black tree linksTreeNode<K,V> left;TreeNode<K,V> right;TreeNode<K,V> prev;    // needed to unlink next upon deletionboolean red;TreeNode(int hash, K key, V val, Node<K,V> next) {super(hash, key, val, next);}......下面代码太多,可以自行源码中查看}}

上面源码中,根据put流程说明,通过源码跟进,我们就可以看出HashMap的结构、hash碰撞时如何保存、扩容逻辑、什么时候开始转红黑树、及一些重要参数的作用等。

TreeMap

TreeMap:基于红黑色树的顺序访问的Map,与HashMap区别在于HashMap中的元素是没有顺序的,而TreeMap中所有的元素都是有某一固定顺序的。TreeMap继承SortedMap类,他保持键的有序顺序,用于给map集合中的键进行排序(排序方法和TreeSet一样,实现comparable 或comparator 接口)

参考源码:

public class TreeMap<K,V> extends AbstractMap<K,V> implements NavigableMap<K,V>, Cloneable, java.io.Serializable
{/*** 排序接口*/private final Comparator<? super K> comparator;private transient Entry<K,V> root;public V put(K key, V value) {Entry<K,V> t = root;//如果root第一个节点为空,则将元素保存到rootif (t == null) {//为插入节点进行排序compare(key, key); // type (and possibly null) checkroot = new Entry<>(key, value, null);size = 1;modCount++;return null;}int cmp;Entry<K,V> parent;// split comparator and comparable pathsComparator<? super K> cpr = comparator;// comparator 非空则使用 comparator 判断排序if (cpr != null) {// 基于根节点遍历,通过左小,右大的方式存入到树节点中(注意:最后字节点会插入null,下面代码会用补充)do {parent = t;cmp = cpr.compare(key, t.key);if (cmp < 0)t = t.left;else if (cmp > 0)t = t.right;elsereturn t.setValue(value);} while (t != null);}// comparator 为空,则使用Comparable 判断排序,其他逻辑与上面差不多else {if (key == null)throw new NullPointerException();@SuppressWarnings("unchecked")Comparable<? super K> k = (Comparable<? super K>) key;do {parent = t;cmp = k.compareTo(t.key);if (cmp < 0)t = t.left;else if (cmp > 0)t = t.right;elsereturn t.setValue(value);} while (t != null);}Entry<K,V> e = new Entry<>(key, value, parent);// 对最后字节点进行补充if (cmp < 0)parent.left = e;elseparent.right = e;//进行红黑树的旋转等操作fixAfterInsertion(e);size++;modCount++;return null;}// 通过两个Key比较来排序,comparator 不存在则使用 Comparablefinal int compare(Object k1, Object k2) {return comparator==null ? ((Comparable<? super K>)k1).compareTo((K)k2): comparator.compare((K)k1, (K)k2);}static final class Entry<K,V> implements Map.Entry<K,V> {K key;V value;//左子节点Entry<K,V> left;//又子节点Entry<K,V> right;//父节点Entry<K,V> parent;//颜色标记-红色/黑色boolean color = BLACK;/*** Make a new cell with given key, value, and parent, and with* {@code null} child links, and BLACK color.*/Entry(K key, V value, Entry<K,V> parent) {this.key = key;this.value = value;this.parent = parent;}public V setValue(V value) {V oldValue = this.value;this.value = value;return oldValue;}......省略}}

源码中可以看到,TreeMap内部使用的是Entry结构,Entry结构中,又声明了 letf ,right等变量用于保存左、右子节点,color标记颜色(红/黑),源码开始形成的是二叉树,执行了fixAfterInsertion(e);后才生成的红黑树对整个树进行平衡。详见如下fixAfterInsertion源码

public class TreeMap<K,V> extends AbstractMap<K,V> implements NavigableMap<K,V>, Cloneable, java.io.Serializable
{//红/黑色标记private static final boolean RED   = false;private static final boolean BLACK = true;//获取颜色private static <K,V> boolean colorOf(Entry<K,V> p) {return (p == null ? BLACK : p.color);}//获取父节点private static <K,V> Entry<K,V> parentOf(Entry<K,V> p) {return (p == null ? null: p.parent);}//设置颜色private static <K,V> void setColor(Entry<K,V> p, boolean c) {if (p != null)p.color = c;}//获取左节点private static <K,V> Entry<K,V> leftOf(Entry<K,V> p) {return (p == null) ? null: p.left;}//获取又节点private static <K,V> Entry<K,V> rightOf(Entry<K,V> p) {return (p == null) ? null: p.right;}/** 向左旋转 */private void rotateLeft(Entry<K,V> p) {if (p != null) {Entry<K,V> r = p.right;p.right = r.left;if (r.left != null)r.left.parent = p;r.parent = p.parent;if (p.parent == null)root = r;else if (p.parent.left == p)p.parent.left = r;elsep.parent.right = r;r.left = p;p.parent = r;}}/**向右旋转 */private void rotateRight(Entry<K,V> p) {if (p != null) {Entry<K,V> l = p.left;p.left = l.right;if (l.right != null) l.right.parent = p;l.parent = p.parent;if (p.parent == null)root = l;else if (p.parent.right == p)p.parent.right = l;else p.parent.left = l;l.right = p;p.parent = l;}}//红黑树平衡设置private void fixAfterInsertion(Entry<K,V> x) {//新节设置为红色x.color = RED;//循环条件=非空&非根节点&x的父节点颜色为红色while (x != null && x != root && x.parent.color == RED) {//判断父节点是否是在左边的节点if (parentOf(x) == leftOf(parentOf(parentOf(x)))) {//获取祖父节点的右子节点Entry<K,V> y = rightOf(parentOf(parentOf(x)));//右叔叔节点为红色,则更新相关颜色if (colorOf(y) == RED) {                    setColor(parentOf(x), BLACK);        //父节点设置为黑色setColor(y, BLACK);                  //叔叔节点置为黑色setColor(parentOf(parentOf(x)), RED);//祖父节点置为红色x = parentOf(parentOf(x));           //将继续循环赋予X,继续循环} else {//如果x在右节点-则进行左旋父节点if (x == rightOf(parentOf(x))) {x = parentOf(x);rotateLeft(x);   //左旋父节点}setColor(parentOf(x), BLACK);        //父节点设置为黑色setColor(parentOf(parentOf(x)), RED);//祖父节点置为红色rotateRight(parentOf(parentOf(x)));  //右旋祖父节点}} else {    //否则是右边的节点 - 其他逻辑与上面的相似Entry<K,V> y = leftOf(parentOf(parentOf(x)));if (colorOf(y) == RED) {setColor(parentOf(x), BLACK);setColor(y, BLACK);setColor(parentOf(parentOf(x)), RED);x = parentOf(parentOf(x));} else {if (x == leftOf(parentOf(x))) {x = parentOf(x);rotateRight(x);}setColor(parentOf(x), BLACK);setColor(parentOf(parentOf(x)), RED);rotateLeft(parentOf(parentOf(x)));}}}root.color = BLACK;}}

LinkedHashMap

LinkedHashMap:继承自 HashMap,在 HashMap 基础上,通过维护一个具有双重链表解决了 HashMap 不能随时保持遍历顺序和插入顺序一致的问题。另外LinkedHashMap可以实现快速的查询第一个元素(First)跟结尾(Last)

对于LinkedHashMap详解,可参考如下文章:java之LinkedHashMap详解_linkedhashmap使用_三木易不爱卷的博客-CSDN博客

相关文章:

JAVA集合之Map >>HashMap/Hashtable/TreeMap/LinkedHashMap结构

Map 是一种键-值对&#xff08;key-value&#xff09;集合&#xff0c;键不可以重复&#xff0c;值可以重复。常见的实现类有&#xff1a;HashMap、Hashtable、TreeMap、LinkedHashMap等。 HashMap&Hashtable HashMap&#xff1a;数据结构为哈希表&#xff0c;允许使用 n…...

JavaScript从零开始 学习记录(一)

前言 选择视频课程之前&#xff0c;不仅查阅了资料&#xff0c;还询问了网友&#xff0c;最终敲定了学习黑马前端的视频教程&#xff0c;学了5小节&#xff0c;发现挺对自己口味的且从反响来看&#xff0c;还是相当不错的&#xff0c;便打算利用这个寒假学完 笔记范围 从这节…...

C++项目——高并发内存池(3)--central cache整体设计

1.central cache的介绍 1.1框架思想 1.1.1哈希映射 centralcache其实也是哈希桶结构的&#xff0c;并且central cache和thread cacha的哈希映射关系是一致的。目的为了&#xff0c;当thread cache某一个哈希桶下没有内存块时&#xff0c;可以利用之前编写的SizeClass::Index…...

Spring Boot 整合 MyBatis 配置等案例教程

运行环境&#xff1a;JDK 7 或 8、Maven 3.0 技术栈&#xff1a;SpringBoot 1.5、SpringBoot Mybatis Starter 1.2 、MyBatis 3.4 前言 距离第一篇 Spring Boot 系列的博文 3 个月了。《Springboot 整合 Mybatis 的完整 Web 案例》第一篇出来是 XML 配置 SQL 的形式。虽然 XM…...

比特数据结构与算法(第三章_下)队列的概念和实现(力扣:225+232+622)

一、队列&#xff08;Queue&#xff09;队列的概念&#xff1a;① 队列只允许在一端进行插入数据操作&#xff0c;在另一端进行删除数据操作的特殊线性表。② 入队列&#xff0c;进行插入操作的一端称为 队尾。出队列&#xff0c;进行删除操作的一端称为 队头。③ 队列中的元素…...

c++提高篇——STL容器实现打分系统

一、案例说明 有5名选手:选手ABCDE&#xff0c;10个评委分别对每一名选手打分&#xff0c;去除最高分&#xff0c;去除评委中最低分&#xff0c;取平均分。 二、案例实现 在实现这个系统时&#xff0c;我们规划一下实现的步骤以及细节&#xff1a; 1、创建一个选手类&#x…...

【图片上传记录三】element-ui组件详解与封装(自定义上传、限制文件大小、格式以及图片尺寸)

业务上有需求是前端上传 jpg/png/gif 格式, 并且 尺寸为 150px * 150px,300px*300px,428*428px 的图片 同时在上传的同时需要携带用户的个人信息以及其他额外信息 因此在 element-upload 基础之上 实现这个需求需要在上传前检查图片的大小&#xff0c;格式以及尺寸如何上传也成…...

一个golang版本管理工具

GitHub - moqsien/gvc: GVC is a productive tool to manage your dev environment for multi platforms and machines. | GVC 是一个用于快速配置和管理多机器跨平台的开发环境的生产力工具。 目前&#xff0c;gvc拥有以下功能或特点&#xff1a; go编译器自动安装和添加环…...

SpringBoot整合Spring Security过滤器链加载执行流程源码分析

文章目录1.引言2.Spring Security过滤器链加载1.2.注册名为 springSecurityFilterChain的过滤器2、查看 DelegatingFilterProxy类3.查看 FilterChainProxy类3.1 查看 doFilterInternal方法。3.2 查看 getFilters方法。4 查看 SecurityFilterChain接口5 查看 SpringBootWebSecur…...

Jest使用

一、测试到底测什么 提到测试的时候&#xff0c;即使是最简单的一个代码块可能都让初学者不知所措。最常问的问题的是“我怎么知道要测试什么&#xff1f;”。如果你正在写一个 Web 应用&#xff0c;那么你每个页面每个页面的测试用户交互的方式&#xff0c;就是一个很好的开端…...

定位于企业数字化底座,开箱可用(spring cloud+Vue)基础框架,赶紧收藏!

项目介绍&#xff1a;JVS是什么&#xff1f;JVS是企业级应用构建的基础脚手架&#xff0c;提供开箱即用的基础功能集成&#xff0c;其中集成了账户管理、租户管理、用户权限体系、三方登录、环境配置、各种业务日志等功能&#xff0c;还提供了对接低代码、数据中台的能力。JVS能…...

java字符统计

问题描述 给定一个只包含大写字母的字符串 &#xfffd; S, 请你输出其中出现次数最多的字符。 如果有多个字母均出现了最多次, 按字母表顺序依次输出所有这些字母。 输入格式 一个只包含大写字母的字符串 &#xfffd; S. 输出格式 若干个大写字母&#xff0c;代表答案。 …...

C#:Krypton控件使用方法详解(第八讲) ——kryptonBreadCrumb

今天介绍的Krypton控件中的kryptonBreadCrumb&#xff0c;下面开始介绍这个控件的属性&#xff1a;首先要介绍的是RootItem属性和外观属性&#xff1a;RootItem属性组中包含属性如下&#xff1a;image属性&#xff1a;代表在文字对象的前方插入一个图片&#xff0c;属性值如下图…...

2023从0开始学性能(1) —— 性能测试基础【持续更新】

背景 不知道各位大佬有没遇到上面的情况&#xff0c;性能这个东西到底是什么&#xff0c;还是以前的358原则吗&#xff1f;明显并不是适用于现在了。多次想踏入性能测试门槛都以失败告终&#xff0c;这次就以系列的方式来督促自己真正踏进性能测试的门槛。 什么是性能测试 通…...

如何通过一台 iPhone 申请一个 icloud 邮箱账号 后缀为 @icloud.com

总目录 iOS开发笔记目录 从一无所知到入门 文章目录需求关键步骤步骤后续需求 在 iPhone 自带的邮箱软件中添加账号&#xff0c;排第一位的是 iCloud 邮箱&#xff1a; 选 iCloud 之后&#xff1a; 提示信息是exampleicloud.com&#xff0c;也就是说是有icloud.com为域的邮箱…...

SQL89 计算总和

描述OrderItems表代表订单信息&#xff0c;包括字段&#xff1a;订单号order_num和item_price商品售出价格、quantity商品数量。order_numitem_pricequantitya110105a211100a21200a421121a5510a2119a775【问题】编写 SQL 语句&#xff0c;根据订单号聚合&#xff0c;返回订单总…...

Netty高级应用之:编解码器与群聊天室开发

Netty高级应用之&#xff1a;编解码器与群聊天室开发 文章目录Netty高级应用之&#xff1a;编解码器与群聊天室开发Netty编解码器Java的编解码Netty编解码器概念解码器(Decoder)编码器(Encoder)编码解码器CodecNetty案例-群聊天室聊天室服务端编写聊天室客户端编写Netty编解码器…...

Vue的生命周期

Vue的生命周期是指Vue实例从创建到销毁的过程&#xff0c;它包括了以下几个阶段&#xff1a;初始化、编译、挂载、更新、渲染和销毁。 初始化&#xff1a;Vue实例创建时&#xff0c;会执行初始化过程&#xff0c;主要包括以下几个步骤&#xff1a; 初始化数据&#xff1a;Vue…...

MySQL —— 数据库基础

文章目录1. centos7 安装Mysql2. 数据库的概念3. 数据库下创建库&#xff0c;表4. 库&#xff0c;表 的本质5. 数据库服务器 和 库 &#xff0c;表的关系6. MySQL架构7. 存储引擎前言&#xff1a; 数据库是对数据进行管理的软件。1. centos7 安装Mysql 需要把系统自带的MySQL给…...

多线程知识点

多线程 基本知识 创建线程的常用三种方式&#xff1a; 继承Thread类实现Runnable接口实现Callable接口&#xff08;JDK1.5>&#xff09; public class ThreadTest extends Thread {Overridepublic void run() {System.out.println(this.getName() "..开始.."…...

四旋翼变形控制:RL与MPC在混合动力学中的对比

1. 四旋翼变形控制的技术挑战与解决方案四旋翼变形控制&#xff08;Quadrotor Morpho-Transition&#xff09;是当前机器人领域最具挑战性的前沿技术之一。这项技术使机器人能够在空中完成形态变换&#xff0c;实现从飞行模式到地面模式的平滑切换。想象一下&#xff0c;一架四…...

小说下载器终极指南:一站式解决100+网站小说保存难题

小说下载器终极指南&#xff1a;一站式解决100网站小说保存难题 【免费下载链接】novel-downloader 一个可扩展的通用型小说下载器。 项目地址: https://gitcode.com/gh_mirrors/no/novel-downloader 在数字阅读时代&#xff0c;你是否曾因小说突然下架、网站404或网络中…...

CentOS 7下‘Development Tools’和‘开发工具’组有区别吗?实测告诉你答案

CentOS 7下‘Development Tools’与‘开发工具’的隐藏关联&#xff1a;技术细节全解析在Linux系统管理中&#xff0c;yum的软件包组功能一直是个既实用又充满谜团的领域。特别是当系统语言环境与软件包元数据语言不一致时&#xff0c;开发者们常常会遇到一个有趣的现象&#x…...

机器学习模型评估中的构念效度:超越基准测试分数的科学推断

1. 项目概述与核心问题在机器学习的日常研究和工程实践中&#xff0c;我们每天都在和各种各样的基准测试&#xff08;Benchmark&#xff09;打交道。无论是为了比较新提出的ResNet变体在ImageNet上的Top-1准确率&#xff0c;还是评估一个大型语言模型在MMLU上的常识推理能力&am…...

告别拍脑袋规划!用ArcGIS做绿道选线:如何科学量化坡度、水域、道路成本并加权计算

科学规划绿道的ArcGIS高阶技法&#xff1a;从成本栅格构建到最优路径生成绿道规划从来不是简单的"两点之间直线最短"&#xff0c;而是需要综合考虑地形、生态、人文等多维因素的复杂决策过程。传统规划中常见的"拍脑袋"决策方式&#xff0c;往往导致建成后…...

内存占用3KB!极致瘦身释放MCU无限可能

极致小体积&#xff0c;给工业领域带来了无限的可能&#xff1a;更低硬件成本&#xff0c;更小芯片体积&#xff0c;更低功耗&#xff0c;更高可靠性&#xff0c;让每一颗小MCU都拥有大系统的完整能力。 https://www.bilibili.com/video/BV1eZLi6PEjc/?spm_id_from333.1387.ho…...

2026论文降AI怎么挑?亲测好用工具附免费降AI指南

“您的论文AIGC率为42%&#xff0c;超出学校30%的合格线&#xff0c;请修改后重新提交。”赶毕业论文的同学这段时间估计没少收到这样的提醒。2026年知网、万方、维普等主流平台的AI检测算法持续迭代&#xff0c;把AI生成内容改到符合学校要求&#xff0c;已经成了毕业生的刚需…...

基于MaixCam的延时摄影系统:从硬件选型到Python编程全解析

1. 项目概述&#xff1a;用MaixCam打造你的专属延时摄影工坊延时摄影&#xff0c;这个听起来有点专业、甚至带点“魔法”色彩的词&#xff0c;其实离我们并不遥远。想想看&#xff0c;把一朵花从含苞到绽放的几天时间&#xff0c;压缩成十几秒的惊艳绽放&#xff1b;或者把一座…...

HDI 高密度互连板阶数的深度理解

一、概述高密度互连板&#xff08;High Density Interconnector, HDI&#xff09;是通过激光微孔技术和逐层积层工艺实现高密度布线的印制电路板。其阶数划分是行业内统一的技术标准&#xff0c;核心依据为独立积层压合次数与配套激光盲孔制程次数&#xff0c;而非单面层数或钻…...

如何快速批量下载高质量歌词:ZonyLrcToolsX跨平台终极解决方案

如何快速批量下载高质量歌词&#xff1a;ZonyLrcToolsX跨平台终极解决方案 【免费下载链接】ZonyLrcToolsX ZonyLrcToolsX 是一个能够方便地下载歌词的小软件。 项目地址: https://gitcode.com/gh_mirrors/zo/ZonyLrcToolsX 还在为本地音乐库缺少歌词而烦恼吗&#xff1…...