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 是一种键-值对(key-value)集合,键不可以重复,值可以重复。常见的实现类有:HashMap、Hashtable、TreeMap、LinkedHashMap等。 HashMap&Hashtable HashMap:数据结构为哈希表,允许使用 n…...
JavaScript从零开始 学习记录(一)
前言 选择视频课程之前,不仅查阅了资料,还询问了网友,最终敲定了学习黑马前端的视频教程,学了5小节,发现挺对自己口味的且从反响来看,还是相当不错的,便打算利用这个寒假学完 笔记范围 从这节…...
C++项目——高并发内存池(3)--central cache整体设计
1.central cache的介绍 1.1框架思想 1.1.1哈希映射 centralcache其实也是哈希桶结构的,并且central cache和thread cacha的哈希映射关系是一致的。目的为了,当thread cache某一个哈希桶下没有内存块时,可以利用之前编写的SizeClass::Index…...
Spring Boot 整合 MyBatis 配置等案例教程
运行环境:JDK 7 或 8、Maven 3.0 技术栈:SpringBoot 1.5、SpringBoot Mybatis Starter 1.2 、MyBatis 3.4 前言 距离第一篇 Spring Boot 系列的博文 3 个月了。《Springboot 整合 Mybatis 的完整 Web 案例》第一篇出来是 XML 配置 SQL 的形式。虽然 XM…...
比特数据结构与算法(第三章_下)队列的概念和实现(力扣:225+232+622)
一、队列(Queue)队列的概念:① 队列只允许在一端进行插入数据操作,在另一端进行删除数据操作的特殊线性表。② 入队列,进行插入操作的一端称为 队尾。出队列,进行删除操作的一端称为 队头。③ 队列中的元素…...
c++提高篇——STL容器实现打分系统
一、案例说明 有5名选手:选手ABCDE,10个评委分别对每一名选手打分,去除最高分,去除评委中最低分,取平均分。 二、案例实现 在实现这个系统时,我们规划一下实现的步骤以及细节: 1、创建一个选手类&#x…...
【图片上传记录三】element-ui组件详解与封装(自定义上传、限制文件大小、格式以及图片尺寸)
业务上有需求是前端上传 jpg/png/gif 格式, 并且 尺寸为 150px * 150px,300px*300px,428*428px 的图片 同时在上传的同时需要携带用户的个人信息以及其他额外信息 因此在 element-upload 基础之上 实现这个需求需要在上传前检查图片的大小,格式以及尺寸如何上传也成…...
一个golang版本管理工具
GitHub - moqsien/gvc: GVC is a productive tool to manage your dev environment for multi platforms and machines. | GVC 是一个用于快速配置和管理多机器跨平台的开发环境的生产力工具。 目前,gvc拥有以下功能或特点: 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使用
一、测试到底测什么 提到测试的时候,即使是最简单的一个代码块可能都让初学者不知所措。最常问的问题的是“我怎么知道要测试什么?”。如果你正在写一个 Web 应用,那么你每个页面每个页面的测试用户交互的方式,就是一个很好的开端…...
定位于企业数字化底座,开箱可用(spring cloud+Vue)基础框架,赶紧收藏!
项目介绍:JVS是什么?JVS是企业级应用构建的基础脚手架,提供开箱即用的基础功能集成,其中集成了账户管理、租户管理、用户权限体系、三方登录、环境配置、各种业务日志等功能,还提供了对接低代码、数据中台的能力。JVS能…...
java字符统计
问题描述 给定一个只包含大写字母的字符串 � S, 请你输出其中出现次数最多的字符。 如果有多个字母均出现了最多次, 按字母表顺序依次输出所有这些字母。 输入格式 一个只包含大写字母的字符串 � S. 输出格式 若干个大写字母,代表答案。 …...
C#:Krypton控件使用方法详解(第八讲) ——kryptonBreadCrumb
今天介绍的Krypton控件中的kryptonBreadCrumb,下面开始介绍这个控件的属性:首先要介绍的是RootItem属性和外观属性:RootItem属性组中包含属性如下:image属性:代表在文字对象的前方插入一个图片,属性值如下图…...
2023从0开始学性能(1) —— 性能测试基础【持续更新】
背景 不知道各位大佬有没遇到上面的情况,性能这个东西到底是什么,还是以前的358原则吗?明显并不是适用于现在了。多次想踏入性能测试门槛都以失败告终,这次就以系列的方式来督促自己真正踏进性能测试的门槛。 什么是性能测试 通…...
如何通过一台 iPhone 申请一个 icloud 邮箱账号 后缀为 @icloud.com
总目录 iOS开发笔记目录 从一无所知到入门 文章目录需求关键步骤步骤后续需求 在 iPhone 自带的邮箱软件中添加账号,排第一位的是 iCloud 邮箱: 选 iCloud 之后: 提示信息是exampleicloud.com,也就是说是有icloud.com为域的邮箱…...
SQL89 计算总和
描述OrderItems表代表订单信息,包括字段:订单号order_num和item_price商品售出价格、quantity商品数量。order_numitem_pricequantitya110105a211100a21200a421121a5510a2119a775【问题】编写 SQL 语句,根据订单号聚合,返回订单总…...
Netty高级应用之:编解码器与群聊天室开发
Netty高级应用之:编解码器与群聊天室开发 文章目录Netty高级应用之:编解码器与群聊天室开发Netty编解码器Java的编解码Netty编解码器概念解码器(Decoder)编码器(Encoder)编码解码器CodecNetty案例-群聊天室聊天室服务端编写聊天室客户端编写Netty编解码器…...
Vue的生命周期
Vue的生命周期是指Vue实例从创建到销毁的过程,它包括了以下几个阶段:初始化、编译、挂载、更新、渲染和销毁。 初始化:Vue实例创建时,会执行初始化过程,主要包括以下几个步骤: 初始化数据:Vue…...
MySQL —— 数据库基础
文章目录1. centos7 安装Mysql2. 数据库的概念3. 数据库下创建库,表4. 库,表 的本质5. 数据库服务器 和 库 ,表的关系6. MySQL架构7. 存储引擎前言: 数据库是对数据进行管理的软件。1. centos7 安装Mysql 需要把系统自带的MySQL给…...
多线程知识点
多线程 基本知识 创建线程的常用三种方式: 继承Thread类实现Runnable接口实现Callable接口(JDK1.5>) public class ThreadTest extends Thread {Overridepublic void run() {System.out.println(this.getName() "..开始.."…...
8k长序列建模,蛋白质语言模型Prot42仅利用目标蛋白序列即可生成高亲和力结合剂
蛋白质结合剂(如抗体、抑制肽)在疾病诊断、成像分析及靶向药物递送等关键场景中发挥着不可替代的作用。传统上,高特异性蛋白质结合剂的开发高度依赖噬菌体展示、定向进化等实验技术,但这类方法普遍面临资源消耗巨大、研发周期冗长…...
java 实现excel文件转pdf | 无水印 | 无限制
文章目录 目录 文章目录 前言 1.项目远程仓库配置 2.pom文件引入相关依赖 3.代码破解 二、Excel转PDF 1.代码实现 2.Aspose.License.xml 授权文件 总结 前言 java处理excel转pdf一直没找到什么好用的免费jar包工具,自己手写的难度,恐怕高级程序员花费一年的事件,也…...
深入浅出:JavaScript 中的 `window.crypto.getRandomValues()` 方法
深入浅出:JavaScript 中的 window.crypto.getRandomValues() 方法 在现代 Web 开发中,随机数的生成看似简单,却隐藏着许多玄机。无论是生成密码、加密密钥,还是创建安全令牌,随机数的质量直接关系到系统的安全性。Jav…...
基于当前项目通过npm包形式暴露公共组件
1.package.sjon文件配置 其中xh-flowable就是暴露出去的npm包名 2.创建tpyes文件夹,并新增内容 3.创建package文件夹...
vue3 字体颜色设置的多种方式
在Vue 3中设置字体颜色可以通过多种方式实现,这取决于你是想在组件内部直接设置,还是在CSS/SCSS/LESS等样式文件中定义。以下是几种常见的方法: 1. 内联样式 你可以直接在模板中使用style绑定来设置字体颜色。 <template><div :s…...
【决胜公务员考试】求职OMG——见面课测验1
2025最新版!!!6.8截至答题,大家注意呀! 博主码字不易点个关注吧,祝期末顺利~~ 1.单选题(2分) 下列说法错误的是:( B ) A.选调生属于公务员系统 B.公务员属于事业编 C.选调生有基层锻炼的要求 D…...
第 86 场周赛:矩阵中的幻方、钥匙和房间、将数组拆分成斐波那契序列、猜猜这个单词
Q1、[中等] 矩阵中的幻方 1、题目描述 3 x 3 的幻方是一个填充有 从 1 到 9 的不同数字的 3 x 3 矩阵,其中每行,每列以及两条对角线上的各数之和都相等。 给定一个由整数组成的row x col 的 grid,其中有多少个 3 3 的 “幻方” 子矩阵&am…...
JVM暂停(Stop-The-World,STW)的原因分类及对应排查方案
JVM暂停(Stop-The-World,STW)的完整原因分类及对应排查方案,结合JVM运行机制和常见故障场景整理而成: 一、GC相关暂停 1. 安全点(Safepoint)阻塞 现象:JVM暂停但无GC日志,日志显示No GCs detected。原因:JVM等待所有线程进入安全点(如…...
【碎碎念】宝可梦 Mesh GO : 基于MESH网络的口袋妖怪 宝可梦GO游戏自组网系统
目录 游戏说明《宝可梦 Mesh GO》 —— 局域宝可梦探索Pokmon GO 类游戏核心理念应用场景Mesh 特性 宝可梦玩法融合设计游戏构想要素1. 地图探索(基于物理空间 广播范围)2. 野生宝可梦生成与广播3. 对战系统4. 道具与通信5. 延伸玩法 安全性设计 技术选…...
Device Mapper 机制
Device Mapper 机制详解 Device Mapper(简称 DM)是 Linux 内核中的一套通用块设备映射框架,为 LVM、加密磁盘、RAID 等提供底层支持。本文将详细介绍 Device Mapper 的原理、实现、内核配置、常用工具、操作测试流程,并配以详细的…...
