【数据结构】-5- 顺序表 (下)

一、集合框架 

这是 Java 集合框架(Java Collections Framework)的核心继承关系树状图

1. 最顶层:Iterable(接口)
  • 作用:所有 “可迭代” 的集合(如 ListSetQueue)都必须实现它,提供遍历元素的能力(通过 iterator() 方法生成迭代器)。
  • 关键方法:Iterator<T> iterator() → 返回迭代器,用于遍历集合元素。

2. 第二层:Collection(接口)
  • 地位:Java 集合框架的根接口(除 Map 体系外,所有集合都直接 / 间接继承它)。
  • 定义:规范了集合的基础行为(增、删、查、遍历等),是所有单列集合(单个元素存储)的 “通用契约”。
  • 关键方法:
    • add(E e):添加元素
    • remove(Object o):删除元素
    • contains(Object o):判断是否包含元素
    • size():获取元素个数
    • iterator():获取迭代器(继承自 Iterable

3. 第三层:三大子接口(ListQueueSet

Collection 派生出三个核心子接口,代表三种不同的集合特性

(1)List(接口)
  • 特点:有序、可重复(元素按插入顺序排列,允许存重复值)。
  • 典型实现类:
    • ArrayList:基于动态数组,查询快(下标访问 O(1))、增删慢(需移动元素)。
    • LinkedList:基于双向链表,增删快(改变指针 O(1))、查询慢(需遍历链表)。
    • Vector:古老实现(线程安全,但性能差,已被 ArrayList 替代)。
    • Stack:继承 Vector,实现栈结构(后进先出,LIFO)。
(2)Queue(接口)
  • 特点:队列特性(通常 “先进先出,FIFO”,但部分实现支持优先级)。
  • 典型实现类:
    • LinkedList:同时实现 List 和 Queue,作为链表队列使用。
    • PriorityQueue优先队列(元素按优先级排序,不严格遵循插入顺序)。
    • Deque(子接口):双端队列(两端都可增删),LinkedList 也实现了它。
(3)Set(接口)
  • 特点:无序、不可重复(元素无顺序,且 equals 相等的元素只能存一个)。
  • 典型实现类:
    • HashSet:基于哈希表HashMap 实现),增删查快(平均 O(1)),无序。
    • TreeSet:基于红黑树,元素自动排序(需实现 Comparable),查询慢(O(log n))。
    • SortedSet(子接口):规范 “有序 Set” 行为,TreeSet 实现它。

4. 抽象类(AbstractList
  • 作用:简化集合实现,为 List 接口的实现类提供通用逻辑(如部分方法默认实现)。
  • 典型继承:ArrayListLinkedList 都继承它,避免重复写 addremove 等基础逻辑。

⭐ 核心设计思想

  1. 接口分层

    • Iterable 定义 “可遍历” 能力 → Collection 定义 “集合基础行为” → 子接口(List/Queue/Set)细化特性。
    • 解耦 “通用行为” 和 “具体特性”,方便扩展(如新增集合类型只需实现接口)。
  2. 实现类分工

    • 不同实现类(ArrayList/LinkedList/HashSet 等)针对不同场景优化(数组查快、链表增删快、哈希表去重等)。
    • 开发时根据需求选实现类(查多改少用 ArrayList;增删多用 LinkedList;去重用 Set)。
  3. 复用与扩展

    • 抽象类(如 AbstractList)封装通用逻辑,减少实现类代码量。
    • 接口(如 Deque 继承 Queue)扩展功能,让集合支持更多特性(双端操作)。

⭐ 典型应用场景

  • 存有序可重复数据 → 选 List(如 ArrayList 存学生名单,允许重复姓名)。
  • 存无序不可重复数据 → 选 Set(如 HashSet 存用户 ID,避免重复)。
  • 需队列 / 栈行为 → 选 Queue/Stack(如 PriorityQueue 实现任务优先级调度)。

掌握这张图,就能清晰理解 Java 集合的体系脉络,开发时也能更合理地选集合类型~

二、集合和数组区别 

你观察得很敏锐!ArrayList 底层确实是用数组实现的(顺序表本质),但 “集合转数组” 的操作依然有其必要性,核心原因在于 “集合的抽象特性” 与 “数组的具体特性” 之间的差异,具体可以从三个角度理解:

⭐ 接口与实现的分离:集合是 “抽象容器”,数组是 “具体存储”

ArrayList 虽然底层用数组存储,但它对外暴露的是 List 接口的抽象方法(如 addgetsize 等),隐藏了数组的具体实现细节(比如扩容逻辑、下标管理等)。

这种 “抽象” 带来了便利(比如无需手动管理容量),但也限制了对底层数组的直接操作。例如:

  • 你不能直接用 ArrayList 调用数组特有的工具方法(如 Arrays.sort()Arrays.binarySearch());
  • 某些 API 或框架可能只接收 Object[] 类型的参数(而非 List 集合)。

此时,toArray() 的作用就是 “打破抽象”,将集合中 “隐藏的数组元素” 提取出来,转换为可直接操作的数组对象,以便使用数组的特性或兼容外部需求。

⭐ 功能场景的差异:集合擅长 “动态管理”,数组擅长 “静态操作”

ArrayList 作为集合,核心优势是 动态管理数据(自动扩容、简化增删逻辑);而数组的优势是 静态高效操作(如固定长度下的快速遍历、使用 Arrays 工具类的各种功能)。

举两个典型场景:

  1. 需要使用数组工具类
    Arrays 类提供了大量便捷方法(排序、二分查找、填充等),但这些方法的参数必须是数组。例如,要对 ArrayList 中的元素排序,直接操作集合不方便,但转成数组后就很简单:

    List<Integer> list = new ArrayList<>(Arrays.asList(3, 1, 2));
    Integer[] arr = list.toArray(new Integer[0]); // 转数组
    Arrays.sort(arr); // 用数组工具排序
    System.out.println(Arrays.toString(arr)); // [1, 2, 3]
    
  2. 需要固定长度的不可变结构
    集合是 “动态的”(可以随时 add/remove 元素),而有时我们需要一个 “固定不变的快照”(比如传递数据时不希望被修改)。数组的长度固定,转成数组后可以避免误操作导致的元素变化:

    Object[] arr = list.toArray(); // 数组长度固定为3
    // 此时即使修改原集合,数组也不受影响
    list.add("西瓜"); 
    System.out.println(arr.length); // 仍为3(数组长度不变)
    

⭐ 类型系统的限制:集合的泛型与数组的 “具体化”

ArrayList 虽然通过泛型(如 List<String>)保证了元素类型安全,但这种泛型是 编译时检查,运行时会被擦除(类型擦除)。而数组是 “具体化类型”(运行时也能确定类型),两者在类型处理上有差异。

例如,当需要将集合元素传递给一个 “要求具体类型数组” 的方法时(如 void process(String[] strs)),直接传 List<String> 会编译报错,必须通过 toArray(String[]) 转换为具体类型的数组:

process在编译检查时会确定里面的参数是不是string类型数组,但是List<String>里面会被擦除,无法判断是不是确切的String类型,编译会报错。

// 定义一个接收 String[] 参数的方法
public static void process(String[] strs) {for (String s : strs) {System.out.println(s);}
}// 调用方法时,必须将 List<String> 转为 String[]
List<String> list = new ArrayList<>(Arrays.asList("a", "b"));
process(list.toArray(new String[0])); // 正确:传递 String[] 数组

总结

ArrayList 底层用数组实现,但它作为 “集合” 提供的是更高层次的抽象功能(动态管理)。而 toArray() 的作用是 在需要时 “降级” 到数组层面,利用数组的特性(工具类支持、固定长度、具体类型)来满足特定场景需求。

简单说:集合是 “包装好的数组”,方便日常使用;toArray() 是 “拆包装” 的工具,让我们在需要时能直接操作里面的 “数组内核”。

 三、toArray() 

在 Java 集合框架中,toArray() 是 Collection 接口(所有集合类的顶层接口,如 ArrayListLinkedListHashSet 等都实现了它) 定义的核心方法,作用是 将集合中的所有元素,转换为一个「数组」并返回,本质是实现「集合 → 数组」的类型转换。

[1] 核心作用:集合转数组的 “桥梁”

集合(如 ArrayList)是动态存储结构(大小可自动扩容),而数组是静态存储结构(初始化后大小固定)。

当需要用数组的方式操作集合元素(比如兼容某些只接收数组参数的方法、或需要数组的高效随机访问特性)时,toArray() 就是两者之间的关键桥梁。

// 1. 创建一个集合,存入元素
List<String> list = new ArrayList<>();
list.add("苹果");
list.add("香蕉");
list.add("橙子");// 2. 调用 toArray(),将集合转为数组
Object[] fruitArray = list.toArray();// 3. 遍历数组(此时可以用数组的操作方式处理原集合元素)
for (Object fruit : fruitArray) {System.out.println(fruit); // 输出:苹果、香蕉、橙子
}

在代码 Object[] fruitArray = list.toArray(); 中,toArray() 方法括号里没有 new Object[0],是因为调用的是 无参的 toArray() 方法,而不是带参数的 toArray(T[] a) 方法。这两个方法的设计目的和返回值有本质区别:

1. 无参 toArray():直接返回 Object[] 数组

无参的 toArray() 方法是 Collection 接口定义的默认实现,它的行为是:

  • 返回值固定为 Object[] 类型,无论集合的泛型是什么(即使是 List<String>,返回的也是 Object[])。
  • 内部会创建一个新的 Object[] 数组,并将集合中的元素复制进去。

因此,当我们写 list.toArray() 时,不需要传入任何参数,方法会自动创建并返回一个 Object[] 数组,所以代码中直接写成 list.toArray() 即可,无需 new Object[0]

2. 带参 toArray(T[] a):需要传入数组参数

另一个重载方法 toArray(T[] a) 的作用是 返回指定类型的数组(如 String[]Integer[]),而非默认的 Object[]。此时需要传入一个数组参数(如 new String[0]),目的是:

  • 告诉方法 “我需要返回什么类型的数组”(参数的类型决定了返回数组的类型)。
  • 例如 list.toArray(new String[0]) 会返回 String[] 类型,而不是 Object[]

3. 为什么这里不需要 new Object[0]

因为代码的需求是 获取 Object[] 类型的数组,而无参 toArray() 正好直接返回 Object[],完全满足需求。此时如果画蛇添足地传入 new Object[0],写成:

Object[] fruitArray = list.toArray(new Object[0]); // 多余的参数

虽然功能上没问题(返回的也是 Object[]),但参数是多余的 —— 无参方法已经能实现同样的效果,传入参数反而增加了代码的冗余。

[2] 两种常用重载形式(重点区分)

toArray() 有两个核心重载方法,用法和返回值差异很大,实际开发中需根据需求选择:

方法签名返回值类型核心特点适用场景
Object[] toArray()Object[]固定返回 Object 类型数组,无论集合泛型是什么仅需 “遍历元素”,不关心元素具体类型时(但有类型转换风险,需谨慎)
<T> T[] toArray(T[] a)传入的数组类型 T[]可指定返回数组的具体类型(如 String[]Integer[]),避免后续强制类型转换需要明确数组类型(如调用需 String[] 参数的方法),是更常用、更安全的方式

(1)无参 toArray():返回 Object[]
  • 特点:无论原集合的泛型是 StringInteger 还是其他类型,返回的数组元素类型都是 Object(因为数组的编译时类型是 Object[])。
  • 注意:不能直接将返回的 Object[] 强制转为具体类型数组(如 String[]),会触发 ClassCastException(类型转换异常)。

List<String> list = new ArrayList<>();
list.add("a");
// 错误!Object[] 不能直接强转 String[]
String[] arr = (String[]) list.toArray(); // 运行时抛 ClassCastException

(2)带参 toArray(T[] a):返回指定类型数组
  • 特点:传入一个 “指定类型的数组” 作为参数,方法会根据该数组的类型,返回一个同类型的数组(存储集合元素),避免类型转换风险。
  • 内部逻辑:
    1. 如果传入的数组 a 大小 ≥ 集合元素个数:直接将集合元素填入数组 a,多余位置填 null,返回 a 本身;
    2. 如果传入的数组 a 大小 < 集合元素个数:创建一个 “和 a 同类型、大小等于集合元素个数” 的新数组,填入元素后返回新数组。

List<String> list = new ArrayList<>();
list.add("a");
list.add("b");// 方式1:传入一个大小足够的数组(推荐,避免创建新数组)
String[] arr1 = new String[list.size()];
arr1 = list.toArray(arr1); // 返回 String[],可直接使用// 方式2:传入一个空数组(简洁,JDK 1.8+ 常用)
String[] arr2 = list.toArray(new String[0]); // 内部会创建大小为 2 的新 String[]// 遍历数组(无需强制转换,类型安全)
for (String s : arr2) {System.out.println(s); // 输出 a、b
}

[3] 关键注意点(避坑)

(1)无参 toArray() 的类型限制

再次强调:无参方法返回的 Object[] 只能存 Object 类型,不能强转具体类型数组。若需具体类型,必须用带参 toArray(T[] a)

(2)返回数组是 “新数组” 还是 “原集合底层数组”?

  • 对于 ArrayListtoArray() 返回的是复制后的新数组,修改数组元素不会影响原集合(因为数组和集合底层存储的是两个独立的数组)。

    List<Integer> list = new ArrayList<>();
    list.add(10);
    Integer[] arr = list.toArray(new Integer[0]);
    arr[0] = 20; // 修改数组元素
    System.out.println(list.get(0)); // 输出 10(原集合无变化)
    
  • 对于其他集合(如 Vector):逻辑类似,均返回 “元素副本的数组”,避免外部通过数组修改集合内部状态。
(3)集合元素为 null 时的处理

若集合中包含 null 元素,toArray() 会将 null 也存入数组(数组允许 null),遍历数组时需注意判空,避免 NullPointerException

List<String> list = new ArrayList<>();
list.add("a");
list.add(null); // 集合允许存 null
String[] arr = list.toArray(new String[0]);
System.out.println(arr[1]); // 输出 null

四、List 接口常用方法 

一、增(添加元素)

  • boolean add(E e)

    • 功能:在顺序表末尾插入元素(尾插)。
    • 逻辑:检查容量 → 数组末尾赋值 → size++ 。
    • 示例:

      ArrayList<Integer> list = new ArrayList<>();
      list.add(10); // 末尾插入10,size 变为1
      
  • void add(int index, E element)

    • 功能:在指定下标 index 处插入元素,后续元素后移。
    • 逻辑:检查下标合法性 → 扩容(如需) → 从 index 开始后移元素 → 插入新值 → size++ 。
    • 注意:index 范围 [0, size](允许末尾插入,对应 index=size )。
    • 示例:
    • list.add(1, 20); // 在索引1处插入20,原索引1及之后元素后移
      
  • boolean addAll(Collection<? extends E> c)

    • 功能:把另一个集合 c 的元素全部尾插到当前表
    • 逻辑:遍历集合 c ,逐个尾插元素;若插入成功(至少一个),返回 true 。
    • 示例:

      List<Integer> other = Arrays.asList(30, 40);
      list.addAll(other); // 末尾插入30、40,size 增加2
      

二、删(删除元素)

  1. E remove(int index)

    • 功能:删除指定下标 index 处的元素,返回被删元素;后续元素前移。
    • 逻辑:检查下标合法性 → 保存被删元素 → 从 index+1 开始前移元素 → size-- → 返回被删值。
    • 示例:

      int removed = list.remove(1); // 删除索引1的元素,返回该元素
      
  2. boolean remove(Object o)

    • 功能:删除第一个遇到的元素 o(基于 equals 比较),删除成功返回 true 。
    • 逻辑:遍历查找第一个与 o 相等的元素 → 找到则删除(后续元素前移) → 返回是否删除成功。
    • 注意:若存储自定义对象,需重写 equals 保证比较逻辑正确。
    • 示例:

      list.remove(Integer.valueOf(20)); // 删除第一个值为20的元素
      

三、改(修改元素)

  • E set(int index, E element)
    • 功能:将下标 index 处的元素替换为 element,返回原元素。
    • 逻辑:检查下标合法性 → 保存原元素 → 赋值新元素 → 返回原元素。
    • 示例:
    • int old = list.set(1, 25); // 索引1的元素改为25,返回原元素
      

四、查(获取 / 查找元素)

  1. E get(int index)

    • 功能:获取下标 index 处的元素
    • 逻辑:检查下标合法性 → 直接返回数组对应位置的值(时间复杂度 O(1) )。
    • 示例:

      int val = list.get(1); // 获取索引1处的元素值
      
  2. boolean contains(Object o)

    • 功能:判断元素 o 是否存在于表中(基于 equals 遍历比较)。
    • 逻辑:遍历表,用 equals 比较元素;找到则返回 true ,否则 false 。
    • 注意:自定义对象需重写 equals ,否则比较地址而非内容。
    • 示例:

      boolean has = list.contains(25); // 判断25是否在表中
      
  3. int indexOf(Object o)

    • 功能:返回第一个 o 所在的下标(基于 equals 遍历);不存在返回 -1 。
    • 逻辑:遍历表,找到第一个与 o equals 的元素,返回其下标。
    • 示例:

      int idx = list.indexOf(25); // 找25第一次出现的下标
      
  4. int lastIndexOf(Object o)

    • 功能:返回最后一个 o 所在的下标(反向遍历,基于 equals );不存在返回 -1 。
    • 逻辑:从表末尾往前遍历,找到第一个与 o equals 的元素,返回其下标。
    • 示例:

      int lastIdx = list.lastIndexOf(25); // 找25最后一次出现的下标
      

五、工具操作

  1. void clear()

    • 功能:清空顺序表(元素个数置 0,数组引用可保留或重置,不同实现可能有差异)。
    • 逻辑:size = 0 (或额外把数组元素置 null ,帮助 GC 回收)。
    • 示例:

      list.clear(); // 清空后 size=0,元素全被移除
      
  2. List<E> subList(int fromIndex, int toIndex)

    • 功能:截取从 fromIndex(含)到 toIndex(不含)的子表,返回新 List 。
    • 逻辑:创建新 List ,遍历原表对应区间,复制元素;子表与原表共享底层数组(修改子表会影响原表,需注意)。
    • 示例:

      List<Integer> sub = list.subList(1, 3); // 截取索引1、2的元素,生成子表
      

六、方法调用关系 & 核心特点

  • 依赖关系:增删操作常依赖扩容(如 add 时检查容量)元素移动(插入 / 删除时数组拷贝);查找依赖 equals(自定义对象需重写)。
  • 时间复杂度
    • 尾插 / 尾删(不扩容时):O(1) ;
    • 指定位置增删(需移动元素):O(n) ;
    • 查找(遍历):O(n) ;
    • 下标访问(get/set):O(1) 。
  • 适用场景:适合频繁按下标访问、尾插操作;若需大量中间增删,优先选链表(如 LinkedList )。

五、 Java 集合的迭代器(Iterator)遍历机制 

一、迭代器的作用:“指针” 式遍历集合

迭代器(Iterator)是 Java 集合框架中用于安全遍历集合元素的工具,它像一个 “移动的指针”,依次访问集合中的每个元素。

核心优势:

  • 支持在遍历中安全删除元素(避免普通 for 循环遍历删除时的 ConcurrentModificationException);
  • 统一了各类集合的遍历方式(ListSetQueue 都能用迭代器遍历)。

二、代码执行流程

假设 list 是一个 List<Integer>,存储元素 [1, 2, 3],代码:

Iterator<Integer> it = list.iterator(); // 1. 获取迭代器
while (it.hasNext()) {                  // 2. 检查是否有下一个元素System.out.println(it.next() + " "); // 3. 获取并移动到下一个元素
}
1. 获取迭代器:list.iterator()
  • 作用:创建一个与 list 关联的迭代器对象 it,初始时指向集合第一个元素之前(类似指针在数组下标 -1 的位置)。
2. 检查是否有下一个元素:it.hasNext()
  • 作用:判断迭代器当前位置之后是否还有未访问的元素
  • 执行逻辑:
    • 第一次调用:指针在 -1,检查到下标 0 有元素(1),返回 true
    • 第二次调用:指针在 0(已访问 1),检查到下标 1 有元素(2),返回 true
    • 第三次调用:指针在 1(已访问 2),检查到下标 2 有元素(3),返回 true
    • 第四次调用:指针在 2(已访问 3),检查到下标 3 无元素,返回 false,结束循环。
3. 获取并移动指针:it.next()
  • 作用:返回当前指针位置的下一个元素,并将指针向后移动一位(“自动向下执行” 的本质)。
  • 执行逻辑:

    • 第一次 it.next():返回下标 0 的元素 1,指针移动到 0 → 1 之间(指向 1 之后)。
    • 第二次 it.next():返回下标 1 的元素 2,指针移动到 1 → 2 之间。
    • 第三次 it.next():返回下标 2 的元素 3,指针移动到 2 → 3 之间。

三、迭代器的 “指针” 模型(对应图中结构)

图中右侧的 “竖排方框” 代表集合 list 的元素(123),it 是迭代器指针,执行流程对应:

  1. 初始状态:it 指向第一个元素(1之前(无具体位置,逻辑上在 -1)。
  2. 第一次 hasNext():检测到 1 存在 → 进入循环 → next() 返回 1,指针移动到 1 之后。
  3. 第二次 hasNext():检测到 2 存在 → 进入循环 → next() 返回 2,指针移动到 2 之后。
  4. 第三次 hasNext():检测到 3 存在 → 进入循环 → next() 返回 3,指针移动到 3 之后。
  5. 第四次 hasNext():检测到无元素 → 退出循环。

四、迭代器的关键特点

  1. 单向遍历:只能从前往后遍历,无法回退(若需回退,用 ListIterator 子接口)。
  2. 快速失败(fail-fast):遍历中若集合被修改(如 list.add/list.remove),会立即抛出 ConcurrentModificationException,避免脏读。
  3. 与集合状态绑定:迭代器遍历的是创建时集合的 “快照”(但如果是 ArrayList 等基于数组的集合,遍历中修改会触发快速失败)。

五、对比普通 for 循环遍历

虽然 for-each 本质也是迭代器遍历,但手动用 Iterator 的优势在于:

  • 支持遍历中删除元素it.remove(),安全且不会报错);
  • 更灵活(可控制遍历过程,比如跳过某些元素)。

示例:遍历中删除元素(安全写法)

Iterator<Integer> it = list.iterator();
while (it.hasNext()) {Integer num = it.next();if (num == 2) {it.remove(); // 安全删除当前元素}
}

理解迭代器的 “指针移动” 模型后,就能掌握集合遍历的底层逻辑,遇到遍历相关的问题(如并发修改异常)也能快速定位啦~

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

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

相关文章

最大连续1的个数Ⅲ-滑动窗口

1004. 最大连续1的个数 III - 力扣&#xff08;LeetCode&#xff09; Solution 标准滑动窗口。 class Solution { public:int longestOnes(vector<int>& nums, int k) {int nnums.size();int l0,z_cnt0,ans0;for(int r0;r<n;r){z_cnt1-nums[r];while(z_cnt>k…

实验二 Cisco IOS Site-to-Site Pre-share Key

一 实验设备 1、 CISCO 路由器 2 台 二 实验拓扑图 三 实验配置 1、 R1 路由器上连通性配置 R1(config)#interface e0/0 R1(config-if)#ip address 192.168.1.2 255.255.255.0 R1(config-if)#no shutdown R1(config)#interface e1/0 R1(config-if)#ip address 10.1.20.1 255.25…

深入理解 Rust Axum:两种依赖注入模式的实践与对比(二)

前言 我想把使用 Rust 开发Websocket 服务的文章写成一个系列&#xff0c;前面写了一遍如何使用 Axum 搭建一个Websocket 服务的文章&#xff0c;我们可以和前端demo页面进行全双工的 Websocket 消息传输&#xff0c;而且可以启用 HTTP2 的同时启用 TLS。 这时候问题来了&…

syn与quote的使用——结构体转create语句

前言 syn和quote的简单使用——生成结构体-CSDN博客https://blog.csdn.net/qq_63401240/article/details/150609865?spm1001.2014.3001.5501 前面使用syn和quote&#xff0c;发现挺好玩的&#xff0c;感觉可以干很多事情&#xff0c;不愧是Rust中的宏。 宏分为声明宏和过程…

集中式负载均衡 vs. 分布式负载均衡

集中式负载均衡 vs. 分布式负载均衡负载均衡&#xff08;Load Balancing&#xff09;是任何可伸缩系统的“交通警察”。 集中式负载均衡&#xff08;Centralized LB&#xff09;与分布式负载均衡&#xff08;Distributed LB&#xff09;代表了两种截然不同的“指挥哲学”&#…

【机器学习】9 Generalized linear models and the exponential family

本章目录 9 Generalized linear models and the exponential family 281 9.1 Introduction 281 9.2 The exponential family 281 9.2.1 Definition 282 9.2.2 Examples 282 9.2.3 Log partition function 284 9.2.4 MLE for the exponential family 286 9.2.5 Bayes for the e…

EndNote 2025 Mac 文献管理工具

原文地址&#xff1a;EndNote 2025 Mac 文献管理工具 EndNote mac版一款文献管理工具&#xff0c;支持国际期刊的参考文献格式有3776种&#xff0c;写作模板几百种&#xff0c;涵盖各个领域的杂志。 EndNote mac不仅仅局限于投稿论文的写作&#xff0c;对于研究生毕业论文的写…

openEuler系统中home文件夹下huawei、HwHiAiUser、lost+found 文件夹的区别和作用

在 openEuler 系统的 /home 目录下出现的 huawei、HwHiAiUser 和 lost+found 文件夹,分别对应不同的功能和用途,具体区别和作用如下: 1. lost+found 文件夹 通用 Linux 系统文件夹:lost+found 是所有 Linux 系统(包括 openEuler)中默认存在的文件夹,并非 openEuler 特有…

Electron 核心 API 全解析:从基础到实战场景

Electron 凭借丰富的 API 体系&#xff0c;让前端开发者能轻松调用系统级能力。本文将系统梳理 Electron 核心 API 的分类、使用场景及实战示例&#xff0c;帮你快速掌握从窗口管理到进程通信的全场景开发。 一、主进程核心 API&#xff08;Main Process&#xff09; 主进程是…

创建线程的方式有哪些?

1. 创建线程的方式有哪些?继承Thread类实现runnable接口实现Callable接口线程池创建线程(项目中使用方式)2. runnable 和 callable 有什么区别?Runnable接口run方法没有返回值Callable接口call方法有返回值,需要FutureTask获取结果Callable接口的call()方法允许抛出异常;而Ru…

More Effective C++ 条款05: 谨慎定义类型转换函数

More Effective C 条款05&#xff1a;谨慎定义类型转换函数核心思想&#xff1a;C中的隐式类型转换虽然方便&#xff0c;但容易导致意外的行为和维护难题。应当通过explicit关键字和命名转换函数等方式严格控制类型转换&#xff0c;优先使用显式转换而非隐式转换。 &#x1f68…

基于springboot的理商管理平台设计与实现、java/vue/mvc

基于springboot的理商管理平台设计与实现、java/vue/mvc

Flask蓝图:模块化开发的利器

蓝图为什么要使用蓝图模块化组织&#xff1a;将应用分解为可重用的模块&#xff08;组件&#xff09;。每个蓝图封装了相关的视图、静态文件、模板等。按功能划分&#xff1a;将大型应用按功能模块划分&#xff08;例如&#xff1a;用户认证、博客、管理后台&#xff09;&#…

设计模式详解

1.创建类型1.1 简单工厂startuml抽象产品接口 interface Product { Operation(): string } 具体产品A class ConcreteProductA { Operation(): string } 具体产品B class ConcreteProductB { Operation(): string } 工厂类 class Factory { CreateProduct(type: string): Produ…

前端查漏补缺

插槽默认、具名&#xff08;多个插槽&#xff09;、作用域&#xff08;接收子组件数据&#xff09;//具名 <div class"container"><header><slot name"header"></slot></header><main><slot></slot></…

网络协议UDP、TCP

一、网络协议 UDPUDP用户数据报协议&#xff1a;传输层网络编程模型B/S模型&#xff1a;browser/server&#xff08;浏览器/服务器&#xff09;客户端是通用的客户端&#xff08;浏览器&#xff09;一般只做服务器开发客户端要加载的数据均来自服务器C/S模型&#xff1a;client…

STM32 TIM_SelectInputTrigger()函数

一、函数功能与定位​TIM_SelectInputTrigger()是STM32定时器外设的关键配置函数&#xff0c;用于设置从模式定时器的触发源&#xff08;Trigger Source&#xff09;​。其核心作用是将定时器的内部事件或外部信号映射为触发信号&#xff08;TRGI&#xff09;&#xff0c;进而控…

Lecture 6 Kernels, Triton 课程笔记

本讲座&#xff1a;基准测试/分析 编写内核 总结 编程模型&#xff08;PyTorch、Triton、PTX&#xff09;与硬件之间的差距 > 性能奥秘 理解扩展的基准测试 用于理解 PyTorch 函数内部结构的分析&#xff08;用内核触底&#xff09; 看 PTX 汇编&#xff0c;了解 CUDA 内核…

Spring Boot 整合网易163邮箱发送邮件实现找回密码功能

在开发用户系统时&#xff0c;发送邮件是一项常见需求&#xff0c;例如用户忘记密码时&#xff0c;通过邮箱发送验证码来验证身份并重置密码。本文将结合 Spring Boot 和 163 邮箱&#xff0c;演示如何实现邮件发送功能。 一、前提条件 普通用户的 163 邮箱可以在 Spring Boot…

如何在mac玩windows游戏?3个工具推荐,不用换电脑!

Mac电脑虽然很流畅&#xff0c;但它也存在局限性&#xff0c;其中一点游戏玩家应该深有体会&#xff0c;那就是无法直接玩Windows专属游戏&#xff0c;只能对着琳琅满目的游戏望眼欲穿。别急&#xff0c;我有办法让你在mac玩windows游戏&#xff0c;下面就来分享我的经验。一、…