Java TreeMap
TreeMap 是一个基于 key 有序的 key value 散列表。
- map 根据其键的自然顺序排序,或者根据 map 创建时提供的 Comparator 排序
- 不是线程安全的
- key 不可以存入null
- 底层是基于红黑树实现的
TreeMap 的类结构图:
- 实现了 NavigableMap 接口,NavigableMap 又实现了Map接口,提供了导航相关的方法。
- 继承了 AbstractMap,该方法实现 Map 操作的骨干逻辑。
- 实现了 Cloneable 接口,标记该类支持 clone 方法复制
- 实现了 Serializable 接口,标记该类支持序列化
构造方法
TreeMap() // 使用键的自然排序构造一个新的空树映射。
TreeMap(Comparator<? super K> comparator) // 构造一个新的空树映射,根据给定的比较器排序。
TreeMap(Map<? extends K,? extends V> m) // 构造一个新的树映射,包含与给定映射相同的映射,按照键的自然顺序排序。
TreeMap(SortedMap<K,? extends V> m) // 构造一个新的树映射,包含相同的映射,并使用与指定排序映射相同的顺序。
关键方法
SortedMap 接口:
Comparator<? super K> comparator() // 返回用于排序此映射中的键的比较器,如果此映射使用其键的自然排序,则返回 null。
Set<Map.Entry<K,V>> entrySet() // 返回此映射中包含的映射的 Set 视图。
K firstKey() // 返回当前映射中的第一个(最低)键。
K lastKey() // 返回当前映射中的最后(最高)键。
NavigableMap 接口:
Map.Entry<K,V> ceilingEntry(K key) 返回与大于或等于给定键的最小键相关联的键值映射,如果没有这样的键则返回 null。
K ceilingKey(K key) 返回大于或等于给定键的最小键,如果没有这样的键,则返回 null。
NavigableMap<K,V> descendingMap() 返回此映射中包含的映射的倒序视图。
Map.Entry<K,V> firstEntry() 返回与该映射中最小的键关联的键值映射,如果映射为空,则返回 null。
Map.Entry<K,V> floorEntry(K key) 返回与小于或等于给定键的最大键相关联的键值映射,如果没有这样的键则返回 null。
SortedMap<K,V> headMap(K toKey) 返回该映射中键严格小于 toKey 的部分的视图。
Map.Entry<K,V> higherEntry(K key) 返回与严格大于给定键的最小键关联的键值映射,如果没有这样的键,则返回 null。
Map.Entry<K,V> lastEntry() 返回与此映射中最大键关联的键值映射,如果映射为空,则返回 null。
Map.Entry<K,V> lowerEntry(K key) 返回与严格小于给定键的最大键关联的键值映射,如果没有这样的键,则返回 null。
Map.Entry<K,V> pollFirstEntry() 删除并返回与该映射中最小的键关联的键值映射,如果映射为空,则返回 null。
Map.Entry<K,V> pollLastEntry() 删除并返回与此映射中最大键关联的键值映射,如果映射为空,则返回 null。
SortedMap<K,V> subMap(K fromKey, K toKey) 返回该映射中键范围从 fromKey(包含)到 toKey(独占)的部分的视图。
SortedMap<K,V> tailMap(K fromKey) 返回该映射中键大于或等于 fromKey 的部分的视图。
验证顺序性
@Testpublic void test1() {Map<Integer, String> treeMap = new TreeMap<>();treeMap.put(16, "a");treeMap.put(1, "b");treeMap.put(4, "c");treeMap.put(3, "d");treeMap.put(8, "e");// 遍历System.out.println("默认排序:");treeMap.forEach((key, value) -> {System.out.println("key: " + key + ", value: " + value);});// 构造方法传入比较器Map<Integer, String> tree2Map = new TreeMap<>((o1, o2) -> o2 - o1);tree2Map.put(16, "a");tree2Map.put(1, "b");tree2Map.put(4, "c");tree2Map.put(3, "d");tree2Map.put(8, "e");// 遍历System.out.println("倒序排序:");tree2Map.forEach((key, value) -> {System.out.println("key: " + key + ", value: " + value);});}
验证不能存储 null
@Testpublic void test2() {Map<Integer, String> treeMap = new TreeMap<>();treeMap.put(null, "a");}
验证 NavigableMap 相关方法
@Testpublic void test3() {NavigableMap<Integer, String> treeMap = new TreeMap<>();treeMap.put(16, "a");treeMap.put(1, "b");treeMap.put(4, "c");treeMap.put(3, "d");treeMap.put(8, "e");// 获取大于等于 5 的 keyInteger ceilingKey = treeMap.ceilingKey(5);System.out.println("ceilingKey 5 is " + ceilingKey);// 获取最大的 keyInteger lastKey = treeMap.lastKey();System.out.println("lastKey is " + lastKey);}
核心机制
实现原理
TreeMap 的底层是如何维护 key 的顺序呢?答案就是基于红黑树实现的。
红黑树是一颗 自平衡 的 排序二叉树。
二叉树 很容易理解,就是一棵树分俩叉。
上面这颗就是一颗最普通的二叉树。但是你会发现看起来不那么美观,因为你以 H 为根节点,发现左右两边高低不平衡,高度相差达到了 2。于是出现了平衡二叉树,使得左右两边高低差不多。
平衡二叉树
不管是从任何一个字母为根节点,左右两边的深度差不了 2,最多是 1。这就是平衡二叉树。把字母变成数字,还要保持这种特性怎么办呢?于是又出现了平衡二叉排序树。
平衡二叉排序树
不管是从长相(平衡),还是从规律(排序)感觉这棵树超级完美。但是有一个问题,那就是在增加删除节点的时候,你要时刻去让这棵树保持平衡,需要做太多的工作了,旋转的次数超级多,于是乎出现了红黑树。
红黑树
这就是传说中的红黑树,和平衡二叉排序树的区别就是每个节点涂上了颜色,他有下列五条性质:
每个节点都只能是红色或者黑色
根节点是黑色
每个叶节点(NIL节点,空节点)是黑色的。
如果一个结点是红的,则它两个子节点都是黑的。也就是说在一条路径上不能出现相邻的两个红色结点。
从任一节点到其每个叶子的所有路径都包含相同数目的黑色节点。
这些性质有什么优点呢?就是插入效率超级高。因为在插入一个元素的时候,最多只需三次旋转,O(1)的复杂度,但是有一点需要说明他的查询效率略微逊色于平衡二叉树,因为他比平衡二叉树会稍微不平衡最多一层,也就是说红黑树的查询性能只比相同内容的avl树最多多一次比较。如何去旋转呢?如下图所示。
首先是左旋:
然后是右旋:
红黑树更详细的内容可以参考这篇文章:segmentfault.com/a/119000001…
源码解析
成员变量
//这是一个比较器,方便插入查找元素等操作
private final Comparator<? super K> comparator;
//红黑树的根节点:每个节点是一个Entry
private transient Entry<K,V> root;
//集合元素数量
private transient int size = 0;
//集合修改的记录
private transient int modCount = 0;
comparator是一个排序器,作为key的排序规则
root是红黑树的根节点,说明的确底层用的红黑树作为数据结构。
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;Entry(K key, V value, Entry<K,V> parent) {this.key = key;this.value = value;this.parent = parent;}public K getKey() {return key;}public V getValue() {return value;}public V setValue(V value) {V oldValue = this.value;this.value = value;return oldValue;}public boolean equals(Object o) {if (!(o instanceof Map.Entry))return false;Map.Entry<?,?> e = (Map.Entry<?,?>)o;return valEquals(key,e.getKey()) && valEquals(value,e.getValue());}public int hashCode() {int keyHash = (key==null ? 0 : key.hashCode());int valueHash = (value==null ? 0 : value.hashCode());return keyHash ^ valueHash;}public String toString() {return key + "=" + value;}}
查找get方法
TreeMap基于红黑树实现,而红黑树是一种自平衡二叉查找树,所以 TreeMap 的查找操作流程和二叉查找树一致。二叉树的查找流程是这样的,先将目标值和根节点的值进行比较,如果目标值小于根节点的值,则再和根节点的左孩子进行比较。如果目标值大于根节点的值,则继续和根节点的右孩子比较。在查找过程中,如果目标值和二叉树中的某个节点值相等,则返回 true,否则返回 false。TreeMap 查找和此类似,只不过在 TreeMap 中,节点(Entry)存储的是键值对<k,v>。在查找过程中,比较的是键的大小,返回的是值,如果没找到,则返回null。TreeMap 中的查找方法是get。
public V get(Object key) {//调用 getEntry方法查找Entry<K,V> p = getEntry(key);return (p==null ? null : p. value);
}final Entry<K,V> getEntry(Object key) {/ 如果比较器为空,只是用key作为比较器查询if (comparator != null) return getEntryUsingComparator(key);if (key == null)throw new NullPointerException();Comparable<? super K> k = (Comparable<? super K>) key;// 取得root节点Entry<K,V> p = root;//核心来了:从root节点开始查找,根据比较器判断是在左子树还是右子树while (p != null) {int cmp = k.compareTo(p.key );if (cmp < 0)p = p. left;else if (cmp > 0)p = p. right;elsereturn p;}
插入put方法
我们来看下关键的插入方法,在插入时候是如何维护key的。
public V put(K key, V value) {Entry<K,V> t = root;// 1.如果根节点为 null,将新节点设为根节点if (t == null) {compare(key, key); // type (and possibly null) checkroot = new Entry<>(key, value, null);size = 1;modCount++;return null;}//如果root不为null,说明已存在元素 int cmp;Entry<K,V> parent;// split comparator and comparable pathsComparator<? super K> cpr = comparator;//如果比较器不为null 则使用比较器if (cpr != null) {//找到元素的插入位置do {parent = t;cmp = cpr.compare(key, t.key);//当前key小于节点key 向左子树查找if (cmp < 0)t = t.left;//当前key大于节点key 向右子树查找else if (cmp > 0)t = t.right;else//相等的情况下 直接更新节点值return t.setValue(value);} while (t != null);}//如果比较器为null 则使用默认比较器else {//如果key为null 则抛出异常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;}
比较关键的就是fixAfterInsertion方法, 看懂这个方法需要你对红黑树的机制比较了解。
private void fixAfterInsertion(Entry<K,V> x) {// 将新插入节点的颜色设置为红色x. color = RED;// while循环,保证新插入节点x不是根节点或者新插入节点x的父节点不是红色(这两种情况不需要调整)while (x != null && x != root && x. parent.color == RED) {// 如果新插入节点x的父节点是祖父节点的左孩子if (parentOf(x) == leftOf(parentOf (parentOf(x)))) {// 取得新插入节点x的叔叔节点Entry<K,V> y = rightOf(parentOf (parentOf(x)));// 如果新插入x的父节点是红色if (colorOf(y) == RED) {// 将x的父节点设置为黑色setColor(parentOf (x), BLACK);// 将x的叔叔节点设置为黑色setColor(y, BLACK);// 将x的祖父节点设置为红色setColor(parentOf (parentOf(x)), RED);// 将x指向祖父节点,如果x的祖父节点的父节点是红色,按照上面的步奏继续循环x = parentOf(parentOf (x));} else {// 如果新插入x的叔叔节点是黑色或缺少,且x的父节点是祖父节点的右孩子if (x == rightOf( parentOf(x))) {// 左旋父节点x = parentOf(x);rotateLeft(x);}// 如果新插入x的叔叔节点是黑色或缺少,且x的父节点是祖父节点的左孩子// 将x的父节点设置为黑色setColor(parentOf (x), BLACK);// 将x的祖父节点设置为红色setColor(parentOf (parentOf(x)), RED);// 右旋x的祖父节点rotateRight( parentOf(parentOf (x)));}} else { // 如果新插入节点x的父节点是祖父节点的右孩子和上面的相似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;
}
删除remove方法
删除remove是最复杂的方法。
public V remove(Object key) {// 根据key查找到对应的节点对象Entry<K,V> p = getEntry(key);if (p == null)return null;// 记录key对应的value,供返回使用V oldValue = p. value;// 删除节点deleteEntry(p);return oldValue;
}
private void deleteEntry(Entry<K,V> p) {modCount++;//元素个数减一size--;// 如果被删除的节点p的左孩子和右孩子都不为空,则查找其替代节if (p.left != null && p. right != null) {// 查找p的替代节点Entry<K,V> s = successor (p);p. key = s.key ;p. value = s.value ;p = s;}Entry<K,V> replacement = (p. left != null ? p.left : p. right);if (replacement != null) { // 将p的父节点拷贝给替代节点replacement. parent = p.parent ;// 如果替代节点p的父节点为空,也就是p为跟节点,则将replacement设置为根节点if (p.parent == null)root = replacement;// 如果替代节点p是其父节点的左孩子,则将replacement设置为其父节点的左孩子else if (p == p.parent. left)p. parent.left = replacement;// 如果替代节点p是其父节点的左孩子,则将replacement设置为其父节点的右孩子elsep. parent.right = replacement;// 将替代节点p的left、right、parent的指针都指向空p. left = p.right = p.parent = null;// 如果替代节点p的颜色是黑色,则需要调整红黑树以保持其平衡if (p.color == BLACK)fixAfterDeletion(replacement);} else if (p.parent == null) { // return if we are the only node.// 如果要替代节点p没有父节点,代表p为根节点,直接删除即可root = null;} else {// 如果p的颜色是黑色,则调整红黑树if (p.color == BLACK)fixAfterDeletion(p);// 下面删除替代节点pif (p.parent != null) {// 解除p的父节点对p的引用if (p == p.parent .left)p. parent.left = null;else if (p == p.parent. right)p. parent.right = null;// 解除p对p父节点的引用p. parent = null;}}}
最终还是落到了对红黑树节点的删除上,需要维持红黑树的特性,做一系列的工作。
相关文章:

Java TreeMap
TreeMap 是一个基于 key 有序的 key value 散列表。 map 根据其键的自然顺序排序,或者根据 map 创建时提供的 Comparator 排序不是线程安全的key 不可以存入null底层是基于红黑树实现的 TreeMap 的类结构图: 实现了 NavigableMap 接口,Na…...
ubuntu 内网源如何搭建 —— 筑梦之路
为什么要搭建内网源? 原因:内网开发环境由于其特定原因不能上外网,所以需要本地环境下的内网源来方便开发人员下载安装软件 搭建建议 单独使用一块磁盘来存放源文件或者单独一个目录下,避免混淆。 环境说明 ubuntu 系统 两张…...

测试用例的设计方法(黑盒)
1.基于需求的设计方法 比如针对网易邮箱进行测试:分为功能相关和非功能相关两大类 但是这么设计的话,有无数多个测试用例,我们现在看到的只是一些大概的测试用例,要想设计具体的测试用例,需要用到下面测试用例的方法…...

Shell编程入门--概念、特性、bash配置文件
目录 一、Shell概念1.定义2.分类和使用场景2.1.分类和切换2.2.使用场景 3.特性3.1.文件描述符与输出重定向3.2.历史命令---history3.3.别名 --alias3.4.命令排序执行3.5.部分快捷键3.6.通配符置换 4.脚本规范5.脚本运行方式5.1.bash脚本执行5.2.bash脚本测试 二、bash配置文件1…...
读书笔记:彼得·德鲁克《认识管理》第14章 工作、做工与员工
一、章节内容概述 虽然工作的历史与人类一样久远,但对工作展开系统研究不过是近百年之内的事,并且“做工”,也就是人从事工作,迄今为止仍很少受到 系统关注。然而我们知道,工作和做工不同,工作是客观的“事…...
diffusers库中stable Diffusion模块的解析
diffusers库中stable Diffusion模块的解析 diffusers中,stable Diffusion v1.5主要由以下几个部分组成 Out[3]: dict_keys([vae, text_encoder, tokenizer, unet, scheduler, safety_checker, feature_extractor])下面给出具体的结构说明。 “text_encoder block…...

智慧城市照明为城市节能降耗提供支持继电器开关钡铼S270
智慧城市照明:为城市节能降耗提供支持——以钡铼技术S270继电器开关为例 随着城市化进程的加速,城市照明系统的需求也日益增长。与此同时,能源消耗和环境污染问题日益严重,使得城市照明的节能减排成为重要议题。智慧城市照明系统…...
固高GTS800控制卡开发数控系统宏程序心得
在对固高GTS800控制卡做数控系统开发时,经过多年的总结与积累,总算是实现了一个数控系统的基本功能。 基本实现宏程序的译码与执行同时执行,虽然不是实时执行,但在充分利用插补缓存区的基础上,实现了相对的实时性。 …...

linux入门---线程池的模拟实现
目录标题 什么是线程池线程的封装准备工作构造函数和析构函数start函数join函数threadname函数完整代码 线程池的实现准备工作构造函数和析构函数push函数pop函数run函数完整的代码 测试代码 什么是线程池 在实现线程池之前我们先了解一下什么是线程池,所谓的池大家…...

jQuery HTML/CSS 参考文档
jQuery HTML/CSS 参考文档 文章目录 应用样式 示例属性方法示例 jQuery HTML/CSS 参考文档 应用样式 addClass( classes ) 方法可用于将定义好的样式表应用于所有匹配的元素上。可以通过空格分隔指定多个类。 示例 以下是一个简单示例,设置了para标签 <p&g…...

QT 布局管理综合实例
通过一个实例基本布局管理,演示QHBoxLayout类、QVBoxLayout类及QGridLayout类效果 本实例共用到四个布局管理器,分别是 LeftLayout、RightLayout、BottomLayout和MainLayout。 在源文件“dialog.cpp”具体代码如下: 运行效果: Se…...

使用 pubsub-js 进行消息发布订阅
npm 包地址 github 包地址 pubsub-js 是一个轻量级的 JavaScript 基于主题的消息订阅发布库 ,压缩后小于1b。它具有使用简单、性能高效、支持多平台等优点,可以很好地满足各种需求。 功能特点: 无依赖同步解耦ES3 兼容。pubsub-js 能够在…...
TA Shader基础
渲染管线 概念:GPU绘制物体的时候,标准的,流水线一样的操作 游戏引擎如何绘制物体:CPU提供绘制数据(顶点数据,纹理贴图等)给GPU,配置渲染管线(装载Shader代码到GPU&…...

VScode + opencv(cmake编译) + c++ + win配置教程
1、下载opencv 2、下载CMake 3、下载MinGW 放到一个文件夹中 并解压另外两个文件 4、cmake编译opencv 新建文件夹mingw-build 双击cmake-gui 程序会开始自动生成Makefiles等文件配置,需要耐心等待一段时间。 简单总结下:finish->configuring …...

Vue中的常用指令v-html / v-show / v-if / v-else / v-on / v-bind / v-for / v-model
前言 持续学习总结输出中,Vue中的常用指令v-html / v-show / v-if / v-else / v-on / v-bind / v-for / v-model 概念:指令(Directives)是Vue提供的带有 v- 前缀 的特殊标签属性。可以提高操作 DOM 的效率。 vue 中的指令按照不…...
ChatGPT 提问技巧
ChatGPT是由 OpenAI 训练的⼀款⼤型语⾔模型,能够和你进⾏任何领域的对话。 它能够⽣成类似于⼈类写作的⽂本。您只需要给出提示或提出问题,它就可以⽣成你想要的东⻄。 在此⻚⾯中,您将找到可与 ChatGPT ⼀起使⽤的各种提示。 只需按照下…...
2023-11-09 LeetCode每日一题(逃离火灾)
2023-11-09每日一题 一、题目编号 2258. 逃离火灾二、题目链接 点击跳转到题目位置 三、题目描述 给你一个下标从 0 开始大小为 m x n 的二维整数数组 grid ,它表示一个网格图。每个格子为下面 3 个值之一: 0 表示草地。1 表示着火的格子。2 表示一…...

阿里云-maven私服idea访问私服与组件上传
1.进入aliyun制品仓库 2. 点击 生产库-release进入 根据以上步骤修改本地 m2/setting.xml文件 3.pom.xml文件 点击设置获取url 4. idea发布组件...
Ubuntu上的TFTP服务软件
2023年11月11日,周六下午 目录 tftpd-hpa atftpd 配置和启动 tftpd-hpa 这是一个TFTP服务器软件包,提供了一个简单的TFTP服务器。 你可以使用以下命令安装它: sudo apt-get install tftpd-hpaatftpd 这是另一个常用的TFTP服务器软件包…...
jedis、lettuce与redis交互分析
概念梳理: redis是缓存服务器,jedis、lettuce都是Java语言下的redis客户端,用于与redis服务器进行交互。springboot项目中一般使用的是spring data redis,spring data redis依赖与jedis或lettuce,可以进行配置&#x…...

(LeetCode 每日一题) 3442. 奇偶频次间的最大差值 I (哈希、字符串)
题目:3442. 奇偶频次间的最大差值 I 思路 :哈希,时间复杂度0(n)。 用哈希表来记录每个字符串中字符的分布情况,哈希表这里用数组即可实现。 C版本: class Solution { public:int maxDifference(string s) {int a[26]…...
uni-app学习笔记二十二---使用vite.config.js全局导入常用依赖
在前面的练习中,每个页面需要使用ref,onShow等生命周期钩子函数时都需要像下面这样导入 import {onMounted, ref} from "vue" 如果不想每个页面都导入,需要使用node.js命令npm安装unplugin-auto-import npm install unplugin-au…...
基于Uniapp开发HarmonyOS 5.0旅游应用技术实践
一、技术选型背景 1.跨平台优势 Uniapp采用Vue.js框架,支持"一次开发,多端部署",可同步生成HarmonyOS、iOS、Android等多平台应用。 2.鸿蒙特性融合 HarmonyOS 5.0的分布式能力与原子化服务,为旅游应用带来…...

自然语言处理——Transformer
自然语言处理——Transformer 自注意力机制多头注意力机制Transformer 虽然循环神经网络可以对具有序列特性的数据非常有效,它能挖掘数据中的时序信息以及语义信息,但是它有一个很大的缺陷——很难并行化。 我们可以考虑用CNN来替代RNN,但是…...
【碎碎念】宝可梦 Mesh GO : 基于MESH网络的口袋妖怪 宝可梦GO游戏自组网系统
目录 游戏说明《宝可梦 Mesh GO》 —— 局域宝可梦探索Pokmon GO 类游戏核心理念应用场景Mesh 特性 宝可梦玩法融合设计游戏构想要素1. 地图探索(基于物理空间 广播范围)2. 野生宝可梦生成与广播3. 对战系统4. 道具与通信5. 延伸玩法 安全性设计 技术选…...

安宝特方案丨船舶智造的“AR+AI+作业标准化管理解决方案”(装配)
船舶制造装配管理现状:装配工作依赖人工经验,装配工人凭借长期实践积累的操作技巧完成零部件组装。企业通常制定了装配作业指导书,但在实际执行中,工人对指导书的理解和遵循程度参差不齐。 船舶装配过程中的挑战与需求 挑战 (1…...

【Linux】Linux 系统默认的目录及作用说明
博主介绍:✌全网粉丝23W,CSDN博客专家、Java领域优质创作者,掘金/华为云/阿里云/InfoQ等平台优质作者、专注于Java技术领域✌ 技术范围:SpringBoot、SpringCloud、Vue、SSM、HTML、Nodejs、Python、MySQL、PostgreSQL、大数据、物…...
站群服务器的应用场景都有哪些?
站群服务器主要是为了多个网站的托管和管理所设计的,可以通过集中管理和高效资源的分配,来支持多个独立的网站同时运行,让每一个网站都可以分配到独立的IP地址,避免出现IP关联的风险,用户还可以通过控制面板进行管理功…...
Caliper 配置文件解析:fisco-bcos.json
config.yaml 文件 config.yaml 是 Caliper 的主配置文件,通常包含以下内容: test:name: fisco-bcos-test # 测试名称description: Performance test of FISCO-BCOS # 测试描述workers:type: local # 工作进程类型number: 5 # 工作进程数量monitor:type: - docker- pro…...
DiscuzX3.5发帖json api
参考文章:PHP实现独立Discuz站外发帖(直连操作数据库)_discuz 发帖api-CSDN博客 简单改造了一下,适配我自己的需求 有一个站点存在多个采集站,我想通过主站拿标题,采集站拿内容 使用到的sql如下 CREATE TABLE pre_forum_post_…...