Collention集合基础知识

Array
  • 数组是一种连续的内存空间存储相同数据类型数据的线性数据结构
  1. 数组获取其他元素的地址值

寻址公式
a[i] = baseaddress + i*datatypesize

  1. 为什么数组索引从0开始 从1开始不行吗
    • 从0开始寻址公式

a[i] = baseaddress + i*datatypesize

  • 从1开始寻址公式

a[i] = baseaddress + (i-1)*datatypesize 效率没有从0开始高

  1. 对于cpu来说增加了一个减法指令

根据数组索引获取元素的时候会用索引和寻址公式来计算内存所对应的元素数据
寻址公式为a[i] = baseaddress + i*datatypesize
如果数组从1开始寻址公式 就需要增加一次减法操作 对于cpu来说就多了一个指令

  1. 数组查找时间复杂度
  • 索引查询

数组元素的访问是通过下标来访问 计算机通过数组的首地址和寻址公式 能够很快速的找到想要访问的元素

  • 未知索引查询

如果数组未排序 只能遍历查询每一个数组 O(n)

  1. 如果是已排序的数组 可以通过二分查询 O(logn)
  2. 操作数组的时间复杂度

数组是一段连续的内存空间 因此为了保证数组的连续性会使数组的插入和删除的效率变得很低O(n)

ArrayList

实现源码
成员变量

    /*** ArrayList的默认容量,为10。*/private static final int DEFAULT_CAPACITY = 10;/*** 一个空的对象数组,用于表示空的ArrayList实例。*/private static final Object[] EMPTY_ELEMENTDATA = {};/**也是一个空的对象数组,但用于表示默认大小的空ArrayList实例。当向这个ArrayList添加第一个元素时,它会被扩展到DEFAULT_CAPACITY*/private static final Object[] DEFAULTCAPACITY_EMPTY_ELEMENTDATA = {};/**是一个transient类型的Object数组,用于存储ArrayList的元素。ArrayList的容量就是这个数组的长度*/transient Object[] elementData; /**ArrayList的大小,即它包含的元素数量。*/private int size;

构造方法

   public ArrayList(int initialCapacity) {if (initialCapacity > 0) {this.elementData = new Object[initialCapacity];} else if (initialCapacity == 0) {this.elementData = EMPTY_ELEMENTDATA;} else {throw new IllegalArgumentException("Illegal Capacity: "+initialCapacity);}}

参数initialCapacity指定列表的初始容量。

如果initialCapacity大于0,则创建一个具有指定容量的空元素数组。

如果initialCapacity等于0,则使用空元素数组EMPTY_ELEMENTDATA。

如果initialCapacity小于0,则抛出IllegalArgumentException异常,提示非法容量。

public ArrayList() {this.elementData = DEFAULTCAPACITY_EMPTY_ELEMENTDATA;}

初始化一个空的ArrayList对象。它将元素数据elementData设置为一个默认容量的空数组DEFAULTCAPACITY_EMPTY_ELEMENTDATA,以便后续添加元素时能够存储。这个构造函数适用于在创建ArrayList对象时不需要指定初始容量的情况

    public ArrayList(Collection<? extends E> c) {Object[] a = c.toArray();if ((size = a.length) != 0) {if (c.getClass() == ArrayList.class) {elementData = a;} else {elementData = Arrays.copyOf(a, size, Object[].class);}} else {// replace with empty array.elementData = EMPTY_ELEMENTDATA;}}

该函数是ArrayList的构造函数,它接受一个Collection类型的参数c,并根据参数c的内容初始化一个ArrayList对象。首先将参数c转换为Object数组a,然后判断数组a的长度是否为0,如果不为0,则判断参数c的类型是否为ArrayList类型,如果是,则直接将数组a赋值给elementData成员变量;如果不是,则通过Arrays.copyOf方法创建一个新的Object数组,并将数组a的内容复制到新数组中,最后将新数组赋值给elementData成员变量。如果数组a的长度为0,则直接将EMPTY_ELEMENTDATA赋值给elementData成员变量

ArrayList.add(i) 分析
public class Array {public static void main(String[] args) {ArrayList<Integer> array = new ArrayList<>();array.add(-1);}
}

add()

    public boolean add(E e) {ensureCapacityInternal(size + 1);  // Increments modCount!!elementData[size++] = e;return true;}

调用ensureCapacityInternal(size + 1)方法来确保集合的容量足够容纳新元素

    private void ensureCapacityInternal(int minCapacity) {计算容量ensureExplicitCapacity(calculateCapacity(elementData, minCapacity));}

计算容量

    private static int calculateCapacity(Object[] elementData, int minCapacity) {if (elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA) {return Math.max(DEFAULT_CAPACITY, minCapacity);}return minCapacity;}
private void ensureExplicitCapacity(int minCapacity) {modCount++; // 1. 增加修改次数计数器modCount的值,这通常用于实现如ArrayList等集合的fail-fast机制,当在迭代过程中检测到modCount变化时会抛出 ConcurrentModificationException。// overflow-conscious code // 2. 注释提示此段代码考虑了溢出情况的处理if (minCapacity - elementData.length > 0) // 3. 检查传入的最小容量minCapacity是否大于当前数组elementData的长度grow(minCapacity); // 4. 如果确实需要扩容,则调用grow方法。grow方法会负责计算新的容量(通常是旧容量的1.5倍,并处理潜在的溢出问题),然后重新分配数组空间并将原数据复制到新数组中。
}

当之前扩容的值和当前元素数组长度相同进行扩容
容量不够进行扩容

    private void grow(int minCapacity) {// overflow-conscious codeint oldCapacity = elementData.length;int newCapacity = oldCapacity + (oldCapacity >> 1);if (newCapacity - minCapacity < 0)newCapacity = minCapacity;if (newCapacity - MAX_ARRAY_SIZE > 0)newCapacity = hugeCapacity(minCapacity);// minCapacity is usually close to size, so this is a win:elementData = Arrays.copyOf(elementData, newCapacity);}

步骤1: 获取旧容量
int oldCapacity = elementData.length;
这里 elementData 是 ArrayList 的内部数组,用于存储所有元素。oldCapacity 就是这个数组的当前长度,也就是 ArrayList 的当前容量。
步骤2: 计算新容量
int newCapacity = oldCapacity + (oldCapacity >> 1);
newCapacity 是计算出的新容量。这里使用了一个简单的数学公式:newCapacity = oldCapacity * 1.5。通过位运算 (oldCapacity >> 1) 实现除以2的操作,然后加上 oldCapacity 得到 1.5 * oldCapacity
步骤3: 检查新容量是否满足最小需求
if (newCapacity - minCapacity < 0)
如果新容量不足以满足 minCapacity 的需求,那么直接将 newCapacity 设置为 minCapacity。
步骤4: 检查新容量是否超过最大数组大小
if (newCapacity - MAX_ARRAY_SIZE > 0)
MAX_ARRAY_SIZE 是一个常量,代表数组的最大允许长度。如果 newCapacity 超过了这个限制,那么调用 hugeCapacity(minCapacity) 方法来处理。这个方法会根据 minCapacity 返回一个合适的容量值,确保不会超过 Integer.MAX_VALUE。
步骤5: 扩容并复制数据
elementData = Arrays.copyOf(elementData, newCapacity);
使用 Arrays.copyOf 方法创建一个新的数组,长度为 newCapacity,并将原数组 elementData 的所有元素复制到新数组中。之后,elementData 引用指向新数组,完成扩容过程。

  1. ArrayList
  • 底层数据结构

ArrayList底层是用动态的数组实现的

  • 初始容量

ArrayList初始容量为0,当第一次添加数据的时候才会初始化容量为10

  • 扩容逻辑

ArrayList在进行扩容的时候是原来容量的1.5倍,每次扩容都需要拷贝数组

  • 添加逻辑
    • 确保数组已使用长度(size)加1之后足够存下下一个数据
    • 计算数组的容量,如果当前数组已使用长度+1后的大于当前的数组长度,则调用grow方法扩容(原来的1.5倍)
    • 确保新增的数据有地方存储之后,则将新元素添加到位于size的位置上。
    • 返回添加成功布尔值。
  1. ArrayList list=new ArrayList(10)中的list扩容几次
    1. 调用grow方法的次数
    2. 带有参数的构造方法并没有调用这个方法 而是创建一个长度为10 的object数组赋值给elementdata
    3. 如果传入的参数为0会将elementdata指向空参empty_elementdata
  2. 如何实现数组和List之间的转换
        //数组转listString []strings = {"123","qwe","asd"};List<String> list = Arrays.asList(strings);//list 转数组List<String> array = new ArrayList<>();array.add("123");array.add("qwe");array.add("asd");String[] arrayString = list.toArray(new String[list.size()]);
  1. 用arrays.aslist转list后修改了数组内容list会受印象吗


Arrays.asList()转换list之后如果修改了数组内容 list受影响
虽然是new 了一个arrayList 但是这个内部类将我们传入的集合进行了包装 a = Objects.requireNonNull(array); 最终的指向还是同一块内存地址

    @SafeVarargs@SuppressWarnings("varargs")public static <T> List<T> asList(T... a) {return new ArrayList<>(a);}/*** @serial include*/private static class ArrayList<E> extends AbstractList<E>implements RandomAccess, java.io.Serializable{private static final long serialVersionUID = -2764017481108945198L;private final E[] a;ArrayList(E[] array) {a = Objects.requireNonNull(array);}}
  1. List用toArray转数组后如果修改了List内容数组受印象吗

当调用了toArray以后在底层他还是进行了数组的拷贝

    public <T> T[] toArray(T[] a) {if (a.length < size)// Make a new array of a's runtime type, but my contents:return (T[]) Arrays.copyOf(elementData, size, a.getClass());System.arraycopy(elementData, 0, a, 0, size);if (a.length > size)a[size] = null;return a;}
  1. ArrayList和LinkedList区别
  2. 底层数据结构
    1. ArrayList是动态数组的数据结构
    2. LinkedList是双向链表的数据结构实现
  3. 操作的效率
    1. 查询
      1. ArrayList按照下标查询的时间复杂度为O(1)
      2. ArrayList 和LinkedList 都需要遍历 时间复杂度都是O(n)
    2. 删除和添加
      1. 删除指定的的都需要遍历链表时间复杂度为O(n)
    3. 内存占用
      1. ArrayList 底层是数组连续内存 节省内春
      2. linkedList是双向链表需要存储数据 和两个指针更占用内存
    4. 线程安全
      1. 都是线程不安全的
        1. 使用可以在方法内使用局部变量是线程安全的
        2. 使用collection.syinzed(new array())
HashMap

hash table 是根据key直接访问内存存储位置值的数据结构
将key映射为数组下标的函数为散列函数 hashvalue = hash(key)
散列函数的基本要求
散列函数计算的到的散列值必须是大于等于0的正整数 hashvlue为数组的下标
如果k1 = k2 那么经过hash后得到的哈希值也必须相同 hash(k1) = hash(k2)
如果k1!=k2那么经过hash后得到的hash值也不必相同 hash(k1)!=hash(k2)
散列冲突
在散列表总数组的每一个下标位置我们可以称之为桶 每一个桶会对应一条链表 所有散列值相同的元素我们都会放到相同槽位相对应的链表中

  1. hashmap实现原理
  • 当我们往hashmap中put元素时利用key的hashcode重新hash计算当前对象在数组中的下标
  • 存储时如果出现hash值现通的key
    • key相同覆盖原始值
    • key不同 将key则将key-vlaue放入链表或红黑树中
    • 1.7
      • 采用的是拉链法 将链表与数组结合 创建一个链表数组 数组中每一格就是一个链表 若遇到哈希冲突则将hash冲突的值加到链表中
    • 1.8
      • 当链表长度大于阈值8时且数组长度达到64时 将链表转化为红黑树 以减少搜索时间 扩容时 红黑树拆成树的节点树小于等于6个则退化成链表
  1. hashmap put 方法的具体流程外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

image.png

1
public V put(K key, V value) {return putVal(hash(key), key, value, false, true);}
2/*** 实现Map的put方法及其相关操作。* 此方法是Map.put操作及其变体的核心实现。** @param hash   键的哈希值* @param key    键* @param value  要放入的值* @param onlyIfAbsent 如果为true,则仅在键不存在时才放入值* @param evict  如果为false,表示表处于创建模式(此参数目前未使用)* @return       与键关联的前一个值,如果之前没有值则返回null*/final V putVal(int hash, K key, V value, boolean onlyIfAbsent,boolean evict) {// 初始化或必要时调整表大小Node<K,V>[] tab; Node<K,V> p; int n, i;if ((tab = table) == null || (n = tab.length) == 0)n = (tab = resize()).length;// 如果槽位为空,尝试直接插入新节点if ((p = tab[i = (n - 1) & hash]) == null)tab[i] = newNode(hash, key, value, null);else {// 处理槽位已占用的情况Node<K,V> e; K k;if (p.hash == hash &&((k = p.key) == key || (key != null && key.equals(k))))e = p;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);// 如果探测长度超过阈值,转换为树节点if (binCount >= TREEIFY_THRESHOLD - 1) // -1 for 1sttreeifyBin(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);return oldValue;}}// 更新大小和modCount,必要时调整大小++modCount;if (++size > threshold)resize();afterNodeInsertion(evict);return null;}
  1. 判断键值对数组table是否为空或为null,否则执行resize()进行扩容(初始化)
  2. 根据键值key计算hash值得到数组索引
  3. 判断table[i]==null,条件成立,直接新建节点添加
  4. 如果table[i]==null ,不成立4.1 判断table[i]的首个元素是否和key一样,如果相同直接覆盖value4.2 判断table[i] 是否为treeNode,即table[i] 是否是红黑树,如果是红黑树,则直接在树中插入键值对4.3 遍历table[i],链表的尾部插入数据,然后判断链表长度是否大于8,大于8的话把链表转换为红黑树,在红黑树中执行插入操 作,遍历过程中若发现key已经存在直接覆盖value
  5. 插入成功后,判断实际存在的键值对数量size是否超多了最大容量threshold(数组长度*0.75),如果超过,进行扩容。
  6. hashmap寻址算法
    1. 首先获取key的hashCode值,然后右移16位 异或运算 原来的hashCode值,主要作用就是使原来的hash值更加均匀,减少hash冲突
    static final int hash(Object key) {int h;return (key == null) ? 0 : (h = key.hashCode()) ^ (h >>> 16);}
  • 有了hash值之后,就很方便的去计算当前key的在数组中存储的下标
  • &hash : 得到数组中的索引,代替取模,性能更好,数组长度必须是2的n次幂
  1. hashmap扩容机制

image.png


//扩容、初始化数组
final Node<K,V>[] resize() {Node<K,V>[] oldTab = table;//如果当前数组为null的时候,把oldCap老数组容量设置为0int oldCap = (oldTab == null) ? 0 : oldTab.length;//老的扩容阈值int oldThr = threshold;int newCap, newThr = 0;//判断数组容量是否大于0,大于0说明数组已经初始化if (oldCap > 0) {//判断当前数组长度是否大于最大数组长度if (oldCap >= MAXIMUM_CAPACITY) {//如果是,将扩容阈值直接设置为int类型的最大数值并直接返回threshold = Integer.MAX_VALUE;return oldTab;}//如果在最大长度范围内,则需要扩容  OldCap << 1等价于oldCap*2//运算过后判断是不是最大值并且oldCap需要大于16else if ((newCap = oldCap << 1) < MAXIMUM_CAPACITY &&oldCap >= DEFAULT_INITIAL_CAPACITY)newThr = oldThr << 1; // double threshold  等价于oldThr*2}//如果oldCap<0,但是已经初始化了,像把元素删除完之后的情况,那么它的临界值肯定还存在,       			如果是首次初始化,它的临界值则为0else if (oldThr > 0) // initial capacity was placed in thresholdnewCap = oldThr;//数组未初始化的情况,将阈值和扩容因子都设置为默认值else {               // zero initial threshold signifies using defaultsnewCap = DEFAULT_INITIAL_CAPACITY;newThr = (int)(DEFAULT_LOAD_FACTOR * DEFAULT_INITIAL_CAPACITY);}//初始化容量小于16的时候,扩容阈值是没有赋值的if (newThr == 0) {//创建阈值float ft = (float)newCap * loadFactor;//判断新容量和新阈值是否大于最大容量newThr = (newCap < MAXIMUM_CAPACITY && ft < (float)MAXIMUM_CAPACITY ?(int)ft : Integer.MAX_VALUE);}//计算出来的阈值赋值threshold = newThr;@SuppressWarnings({"rawtypes","unchecked"})//根据上边计算得出的容量 创建新的数组       Node<K,V>[] newTab = (Node<K,V>[])new Node[newCap];//赋值table = newTab;//扩容操作,判断不为空证明不是初始化数组if (oldTab != null) {//遍历数组for (int j = 0; j < oldCap; ++j) {Node<K,V> e;//判断当前下标为j的数组如果不为空的话赋值个e,进行下一步操作if ((e = oldTab[j]) != null) {//将数组位置置空oldTab[j] = null;//判断是否有下个节点if (e.next == null)//如果没有,就重新计算在新数组中的下标并放进去newTab[e.hash & (newCap - 1)] = e;//有下个节点的情况,并且判断是否已经树化else if (e instanceof TreeNode)//进行红黑树的操作((TreeNode<K,V>)e).split(this, newTab, j, oldCap);//有下个节点的情况,并且没有树化(链表形式)else {//比如老数组容量是16,那下标就为0-15//扩容操作*2,容量就变为32,下标为0-31//低位:0-15,高位16-31//定义了四个变量//        低位头          低位尾Node<K,V> loHead = null, loTail = null;//        高位头		   高位尾Node<K,V> hiHead = null, hiTail = null;//下个节点Node<K,V> next;//循环遍历do {//取出next节点next = e.next;//通过 与操作 计算得出结果为0if ((e.hash & oldCap) == 0) {//如果低位尾为null,证明当前数组位置为空,没有任何数据if (loTail == null)//将e值放入低位头loHead = e;//低位尾不为null,证明已经有数据了else//将数据放入next节点loTail.next = e;//记录低位尾数据loTail = e;}//通过 与操作 计算得出结果不为0else {//如果高位尾为null,证明当前数组位置为空,没有任何数据if (hiTail == null)//将e值放入高位头hiHead = e;//高位尾不为null,证明已经有数据了else//将数据放入next节点hiTail.next = e;//记录高位尾数据hiTail = e;}} //如果e不为空,证明没有到链表尾部,继续执行循环while ((e = next) != null);//低位尾如果记录的有数据,是链表if (loTail != null) {//将下一个元素置空loTail.next = null;//将低位头放入新数组的原下标位置newTab[j] = loHead;}//高位尾如果记录的有数据,是链表if (hiTail != null) {//将下一个元素置空hiTail.next = null;//将高位头放入新数组的(原下标+原数组容量)位置newTab[j + oldCap] = hiHead;}}}}}//返回新的数组对象return newTab;}
  • 在添加元素或初始化的时候需要调用resize方法进行扩容,第一次添加数据初始化数组长度为16,以后每次每次扩容都是达到了扩容阈值(数组长度 * 0.75)
  • 每次扩容的时候,都是扩容之前容量的2倍;
  • 扩容之后,会新创建一个数组,需要把老数组中的数据挪动到新的数组中
    • 没有hash冲突的节点,则直接使用 e.hash & (newCap - 1) 计算新数组的索引位置
    • 如果是红黑树,走红黑树的添加
    • 如果是链表,则需要遍历链表,可能需要拆分链表,判断(e.hash & oldCap)是否为0,该元素的位置要么停留在原始位置,要么移动到原始位置+增加的数组大小这个位置上
  1. hashmap的数组长度一定是2的次幂
    1. &hash : 得到数组中的索引,代替取模,性能更好,数组长度必须是2的n次幂
    2. 扩容时重新计算索引效率更高: hash & oldCap == 0 的元素留在原来位置 ,否则新位置 = 旧位置 + oldCap
  2. hashmap在1.7的情况下的多线程死循环问题
    1. jdk7的的数据结构是:数组+链表
    2. 在数组进行扩容的时候,因为链表是头插法,在进行数据迁移的过程中,有可能导致死循环
  • 变量e指向的是需要迁移的对象
  • 变量next指向的是下一个需要迁移的对象
  • Jdk1.7中的链表采用的头插法
  • 在数据迁移的过程中并没有新的对象产生,只是改变了对象的引用
  1. hashset 与hashmap的区别
  • HashSet实现了Set接口, 仅存储对象; HashMap实现了 Map接口, 存储的是键值对.
  • HashSet底层其实是用HashMap实现存储的, HashSet封装了一系列HashMap的方法. 依靠HashMap来存储元素值,(利用hashMap的key键进行存储), 而value值默认为Object对象. 所以HashSet也不允许出现重复值, 判断标准和HashMap判断标准相同, 两个元素的hashCode相等并且通过equals()方法返回true.
    | 区别 | HashTable | HashMap |
    | — | — | — |
    | 数据结构 | 数组+链表 | 数组+链表+红黑树 |
    | 是否可以为null | Key和value都不能为null | 可以为null |
    | hash算法 | key的hashCode() | 二次hash |
    | 扩容方式 | 当前容量翻倍 +1 | 当前容量翻倍 |
    | 线程安全 | 同步(synchronized)的,线程安全 | 非线程安全 |

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

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

相关文章

【计算机网络】无线网络和移动网络(第9章)大纲(共70+页)

最后只复习了1.5天&#xff0c;应用层简单过了一遍。 本来是mindmap的&#xff0c;但是太大了只能导出成提纲了&#xff0c;凑合看吧orz。 如果你找我要源文件&#xff0c;最好是在2024年&#xff0c;不然我可能就找不到了&#xff08;&#xff09;。

基于STC8H系列单片机的中断系统

基于STC8H系列单片机的中断系统 STC8H4K64TL单片机介绍STC8H4K64TL单片机管脚图(48个引脚)STC8H4K64TL单片机串口仿真与串口通信STC8H4K64TL单片机管脚图(32个引脚)STC8H4K64TL单片机管脚图(20个引脚)STC8H系列单片机管脚说明STC8H系列单片机I/O口STC8H系列单片机I/O口相…

【C++】:红黑树的应用 --- 封装map和set

点击跳转至文章&#xff1a;【C】&#xff1a;红黑树深度剖析 — 手撕红黑树&#xff01; 目录 前言一&#xff0c;红黑树的改造1. 红黑树的主体框架2. 对红黑树节点结构的改造3. 红黑树的迭代器3.1 迭代器类3.2 Begin() 和 End() 四&#xff0c;红黑树相关接口的改造4.1 Find…

centos stream 9安装 Kubernetes v1.30 集群

1、版本说明&#xff1a; 系统版本&#xff1a;centos stream 9 Kubernetes版本&#xff1a;最新版(v1.30) docker版本&#xff1a;27.1.1 节点主机名ip主节点k8s-master172.31.0.10节点1k8s-node1172.31.0.11节点2k8s-node2172.31.0.12 2、首先&#xff0c;使用Vagrant和Virt…

【2024年国际高等学校数学建模竞赛IMMCHE】问题 B:太空移民计划和战略 问题分析及数学模型及求解代码

【2024年国际高等学校数学建模竞赛IMMCHE】问题 B&#xff1a;太空移民计划和战略 问题分析及数学模型及求解代码 Problem B: Space Migration Program and Strategy 1 题目 我们的未来有两种可能&#xff1a;第一&#xff0c;我们将留在地球上&#xff0c;直到完全灭绝&…

Hive3:Hive初体验

1、创建表 CREATE TABLE test(id INT, name STRING, gender STRING);2、新增数据 INSERT INTO test VALUES(1, 王力红, 男); INSERT INTO test VALUES(2, 钉钉盯, 女); INSERT INTO test VALUES(3, 咔咔咔, 女);3、查询数据 简单查询 select * from test;带聚合函数的查询 …

Halcon 引擎方式调试

1.C# 端添加代码 启动调试模式 public HDevEngine MyEngine new HDevEngine(); // halcon引擎;// 启动调试服务 MyEngine.StartDebugServer();2.Halcon程序添加到进程 打开Halcon程序 【执行】>【附加到进程】 点击【确定】 3.C# 程序执行到相关位置 C# 程序执行调用…

vector深度剖析及模拟实现

目录 前言vector核心框架模拟实现1. 前期准备2. 构造和销毁补充: 隐式类型转换和多参数构造的区别 3. 迭代器相关4. 容器相关补充: memcpy拷贝问题 5. 元素访问6. vector的修改测试代码 总结 前言 本文重点模拟实现vector的核心接口, 帮助我们更好的理解底层逻辑, 以及对vecto…

科学又省力 宠物浮毛怎么去掉便捷高效?除毛秘籍养宠空气净化器

上次和朋友逛完街去她家&#xff0c;她家的猫哈基米一开门就飞奔过来&#xff0c;朋友直接抱起它狂亲。结果&#xff0c;猫毛和汗水粘得到处都是&#xff0c;手臂上、脸上都是&#xff0c;看得我这鼻炎星人直起鸡皮疙瘩。很多养宠物的朋友都说&#xff0c;天天给猫狗梳毛&#…

Android Studio导入源码

在有源码并且编译环境可用的情况下&#xff1a; 1.生成导入AS所需的配置文件 在源码的根目录执行以下命令&#xff1a; source build/ensetup.sh lunch 要编译的项目 make idegen //这一步会生成out/host/linux-x86/framework/idegen.jar development/tools/idegen/idegen.sh…

利用OSMnx求路网最短路径并可视化(二)

书接上回&#xff0c;为了增加多路径的可视化效果和坐标匹配最近点来实现最短路可视化&#xff0c;我们使用图形化工具matplotlib结合OSMnx的绘图功能来展示整个路网图&#xff0c;并特别高亮显示计算出的最短路径。 多起终点最短路路径并计算距离和时间 完整代码#运行环境 P…

《昇思25天学习打卡营第24天|基于MindSpore通过GPT实现情感分类》

基于MindSpore通过GPT实现情感分类 %%capture captured_output # 实验环境已经预装了mindspore2.2.14&#xff0c;如需更换mindspore版本&#xff0c;可更改下面mindspore的版本号 !pip uninstall mindspore -y !pip install -i https://pypi.mirrors.ustc.edu.cn/simple mind…

自动化测试 pytest 中 scope 限制 fixture使用范围!

导读 fixture 是 pytest 中一个非常重要的模块&#xff0c;可以让代码更加简洁。 fixture 的 autouse 为 True 可以自动化加载 fixture。 如果不想每条用例执行前都运行初始化方法(可能多个fixture)怎么办&#xff1f;可不可以只运行一次初始化方法&#xff1f; 答&#xf…

C语言进阶 11.结构体

C语言进阶 11.结构体 文章目录 C语言进阶 11.结构体11.1. 枚举11.2. 结构类型11.3. 结构与函数11.4. 结构中的结构11.5. 类型定义11.6. 联合11.7. PAT11-0. 平面向量加法(10)11-1. 通讯录的录入与显示(10) 11.1. 枚举 常量符号化: 用符号而不是具体的数字表示程序中的数字 cons…

【C++深度探索】AVL树与红黑树的原理与特性

&#x1f525; 个人主页&#xff1a;大耳朵土土垚 &#x1f525; 所属专栏&#xff1a;C从入门至进阶 这里将会不定期更新有关C/C的内容&#xff0c;欢迎大家点赞&#xff0c;收藏&#xff0c;评论&#x1f973;&#x1f973;&#x1f389;&#x1f389;&#x1f389; 前言 前…

渣土车与搅拌车安全问题解析及智能监控解决方案

一、背景分析 近年来&#xff0c;渣土车在货物运输中由于超载超速、违规驾驶、车辆盲区过大等问题导致的事故频发&#xff0c;严重影响了人们的生命财产安全。而搅拌车作为一种特殊的运输车辆&#xff0c;在混凝土输送过程中也存在类似的隐患。针对这些问题&#xff0c;对搅拌…

多维矩阵乘积运算和对应的广播机制

神经网络中的多维矩阵乘积运算&#xff1a; 遵循的原则是&#xff1a; 两张量前两维度应该是相同的&#xff0c;如果不同则其中一张量维度为1。 如果有论文中有遇到矩阵乘积的两项维度不一致&#xff0c;那就考虑它计算时是使用了广播机制&#xff08;如YOLACT&#xff09;。…

谁说只有车载HMI界面?现在工业类的HMI界面UI也崛起了

谁说只有车载HMI界面&#xff1f;现在工业类的HMI界面UI也崛起了 引言 艾斯视觉作为行业ui设计和前端开发领域的从业者&#xff0c;其观点始终认为&#xff1a;工业自动化和智能化水平不断提高&#xff0c;人机界面&#xff08;Human-Machine Interface&#xff0c;简称HMI&a…

Lombok的认识

Lombok的作用 Lombok是一个Java库&#xff0c;它可以通过简单的注解形式来帮助开发人员简化Java代码的编写&#xff0c;特别是减少模板代码的书写。具体来说&#xff0c;Lombok的主要作用包括&#xff1a; 减少模板代码&#xff1a;Lombok可以通过注解自动生成getter、setter、…

QT opencv常用代码备忘

最近在了解qt opencv的一些用法&#xff0c;把常用的代码记下来方便需要时复制使用 在默认.pro文件加入opencv包含路径和库文件 QT core guigreaterThan(QT_MAJOR_VERSION, 4): QT widgetsCONFIG c17# You can make your code fail to compile if it uses deprecate…