Java数据结构之Map与Set

news2024/7/7 17:55:44

文章目录

  • 一、搜索
    • (一)概念及场景
    • (二)模型
  • 二、Map
    • (一)介绍
    • (二)Map常用方法说明
      • 1.需要注意的几个点
      • 2.特别注意的几个方法
        • (1)V getOrdefault(Object key,V defaultValue),这个方法可以减少我们出bug的概率
        • (2)Set<Map.Entry<K,V>> entrySet()
          • <1>关于Map.Entry<K,V>的说明
    • (三)TreeMap使用案例
  • 三、Set
    • (一)常见方法说明
      • 1.需要注意的几点
  • 四、哈希表
    • (一)概念
    • (二)哈希冲突
    • (三)冲突的避免
      • 1. 哈希函数设计
      • 2. 装填因子调节(重点)
    • (四)冲突的处理
      • 1. 闭散列
      • 2.开散列/哈希桶(重点,Java8中桶满后会变成二叉搜索树)
        • 开散列冲突严重时的解决办法
        • 开散列的性能分析
    • (五)哈希表和 Java 类集的关系
    • (六)HashMap源码分析
      • 1.HashMap是可序列化的
      • 2.HashMap中各种final值的意义
        • (1)对树化的分析
        • (2)HashMap的初始容量为什么必须是2的次幂
      • 3.真正分配容量内存的位置
      • 4.HashMap中阈值(什么时候就需要对存储进行扩容)的确定
      • 5.HashMap何时扩容
      • 6.扩容时空间和阈值的变化
      • 7.HashMap中hash的取值
      • 8.哈希桶中链表插入采用尾插法
  • 五、Map的几种遍历方法
    • (一)toString
    • (二)知道所有的key,然后手动一个一个遍历(可以尝试KeySet方法)
    • (三)实例化entrySet内部类
  • 六、TreeMap(TreeSet)和HashMap(HashSet)的区别

一、搜索

(一)概念及场景

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

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

二分查找比较适合静态类型的查找,即尽量不会对序列中的元素进行增删改,但是现实中的许多情况下又必须在查找时进行一定的增删操作,即动态查找,Map和Set就是一种适合动态查找的集合容器,查找效率既高,增加删除元素的成本也很小

(二)模型

我们在搜索的时候一般把搜索的数据称为关键字(Key),和关键字对应的称为值(Value),这两个组合起来并称为键值对,所以存在了两种模型:

  1. key模型,就是单纯的关键字,可能是Integer,String等等类型
  2. Key-Value模型,Key是独一无二作为关键字的,Value则提供一种辅助,比如:
  • 字符串出现的次数
  • 在一家餐厅点外卖的备注

二、Map

(一)介绍

Map集合框架

Map是一个独立的接口类,该类没有继承Collection和Iterable接口,因此我们在前面数据结构常用的方法不一定有,也无法使用迭代器for-each语句,但是提供了toString()方法,因此如何实现自主遍历是我们后面要介绍的重点之一
该类中存储的是结构的键值对,并且K一定是唯一的,不能重复

(二)Map常用方法说明

这个时候上次学的二叉搜索树就派上用场了,作者以TreeMap为例,即底层是红黑树的数据结构的Key-Value值

方法功能
V get(Object key)返回key对应的value值
V getOrdefault(Object key,V defaultValue)返回key对应的value,key不存在时,返回默认值
V put(K key,V value)增加key和对应的value或更改原有key的value值
V remove(Object key)删除对应的Key-Value键值对
Set keySet()返回所有key的不重复集合
Collection values()返回所有value的可重复集合
Set<Map.Entry<K,V>>entrySet()返回所有的key-value映射关系
boolean containsKey(Object key)判断是否存在key
boolean containsValue(Object value)判断是否包含value

1.需要注意的几个点

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

2.特别注意的几个方法

(1)V getOrdefault(Object key,V defaultValue),这个方法可以减少我们出bug的概率

(2)Set<Map.Entry<K,V>> entrySet()

我们之前说过,Map无法自己实现遍历,只能用toString()方法或者自己本来就知道所有的key值然后一个一个搜索。实际这个问题是我们无法访问到节点,root被设成private修饰符了,而其他节点必须依靠root节点才能访问到,所以加了这个方法来解决这个问题的
<>中的是类型,即Map.Entry<K,V>,而在Map中静态内部类Entry<K,V>就是节点的存储形式
从源码中我们可以看出,节点的方法实际上是public的,我们可以直接使用
Entry<K,V>类图

所以我们现在要解决的问题就是怎么才能得到节点呢???就想到了迭代器。但是迭代器需要实现Iterable接口,Map并没有实现Iterable接口,因此才又创建了一个实例内部类EntrySet来实现Iterable接口,具体示例代码见最下方遍历Map操作具体流程图如下图:

EntrySet继承图

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

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

方法功能
K getKey()返回entry中的key
V getValue()返回entry中的value
V setValue(V value)将键值对中的value替换为指定value

注意:Map.Entry<K,V>并没有提供设置Key的方法

(三)TreeMap使用案例

代码示例:

public static void main(String[] args) {
    TreeMap<String,Integer> map = new TreeMap<>();
    //V put(K key,V value) | 增加key和对应的value或更改原有key的value值
    map.put("hello", 1);
    map.put("world", 2);
    System.out.println(map);
    //V get(Object key) | 返回key对应的value值
    System.out.println(map.get("world"));
    /**
    * V getOrdefault(Object key,V defaultValue) | 返回key对应的value,key不存在时,返回默认值
    */
    //注意,由于我们的value类型时Integer类型的,因此如果没有找到对应的key,并且采用int类型接收将极其危险
    //因为此时会return null,而null无法自动拆包,int无法接收,就会报空指针异常错误
    /*错误示范*/
    //int num = map.get("main");
    /*正确示范*/
    Integer num1 = map.get("main");
    System.out.println(num1);
    System.out.println(map.getOrDefault("main",0));
    //Set<K> keySet() | 返回所有key的不重复集合
    Set<String> set = map.keySet();
    System.out.println(set);
    //Collection<V> values()
    Collection<Integer> collection = map.values();
    System.out.println(collection);
    //Set<Map.Entry<K,V>>entrySet()
    Set<Map.Entry<String, Integer>> mapSet = map.entrySet();
    for (Map.Entry<String, Integer> entry: mapSet) {
        System.out.println("key:" + entry.getKey() + " value:" + entry.getValue());
    }
    //V remove(Object key) | 删除对应的Key-Value键值对
    map.remove("world");
    System.out.println(map);
    //boolean containsKey(Object key)
    System.out.println(map.containsKey("world"));
    //boolean containsValue(Object value)
    System.out.println(map.containsValue(1));
}

运行结果:
运行图

三、Set

Set和Map的区别主要有两点:Set继承了Collection的接口,Set中只存储key
Set集合框架

(一)常见方法说明

方法功能
boolean add(E e)添加元素,但重复元素不会被添加成功
void clear()清空集合
boolean contains(Object o)判断 o 是否在集合中
Iterator iterator()返回迭代器
boolean remove(Object o)删除集合中的 o
int size()返回set中元素的个数
boolean isEmpty()检测set是否为空,空返回true,否则返回false
Object[] toArray()将set中的元素转换为数组返回
boolean containsAll(Collection<?> c)集合c中的元素是否在set中全部存在,是返回true,否则返回false
boolean addAll(Collection<? extends E> c)将集合c中的元素添加到set中,可以达到去重的效果

1.需要注意的几点

1.Set是继承自Collection的一个接口
2.Set只存储了key,并且要求key唯一
3.Set底层是用Map来实现的,Set使用key和Object的一个默认对象作为键值对来方便使用Map的集合
4.Set中的最大功能就是对集合中的元素去重
5.实现set接口的常用类有TreeSet和HashSet
6.Set中的key不能修改,只能删除,然后重新插入
7.Set中不能插入null的key

四、哈希表

(一)概念

构造一种数据结构,通过某种函数使元素的存储位置与它的关键码之间能够建立一一映射的关系,查找时通过函数直接查找到存储位置,那么就可以不经过任何比较,一次直接从表中得到要搜索的元素。
这种方法即为哈希(散列)方法,哈希方法中使用的转换函数称为哈希(散列)函数,构造出来的结构叫做哈希表(HashTable)(或散列表)
哈希表原理

(二)哈希冲突

如下图,不同关键字通过相同的哈希函数得到相同的哈希地址,这种现象称为哈希冲突或者哈希碰撞
把具有不同关键码(Key)而具有相同哈希地址的数据元素称为“同义词
哈希冲突

(三)冲突的避免

首先明确,哈希表底层数组的容量往往比需要存储的数据量小,因此冲突是必然的,我们能做的就是降低冲突率

1. 哈希函数设计

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

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

常见的哈希函数

  1. 直接定址法

根据关键码来设线性函数取哈希地址:Hash(Key) = A * Key + B,
优点:简单,均匀
缺点:需要事先知道关键码的分布情况
使用场景:适合查找比较小且连续的情况
2.除留余数法
当哈希表的数组大小为 m 时,取一个不大于m,但最接近或者等于m的质数p作为除数,按照哈希函数:Hash(Key) = key%p(p<=m),将关键码转为哈希地址

注意:哈希函数设计的越精妙,产生哈希冲突的可能性就越小,但无法避免哈希冲突

2. 装填因子调节(重点)

哈希表的装填因子定义为:α=填入表中的元素/散列表的长度
由上述公式我们就能看到,α是散列表装满程度的标志因子,由于表长是定长,α与填入表中的元素个数成正比。因此,α越大,表明填入表中的元素越多,产生冲突的可能性就越大,相反,就越小
由于HashMap是采用开放定址法来处理冲突的,因此负载因子在HashMap中是极为重要的,一般HashMap的负载因子取值都要求在0.75左右

已知哈希表中已有的关键字个数是不可变的,那我们只能调整的哈希表中的数组的大小

(四)冲突的处理

处理哈希冲突常用的两种解决办法:闭散列开散列

1. 闭散列

闭散列(开放定址法):当发生哈希冲突时,如果哈希表未被填满,说明在哈希表中必然还有空位置,那么就可以把key放在冲突位置的下一个空位置中。寻找下一个空位置的方法:

(1) 线性探测

从发生冲突的位置开始向后探测,知道寻找到下一个空位置为止,如下图:
线性探测

采用线性探测处理哈希冲突时,不能随便物理删除哈希表中已有的元素,如果直接删除元素,可能会对其他元素造成影响,导致其他元素查找不到,因此线性探测采用标记的伪代码来删除一个元素

(2)二次探测
线性探测的缺陷就是将产生冲突的数据堆积在一块,这与其找下一个空位置有关系,因为找空位置的方式就是挨着往后逐个去找,因此二次探测为了避免该问题,找下一个空位置的方法为:Hi = (H0 + i2)% m, 或者:Hi = (H0 - i2)% m。其中:i=1,2,3…,H0是通过散列函数Hash(x)对元素的关键码 key 进行计算得到的位置,m是表的大小.如下图:
二次探测

研究表明:当表的长度为质数且表装载因子a不超过0.5时,新的表项一定能够插入,而且任何一个位置都不会被探查两次。因此只要表中有一半的空位置,就不会存在表满的问题。在搜索时可以不考虑表装满的情况,但在插入时必须确保表的装载因子a不超过0.5,如果超出必须考虑增容

因此,闭散列最大的缺陷就是空间利用率比较低,这也是哈希的缺陷

2.开散列/哈希桶(重点,Java8中桶满后会变成二叉搜索树)

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

由上图可知,开散列中的每个桶中存放的都是发生哈希冲突的元素
开散列可以认为是把一个在大集合中的搜索问题转化为在小集合中做搜索

开散列冲突严重时的解决办法

如果冲突严重,就意味着小集合的搜索性能也不好,这个时候我们就可以将这个所谓的小集合搜索问题继续进行转化,例如:

  1. 每个桶的背后是另一个哈希表
  2. 每个桶的背后是一棵搜索树

开散列的性能分析

虽然作者用了很多的语句介绍哈希冲突,但在实际使用过程中,我们认为哈希表的冲突率是不高的,冲突个数是可控的,也就是每个桶中的链表的长度是一个常数,因此,通常情况下,我们认为哈希表的插入/删除/查找时间复杂度是O(1)

(五)哈希表和 Java 类集的关系

1.HashMap和HashSet就是 Java 中用哈希表实现的集合类
2.Java中使用的是哈希桶的方式解决冲突的
3.Java会在冲突链表长度大于一定阈值之后,将链表转为搜索树(红黑树)
4.Java中计算哈希值是调用类中的hashCode方法,进行key的相等性比较是调用key的equals方法。所以如果要用自定义类作为 HashMap 的 key 或者 HashSet 的值,必须覆写 hashCode 和 equals 方法,而且要做到 equals 相等的对象,hashCode 一定是一致的

(六)HashMap源码分析

1.HashMap是可序列化的

public class HashMap<K,V> extends AbstractMap<K,V> implements Map<K,V>, Cloneable, Serializable {

源码分析图:
HashMap是可序列化的

2.HashMap中各种final值的意义

static final int DEFAULT_INITIAL_CAPACITY = 1 << 4; // aka 16
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;

源码分析图:
final解释图

(1)对树化的分析

树化的条件:HashMap的容量 >= 64 && 某一个哈希桶中链表的长度 >= 8
源码分析图:
树化分析图

(2)HashMap的初始容量为什么必须是2的次幂

解释:由于确定新插入的TreeNode节点的存储位置的时候需要 % 存储空间(存储空间大小设为n),而Java8底层是采用异或的方式进行取模运算,即哈希值与(n - 1)进行异或,那么我们就要保证(n - 1)的从最高位的1算起,到最低位的值都要是1,避免出现0,否则和哈希值进行异或的时候就会导致某些哈希桶的值一直取不到,既浪费空间,又提高了出现哈希碰撞的几率,因此HashMap在进行容量扩容的时候,扩容结果也一定是 2 的次幂
源码分析图:
容量设置分析图

3.真正分配容量内存的位置

首先,容量空间的分配并不是在构造方法中,而是在put方法中
其次,如果构造方法中传了具体大小的存储空间,那么最终分配的空间就是大于等于参数的2的次幂的最小值
代码分析图:
第一次分配空间的代码分析

4.HashMap中阈值(什么时候就需要对存储进行扩容)的确定

在构造方法中,有参和无参的构造方法的阈值是不同的

(1)无参的构造方法中只将装填因子设为默认值,阈值没变,还是0
(2)只传了容量的构造方法,调用了两个参数的构造方法
(3)两个参数的构造方法中,也并没有关心用户传过来的容量,只是将装填因子和存储元素的阈值进行了设置,阈值被设置成了大于等于容量的最小的2次幂的值,在第一次put的时候进行再次设置

源码分析图:
HashMap中阈值的确定

5.HashMap何时扩容

当插入的元素数量size > 阈值的时候,我们进行扩容
源代码:

if (++size > threshold)
    resize();

6.扩容时空间和阈值的变化

结论:当原来的空间大小 >= 16时,扩容后空间和阈值都是二倍,因此扩容越来越大,阈值可能会比负载因子 * 空间的大小小一些,当原来空间小于16时,阈值 = 负载因子 * 空间大小

源码分析图:
扩容时空间和阈值的变化

7.HashMap中hash的取值

目的:为了增强hash值的随机性,减少哈希冲突的几率
源码分析图:
HashMap中hash的取值图

8.哈希桶中链表插入采用尾插法

五、Map的几种遍历方法

(一)toString

代码示例:

public static void main(String[] args) {
    HashMap<String,Integer> map = new HashMap<>();
    map.put("hello", 1);
    map.put("world", 2);
    System.out.println(map);
}

运行结果:
ToString方法截图

(二)知道所有的key,然后手动一个一个遍历(可以尝试KeySet方法)

代码示例:

public static void main(String[] args) {
    HashMap<String,Integer> map = new HashMap<>();
    map.put("hello", 1);
    map.put("world", 2);
    System.out.println("key: " + "hello " + "val: " + map.get("hello"));
    System.out.println("key: " + "world " + "val: " + map.get("world"));
}

运行结果:
遍历方法截图

(三)实例化entrySet内部类

该内部类实现了Iterable接口,可以使用迭代器,for-each遍历
代码示例:

public static void main(String[] args) {
    HashMap<String,Integer> map = new HashMap<>();
    map.put("hello", 1);
    map.put("world", 2);
    Set<Map.Entry<String, Integer>> set = map.entrySet();
    for (Map.Entry<String, Integer> entry: set) {
        System.out.println("key: " + entry.getKey() + " value: " + entry.getValue());
    }
    System.out.println();
    Iterator<Map.Entry<String, Integer>> iterator = set.iterator();
    while(iterator.hasNext()) {
        System.out.println(iterator.next());
    }
}

运行结果:
实例化entrySet内部类截图

六、TreeMap(TreeSet)和HashMap(HashSet)的区别

Map(Set)TreeMap(TreeSet)HashMap(HashSet)
底层结构红黑树哈希表
插入/删除/查找时间复杂度O(log2N)O(1)
是否有序有序无序
线程安全不安全不安全
插入/删除/查找区别先进行比较,再根据红黑树的特性插入删除先通过哈希函数计算哈希地址,再进行插入删除操作
比较与覆写key必须要能够比较key不需要比较,自定义类型需要覆写HashCode方法和equals方法
应用场景需要key有序场景下key有不有序不关心,但是查找效率要高

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

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

相关文章

【DL with Pytorch】第 5 章 :风格迁移

&#x1f50e;大家好&#xff0c;我是Sonhhxg_柒&#xff0c;希望你看完之后&#xff0c;能对你有所帮助&#xff0c;不足请指正&#xff01;共同学习交流&#x1f50e; &#x1f4dd;个人主页&#xff0d;Sonhhxg_柒的博客_CSDN博客 &#x1f4c3; &#x1f381;欢迎各位→点赞…

[JavaEE]计算机是如何工作的

专栏简介: JavaEE从入门到进阶 题目来源: leetcode,牛客,剑指offer. 创作目标: 记录学习JavaEE学习历程 希望在提升自己的同时,帮助他人,,与大家一起共同进步,互相成长. 学历代表过去,能力代表现在,学习能力代表未来! 目录 1. javaEE概述 2. 计算机发展史 3. 冯诺依曼体系 …

java面试强基(15)

说明一下public static void main(String args[])这段声明里每个关键字的作用? ​ public: main方法是Java程序运行时调用的第一个方法&#xff0c;因此它必须对Java环境可见。所以可见性设置为 pulic. ​ static: Java平台调用这个方法时不会创建这个类的一个实例&#xf…

如何将带GPS的网络化的软件定义无线电接收机应用于分布式和移动频谱监测?(二)

GPS定位和测向的四种技术 知道感兴趣信号的位置对于许多应用很重要。军事用户获得了更好的态势感知能力&#xff0c;诸如机场或公用事业基础设施之类的敏感设施可以找到RF干扰源&#xff0c;电信公司可以识别恶意发射机或其他干扰其覆盖范围的设备。通过嵌入式GPS功能了解测量…

中国什么时候能办世界杯?

自从1930年在乌拉圭举办了第一届世界杯以来&#xff0c;到现在已经成功举办了22届&#xff0c;然而这22届里&#xff0c;光是欧洲就举办了11届&#xff0c;南美洲5届&#xff0c;中北美洲3届&#xff0c;亚洲2届&#xff0c;非洲1届。 说到这里不难发现&#xff0c;他们之间分布…

Azure DevOps Server 用户组加入 Azure AD Domain Service 管理用户

一&#xff0c;引言 今天我们继续讲解 Azure DevOps Server 的内容&#xff0c;对于管理用户组除了在 Azure DevOps Server 服务器上添加管理员方式外&#xff0c;还有没有其他方式&#xff0c;Azure DevOps 需要加入Azure ADDS 服务域后&#xff0c;Azure DevOps Server 的管理…

[附源码]计算机毕业设计springboot基于vue+mysql开发的考试系统

项目运行 环境配置&#xff1a; Jdk1.8 Tomcat7.0 Mysql HBuilderX&#xff08;Webstorm也行&#xff09; Eclispe&#xff08;IntelliJ IDEA,Eclispe,MyEclispe,Sts都支持&#xff09;。 项目技术&#xff1a; SSM mybatis Maven Vue 等等组成&#xff0c;B/S模式 M…

图扑软件荣获第七届“创客中国”中小企业创新创业大赛优胜奖!

2022 年 11 月 17 日&#xff0c;由工业和信息化部、财政部共同主办的第七届“创客中国”中小企业创新创业大赛全国总决赛在浙江杭州落下帷幕。 本次《第七届“创客中国”中小企业创新创业大赛》举办目的&#xff0c;意在加大优质中小企业梯度培育力度&#xff0c;进一步提升中…

ProcessDB实时/时序数据库——ODBC之连接数据库

目录 前言 一、安装ProcessDB-ODBC驱动 1.下载ProcessDB-ODBC驱动 2.安装ProcessDB-ODBC驱动 二、配置ProcessDB数据源 三、JAVA连接ProcessDB数据库 前言 ProcessDB实时/时序数据库支持ODBC连接数据库&#xff0c;接下来将和大家分享下如何使用ODBC操作ProcessDB实时/时…

Java基础之《netty(5)—NIO之Selector》

一、基本介绍 1、Java的NIO&#xff0c;用非阻塞的IO方式&#xff0c;可以用一个线程&#xff0c;处理多个的客户端连接&#xff0c;就会使用到Selector&#xff08;选择器&#xff09;。 2、Selector能够检测多个注册的通道上是否有事件发生&#xff08;注意&#xff1a;多个…

[附源码]SSM计算机毕业设计新闻发布和评论管理系统JAVA

项目运行 环境配置&#xff1a; Jdk1.8 Tomcat7.0 Mysql HBuilderX&#xff08;Webstorm也行&#xff09; Eclispe&#xff08;IntelliJ IDEA,Eclispe,MyEclispe,Sts都支持&#xff09;。 项目技术&#xff1a; SSM mybatis Maven Vue 等等组成&#xff0c;B/S模式 M…

【冰糖Python】Python 中的 assert 语句

assert 判断一个表达式的真假&#xff0c;在表达式条件为 false 的时候触发异常&#xff0c;返回错误 具体用法&#xff1a; assert expression assert expression [, arguments] 实际用例&#xff1a; 注意以上使用&#xff1a; 1、条件为True时&#xff0c;assert不执行…

基于PHP+MySQL高校教务选课系统的设计与实现

兴趣是最好的老师,只有学生选择了自己感兴趣的课程才能够更好的进行学习,目前有很多高校的选课中出现很多问题,如学生对开设的课程不了解,代选课程等等,这些问题多而繁杂,不容易解决。 本系统就是为了学生开放的在线选课系统,而网络选课系统是帮助学生了解到所学课程的内容,多自…

Android——使用ContentProvider共享数据

实验名称&#xff1a; 使用ContentProvider共享数据 实验目的&#xff1a; &#xff08;1&#xff09;能使用ContentProvider共享数据 &#xff08;2&#xff09;能使用内容观察者观察其他程序的数据变化 实验内容及原理&…

H2N-Hyp-FF-OH, 2493080-84-3

Hyp-Phe-Phe 是一种三肽&#xff0c;通过 Phe 环的芳香相互作用形成螺旋状的薄片&#xff0c;构成一个交叉螺旋结构。Hyp-Phe-Phe 具有很高的剪切压电特性&#xff0c;可作为一种压电材料。Hyp-Phe-Phe is a tripeptide that forms helical-like sheets via aromatic interacti…

Flowable定时器与实时流程图江南一点雨

1. 定时器 1.1. 流程定义定时激活 在之前松哥给小伙伴们介绍流程定义的时候&#xff0c;流程都是定义好之后立马就激活了&#xff0c;其实在流程定义的这个过程中&#xff0c;我们还可以设置一个激活时间&#xff0c;也就是流程定义好之后&#xff0c;并不会立马激活&#xf…

数据存储——存储视频

数据存储——存储视频视频的数字化一、视频采样二、视频量化总结&#xff1a;视频数字化的过程视频的数字化 1.视频是图像&#xff08;帧&#xff09;在时间上的表示 图象是离散的视频&#xff0c;视频是连续的图像 2.视频储存 每一帧图像或帧被转化为位模式并加以储存 一、视…

(3)点云数据处理学习——KD树近邻搜索

1、主要参考资料 &#xff08;1&#xff09;kd树原理 数组索引的kdtree建立及简明快速的k近邻搜索方法 &#xff08;2&#xff09;open3d 爆肝5万字 Open3D 点云数据处理基础&#xff08;Python版&#xff09;&#xff09;-技术圈 (3)视频参考 【PythonOpen3D处理点云数据…

12【MyBatis注解开发】

文章目录三、Mybatis注解开发3.1 快速入门3.1.1 常用注解说明3.1.2 注解实现开发3.2 注解实现一对一映射3.2.1 接口3.2.2 测试类3.3 注解实现一对多映射3.2.1 接口3.2.2 测试类三、Mybatis注解开发 3.1 快速入门 3.1.1 常用注解说明 注解功能Insert新增Update更新Delete删除…

创新指南|如何以STEPPS模型6招打造病毒式传播产品

从爆款产品到网络流行语&#xff0c;这种流行绝对不是依赖于运气&#xff0c;更不是神话。让人们喜欢读某些文章&#xff0c;让人们尝试某项新服务&#xff0c;甚至是投票竞选&#xff0c;这些事情的背后都有STEPPS模型的驱动&#xff0c;遵循或者仅仅应用STEPPS中的某几条&…