ArrayList浅析

目录

  • 一、ArrayList源码
    • 1.1 迭代器
      • 1.1.1 Itr源码浅析
      • 1.1.2 ListItr源码浅析
    • 1.2 常用方法
    • 1.3 System.arraycopy
    • 1.4 ArrayList 的创建方式
  • 二、引申问题
    • 2.1 ArrayList的大小是如何增加的?
    • 2.2 什么情况下你会使用ArrayList
    • 2.3 在索引中ArrayList的增加或者删除某个对象的运行过程,效率很低吗?解释一下为什么
    • 2.4 ArrayList如何顺序删除节点
    • 2.5 ArrayList的遍历方法
  • 三、总结


一、ArrayList源码

在这里插入图片描述

首先看一下ArrayList的继承关系结构图
在这里插入图片描述

ArrayList的类声明

public class ArrayList<E> extends AbstractList<E>implements List<E>, RandomAccess, Cloneable, java.io.Serializable
{

1.1 迭代器

ArrayList源码中有一个内部类ListItr
ListItr是什么?---->官方注释:AbstractList的优化版本:ListItr

    /*** An optimized version of AbstractList.ListItr*/private class ListItr extends Itr implements ListIterator<E> {ListItr(int index) {super();cursor = index;}public boolean hasPrevious() {return cursor != 0;}public int nextIndex() {return cursor;}public int previousIndex() {return cursor - 1;}@SuppressWarnings("unchecked")public E previous() {checkForComodification();int i = cursor - 1;if (i < 0)throw new NoSuchElementException();Object[] elementData = ArrayList.this.elementData;if (i >= elementData.length)throw new ConcurrentModificationException();cursor = i;return (E) elementData[lastRet = i];}public void set(E e) {if (lastRet < 0)throw new IllegalStateException();checkForComodification();try {ArrayList.this.set(lastRet, e);} catch (IndexOutOfBoundsException ex) {throw new ConcurrentModificationException();}}public void add(E e) {checkForComodification();try {int i = cursor;ArrayList.this.add(i, e);cursor = i + 1;lastRet = -1;expectedModCount = modCount;} catch (IndexOutOfBoundsException ex) {throw new ConcurrentModificationException();}}}

可以看到 ListItr 继承自Itr,那么Itr长啥样子呢?
官方注释:Itr,一个AbstractList.Itr的优化版本

    /*** An optimized version of AbstractList.Itr*/private class Itr implements Iterator<E> {int cursor;       // index of next element to returnint lastRet = -1; // index of last element returned; -1 if no suchint expectedModCount = modCount;// prevent creating a synthetic constructorItr() {}public boolean hasNext() {return cursor != size;}@SuppressWarnings("unchecked")public E next() {checkForComodification();int i = cursor;if (i >= size)throw new NoSuchElementException();Object[] elementData = ArrayList.this.elementData;if (i >= elementData.length)throw new ConcurrentModificationException();cursor = i + 1;return (E) elementData[lastRet = i];}public void remove() {if (lastRet < 0)throw new IllegalStateException();checkForComodification();try {ArrayList.this.remove(lastRet);cursor = lastRet;lastRet = -1;expectedModCount = modCount;} catch (IndexOutOfBoundsException ex) {throw new ConcurrentModificationException();}}@Overridepublic void forEachRemaining(Consumer<? super E> action) {Objects.requireNonNull(action);final int size = ArrayList.this.size;int i = cursor;if (i < size) {final Object[] es = elementData;if (i >= es.length)throw new ConcurrentModificationException();for (; i < size && modCount == expectedModCount; i++)action.accept(elementAt(es, i));// update once at end to reduce heap write trafficcursor = i;lastRet = i - 1;checkForComodification();}}final void checkForComodification() {if (modCount != expectedModCount)throw new ConcurrentModificationException();}}

1.1.1 Itr源码浅析

可以在上面看到Itr实现了Iterator迭代器接口,实现了四个方法hasNext()next()remove()forEachRemaining()

  • int cursor;:表示下一个要返回的元素的索引。
  • int lastRet = -1;:表示最后一个返回的元素的索引;如果没有返回过元素,则为 -1。
  • int expectedModCount = modCount;:用于检查在迭代过程中是否有并发修改的情况。
  • Itr():私有构造方法,用于防止生成合成构造函数。
  • public boolean hasNext():判断是否还有下一个元素待返回。
  • public E next():返回下一个元素,并将游标向后移动一个位置。
  • public void remove():从列表中移除上一个返回的元素。
  • public void forEachRemaining(Consumer<? super E> action):对列表中剩余的元素执行指定操作。
    其他方法:
  • checkForComodification():检查在迭代过程中是否有并发修改。

在hasNext() 方法中:
判断游标和数组size大小是否相等,不相等则返回true,表示仍有下一个元素。

在 next() 方法中:
首先检查是否有并发修改(调用 checkForComodification() 方法)。
获取当前游标位置 i,检查是否超出列表大小,若超出则抛出 NoSuchElementException 异常。
获取 ArrayList 的元素数组 elementData。
若游标位置超出数组长度,则抛出 ConcurrentModificationException 异常。
将游标后移一位,返回当前元素,并更新 lastRet 为当前索引 i。

在 remove() 方法中:
检查是否有上一个元素被返回,若没有则抛出 IllegalStateException 异常。
检查是否有并发修改。
尝试从 ArrayList 中移除上一个返回的元素,更新游标和 lastRet,以及 expectedModCount。
若捕获到 IndexOutOfBoundsException 异常,则抛出 ConcurrentModificationException 异常。

1.1.2 ListItr源码浅析

Itr仅仅是实现了迭代器接口, 而ListItr继承自 Itr 类并实现了 ListIterator< E> 接口,用于提供对 ArrayList 的列表迭代器功能。以下是对代码中关键部分的详细解释:

  • ListItr(int index):构造方法,初始化 ListIterator 的游标位置为指定的索引 index。
  • public boolean hasPrevious():判断是否还有前一个元素。
  • public int nextIndex():返回下一个元素的索引。
  • public int previousIndex():返回前一个元素的索引。
  • public E previous():返回前一个元素,并将游标向前移动一个位置。
    首先检查是否有并发修改。
    计算前一个元素的索引 i,若小于 0 则抛出 NoSuchElementException 异常。
    获取 ArrayList 的元素数组 elementData。
    若索引超出数组长度,则抛出 ConcurrentModificationException 异常。
    更新游标和 lastRet,并返回前一个元素。
  • public void set(E e):将上一个返回的元素替换为指定的元素。
    检查是否有上一个元素被返回,若没有则抛出 IllegalStateException 异常。
    检查是否有并发修改,然后尝试调用 ArrayList 的 set 方法进行替换操作。
  • public void add(E e):在当前位置添加一个元素。
    检查是否有并发修改。
    尝试在当前位置添加元素,更新游标和 lastRet,以及 expectedModCount。
    若捕获到 IndexOutOfBoundsException 异常,则抛出 ConcurrentModificationException 异常。

这段代码实现了 ListIterator 的功能,允许在 ArrayList 中进行双向迭代,并提供了添加和替换元素的功能。同时,代码中也考虑了并发修改的情况,确保操作的安全性和一致性。

看一下迭代器的创建

    /*** Returns a list iterator over the elements in this list (in proper* sequence), starting at the specified position in the list.* The specified index indicates the first element that would be* returned by an initial call to {@link ListIterator#next next}.* An initial call to {@link ListIterator#previous previous} would* return the element with the specified index minus one.** <p>The returned list iterator is <a href="#fail-fast"><i>fail-fast</i></a>.** @throws IndexOutOfBoundsException {@inheritDoc}*/public ListIterator<E> listIterator(int index) {rangeCheckForAdd(index);return new ListItr(index);}/*** Returns a list iterator over the elements in this list (in proper* sequence).** <p>The returned list iterator is <a href="#fail-fast"><i>fail-fast</i></a>.** @see #listIterator(int)*/public ListIterator<E> listIterator() {return new ListItr(0);}

两个重载方法 listIterator() 和 listIterator(int index),用于返回一个 ListIterator 对象,从列表中的指定位置或者从列表的起始位置开始迭代元素。


1.2 常用方法

常用方法 无非增删改查

在这里插入图片描述

    public void add(int index, E element) {rangeCheckForAdd(index);modCount++;final int s;Object[] elementData;if ((s = size) == (elementData = this.elementData).length)elementData = grow();System.arraycopy(elementData, index,elementData, index + 1,s - index);elementData[index] = element;size = s + 1;}

添加一个元素到指定位置的列表中。
首先检查索引是否在合法范围内;
增加修改计数器 modCount;
检查并扩容;
使用 System.arraycopy 方法将原数组中的元素向后移动一个位置,并在指定位置插入新元素;
更新列表大小。

    public E remove(int index) {Objects.checkIndex(index, size);final Object[] es = elementData;@SuppressWarnings("unchecked") E oldValue = (E) es[index];fastRemove(es, index);return oldValue;}private void fastRemove(Object[] es, int i) {modCount++;final int newSize;if ((newSize = size - 1) > i)System.arraycopy(es, i + 1, es, i, newSize - i);es[size = newSize] = null;}

remove()
从列表中移除指定索引位置的元素。
首先检查索引是否在合法范围内;
获取移除的元素;
调用 fastRemove 方法将要移除元素后面的元素向前移动一个位置;
更新 modCount;
返回被移除的元素。

fastRemove()
快速移除指定位置元素的方法;
更新 modCount;
如果移除的不是最后一个元素,则调用 System.arraycopy 方法将后面的元素向前移动一个位置;
将数组最后位置置空;
更新列表大小。

    public E set(int index, E element) {Objects.checkIndex(index, size);E oldValue = elementData(index);elementData[index] = element;return oldValue;}

替换指定位置的元素为新元素;
检查索引是否合法;
获取替换之前的元素;
直接替换指定位置的元素为新元素;
返回替换之前的元素。

    public E get(int index) {Objects.checkIndex(index, size);return elementData(index);}

获取指定位置的元素;
检查索引是否合法;
返回指定位置的元素。


1.3 System.arraycopy

常用方法中只有增删操作使用了System.arraycopy

 public static native void arraycopy(Object src,  int  srcPos,Object dest, int destPos,int length);

System.arraycopy是一个native方法,

参数解释:

src:源数组,要复制元素的数组。
srcPos:源数组中开始复制的起始位置。
dest:目标数组,要复制到的数组。
destPos:目标数组中开始粘贴的位置。
length:要复制的元素数量。

对于增删操作中的 System.arraycopy 的使用场景:

在添加元素时,通过 System.arraycopy 将特定位置之后的元素依次向后移动一个位置,为新元素腾出空间;
在删除元素时,通过 System.arraycopy 将被删除元素位置之后的元素依次向前移动一个位置,填补被删除元素的空缺;
如果是替换元素或获取元素,通常不会直接使用 System.arraycopy。

System.arraycopy 是一种底层的数组复制方法,效率较高,但只能用于数组之间的元素复制,不能用于集合之间的元素复制。在增删操作中,通过 System.arraycopy 可以较方便地实现元素的移动和填充,同时能够保证数据的完整性和位置的正确性。


1.4 ArrayList 的创建方式

public class ArrayList<E> {public ArrayList()public ArrayList(int initialCapacity) public ArrayList(Collection<? extends E> c) }

通过无参构造创建时,数组的默认初始容量是10

通过指定长度参构造创建时,数组的初始容量是指定的长度

第三种在创建时,会将传入的集合数据存储到数组中,数组的初始容量是传入集合的长度


二、引申问题

2.1 ArrayList的大小是如何增加的?

在add方法中,添加元素,增长ArrayList的长度

    public void add(int index, E element) {rangeCheckForAdd(index);modCount++;final int s;Object[] elementData;if ((s = size) == (elementData = this.elementData).length)elementData = grow();System.arraycopy(elementData, index,elementData, index + 1,s - index);elementData[index] = element;size = s + 1;}
    private Object[] grow() {return grow(size + 1);}
    /*** Increases the capacity to ensure that it can hold at least the* number of elements specified by the minimum capacity argument.** @param minCapacity the desired minimum capacity* @throws OutOfMemoryError if minCapacity is less than zero*/private Object[] grow(int minCapacity) {int oldCapacity = elementData.length;if (oldCapacity > 0 || elementData != DEFAULTCAPACITY_EMPTY_ELEMENTDATA) {int newCapacity = ArraysSupport.newLength(oldCapacity,minCapacity - oldCapacity, /* minimum growth */oldCapacity >> 1           /* preferred growth */);return elementData = Arrays.copyOf(elementData, newCapacity);} else {return elementData = new Object[Math.max(DEFAULT_CAPACITY, minCapacity)];}}

在扩容过程中,会根据当前数组的容量和需要扩容的最小增量以及首选增量来计算新的容量大小,然后使用 Arrays.copyOf 方法创建一个新的数组,并将原数组的内容复制到新数组中,最后将新数组赋值给 elementData。完成了列表的扩容操作,确保ArrayList 在添加元素时能够保持合理的容量并避免频繁扩容。


2.2 什么情况下你会使用ArrayList

使用List无非就是使用它的常用方法,而从ArrayList的增删改查源码中我们可以看出,增删过程会将数组的元素拷贝到新数组中来,再添加新数据;由于扩容需要新建数组且拷贝之前到元素到新数组中,所以说数据越多,操作越慢。

如果数据量很大的情况下,并涉及到元素的增删,会十分浪费性能,不建议使用ArrayList
ArrayList查询快,知道索引瞬间查到,适合常用来查询,修改也比较快。


2.3 在索引中ArrayList的增加或者删除某个对象的运行过程,效率很低吗?解释一下为什么

从源码已经看出按索引增加或者删除某个对象,会使用底层的arraycopy挪动数组,效率相对较低,特别是在操作的位置接近列表的开始处时。这主要是由于数组的特性决定的

  • 数组的结构:ArrayList 内部使用数组作为数据存储结构,数组是一种紧凑的数据结构,元素在内存中是连续存储的。当在数组中某个位置插入或删除元素时,需要将该位置后面的所有元素向后或向前移动,以保持索引的连续性。
  • 移动元素的开销:在数组中,移动元素的操作是比较耗时的,因为需要将大量元素复制到新的位置。如果需要在数组的开始处插入或删除元素,那么所有后续元素都需要移动,这个开销是随索引位置增大而增大的。
  • 时间复杂度:在 ArrayList 中按索引增加或删除元素的时间复杂度为 O(n),其中 n 是列表元素的总数。这是因为需要移动大量元素来维持索引的连续性,复杂度与数组中需要移动的元素数量成正比。
  • 相对于末尾的操作:相比较于在 ArrayList 的末尾增加或删除元素,按索引操作效率更低。在末尾增加或删除元素时,时间复杂度为 O(1),因为不需要移动元素,只需修改数组的长度即可。

ArrayList 在按索引增加或删除元素时效率较低,特别是在操作的位置接近列表的起始处时。如果对列表的操作需求包括频繁的按索引增加或删除元素,可能会影响程序的性能。在这种情况下,考虑使用其他数据结构如 LinkedList 等可能会更加高效。


2.4 ArrayList如何顺序删除节点

可以使用迭代器(Iterator)来遍历列表并删除满足特定条件的节点。

  • 获取 ArrayList 的迭代器对象:通过调用 ArrayList 的 iterator() 方法获取一个迭代器对象,用于遍历 ArrayList 中的元素。
  • 使用迭代器遍历 ArrayList:通过迭代器的 hasNext() 和 next() 方法来遍历 ArrayList 中的元素。在遍历过程中,可以判断当前元素是否满足删除条件。
  • 删除满足条件的节点:如果发现某个节点(元素)满足删除条件,可以调用迭代器的 remove() 方法来删除当前节点。注意:在使用迭代器的 remove() 方法之前必须先调用 next() 方法来指向要删除的元素。
  • 循环遍历直至完成:重复执行第2步和第3步,直到遍历完成所有的节点。

示例

import java.util.ArrayList;
import java.util.Iterator;public class RemoveElementsInArrayList {public static void main(String[] args) {ArrayList<Integer> numbers = new ArrayList<>();numbers.add(1);numbers.add(2);numbers.add(3);numbers.add(4);numbers.add(5);Iterator<Integer> iterator = numbers.iterator();while (iterator.hasNext()) {int number = iterator.next();if (number % 2 == 0) {  // 删除偶数节点iterator.remove();}}System.out.println(numbers);}
}

2.5 ArrayList的遍历方法

适用迭代器的next()方法遍历。


三、总结

ArrayList 的特点:内部是数组,有序、可重复、可存 null 值
ArrayList 的优点:尾插效率高,支持随机访问,查询快,知道索引瞬间查到,是所有集合当中查询速度最快的,
ArrayList 的缺点:中间插入、删除效率低

  • 数组一旦创建长度就固定了,在使用的过程中,不能更改,所以说数组一旦满了就得扩容,扩容的操作是先创建一个原来容量1.5倍的新数组,然后将之前数组的元素拷贝到新数组中来,再添加新数据;由于扩容需要新建数组且拷贝之前到元素到新数组中,所以说数据越多,操作越慢。
  • 同样的道理,在执行插入操作的时候,需要将插入节点之后所有的数据向后移动,执行删除操作时,有需要将删除节点之后的所有数据向前移动,由于需要移动数据,所以说操作的节点之后的数据越多,操作越慢。

数组的两个概念:大小、容量

大小指的是数组元素的个数,容量指的是数组本身的长度(最多可存储的元素个数)

ArrayList 和 LinkedList 的区别

分类ArrayListLinkedList
数据结构数组链表
查询速度
增删速度不一定不一定
存储相同数据所需要的空间
应用场景查询较多增删较多

参考链接:
java集合框架05——ArrayList和LinkedList的区别

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

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

相关文章

【无标题】QTday1

#include "mywidget.h"MyWidget::MyWidget(QWidget *parent): QMainWindow(parent) {//设置窗口标题this->setWindowTitle("QQ");//设置窗口图标this->setWindowIcon(QIcon("C:\\Users\\雷特玉\\Desktop\\qq.png"));//设置窗口的背景颜色t…

Springboot(若依)国际化配置接口访问后返回????????

最近使用若依的框架进行二次开发&#xff0c;配置了国际化&#xff0c;application.yml配置英文时没问题&#xff0c;但配置中文basename: i18n/messages_zh_CN&#xff0c;访问接口就直接返回的???&#xff0c;如图&#xff1a; 于是检查了I18nConfig文件&#xff0c;没配错…

MathWorks的介绍,以及Simscape 的主要特点

MathWorks 是一家美国的软件公司&#xff0c;以其科学计算软件为广泛知名&#xff0c;特别是 MATLAB 和 Simulink。这两款产品广泛用于工程、科学研究、学术界和工业应用中&#xff0c;帮助用户进行数学计算、算法开发、数据可视化、数据分析&#xff0c;以及仿真和模型构建。 …

每日5题Day23 - LeetCode 111 - 115

每一步向前都是向自己的梦想更近一步&#xff0c;坚持不懈&#xff0c;勇往直前&#xff01; 第一题&#xff1a;111. 二叉树的最小深度 - 力扣&#xff08;LeetCode&#xff09; /*** Definition for a binary tree node.* public class TreeNode {* int val;* TreeN…

探索Java 8 Stream API:现代数据处理的新纪元

Stream流 Stream初探&#xff1a;何方神圣&#xff1f; Stream流是一种处理集合数据的高效工具&#xff0c;它可以让你以声明性的方式处理数据集合。Stream不是存储数据的数据结构&#xff0c;而是对数据源&#xff08;如集合、数组&#xff09;的运算操作概念&#xff0c;支…

python绘制散点图

文章目录 1.实验目的2.需求3. 代码以及资源文件4.实验结果 1.实验目的 掌握Python绘图库matplotlib库 2.需求 3. 代码以及资源文件 import numpy as np import matplotlib.pyplot as plt import pandas as pd# 读取NPZ文件 data np.load(../Files/国民经济核算季度数据.npz…

cilium关闭vxlan

说明 操作 启用标志 yum -y install net-tools.x86_64 ifconfig | grep vxlan cilium_vxlan: flags4163<UP,BROADCAST,RUNNING,MULTICAST> mtu 1500修改相关配置 ks get cm cilium-config -oyaml | grep -E tunnel|ipv4-native-routing-cidr|auto-direct-node-routes…

【OceanBase DBA早下班系列】—— 性能问题如何 “拍CT“ (一键获取火焰图和扁鹊图)

1. 前言 最近接连遇到几个客户的环境在排查集群性能问题&#xff0c;总结了一下&#xff0c;直接教大家如何去获取火焰图、扁鹊图&#xff08;调用关系图&#xff09;&#xff0c;直击要害&#xff0c;就像是内脏的疾病去医院看病&#xff0c;上来先照一个CT&#xff0c;通过分…

for循环结构

循环&#xff1a; 循环是一个重复执行一个代码的结构。只要满足循环的条件&#xff0c;会一直执行这个代码。 循环条件&#xff1a;在一定范围之内&#xff0c;按照指定的次数来执行循环。 循环体&#xff1a;在指定的次数内&#xff0c;执行的命令序列。只要条件满足&#…

【iOS】KVC相关总结

目录 1. 什么是KVC&#xff1f;2. 访问对象属性常用方法声明基础使用KeyPath路径多值操作 3. 访问集合属性4. 集合运算符自定义集合运算符 5. 非对象值处理访问基本数据类型访问结构体 6. 属性验证7. 设值和取值原理基本的Getter搜索模式基本的Setter搜索模式NSMutableArray搜索…

Windows本地使用SSH连接VM虚拟机

WIN10 VM17.5 Ubuntu:20.04 1.网路设置 1)选择编辑->更改设置 配置完成 2.修改了服务器文件&#xff0c;修改sshd配置&#xff0c;在此文件下/etc/ssh/sshd_config&#xff0c;以下为比较重要的配置 PasswordAuthentication yes PermitRootLogin yes PubkeyAuthenticat…

[ue5]建模场景学习笔记(6)——必修内容可交互的地形,交互沙(4)

1.需求分析&#xff1a; 现在我们已经有了可以在世界内近于无限的跑动痕迹&#xff0c;现在需要对痕迹进行细化&#xff0c;包括例如当人物跳起时便不再绘制痕迹&#xff0c;以及痕迹应该存在深浅&#xff0c;应该由两只脚分别绘制&#xff0c;同时也应该对地面材质进行进一步处…

Vue基本使用-02

上节我们讲了什么是mvvm模型&#xff0c;以及我们vue的一些常用指令&#xff0c;今天给大家讲一下vue的基本使用&#xff0c;在将之前我们需要重点讲解我们的一个指令&#xff0c;v-model指令 v-model v-model 可以在组件上使用以实现双向绑定,什么是双向绑定呢?意思就是当我们…

景芯SoC A72的时钟树分析

innovus的ctslog中的Clock DAG信息可以报出来CTS主要运行步骤的关键信息&#xff0c;比如clustering&#xff0c;balancing做完后的clock tree的长度&#xff0c;clock tree上所用的buffer、inverter&#xff0c;icg cell数量&#xff0c;clock skew等信息。我们以景芯SoC A72 …

Centos离线安装Python3

目录 1.准备工作 2.解压python压缩包 3.编译 4.安装、更改环境变量 5.建立pip连接 使用的是Centos7服务器&#xff0c;Py版本是py3.9.0 1.准备工作 首先确保服务器中存在相关的编译器&#xff0c;例如GCC&#xff1b;这里不做过多叙述&#xff0c;需要者前往&#xff1a…

空间搜索geohash概述;redis的geo命令

概述 通常在一些2C业务场景中会根据用户的位置来搜索一些内容。通常提供位置搜索的都是直接通过redis/mongodb/es等中间件实现的。 但是这些中间件又是怎么实现位置搜索的呢&#xff1b; 查了一番资料&#xff0c;发现背后一个公共的算法Geohash。 搜索的时候可以根据距离对…

Vitis HLS 学习笔记--移除内存分配malloc

目录 1. 简介 2. 示例解析 2.1 源码解释 2.2 malloc 分析 2.3 替代方案分析 3. 总结 1. 简介 Vitis HLS 也不支持动态创建或删除 C/C 对象&#xff08;用于综合&#xff09;。 本文探究如何在C/C代码中避免使用显式的malloc函数来分配内存。在硬件设计和FPGA开发中&…

Xcode无法使用设备:Failed to prepare the device for development

问题&#xff1a; Xcode无法使用设备开发&#xff0c;失败报错如下&#xff1a; Failed to prepare the device for development. This operation can fail if the version of the OS on the device is incompatible with the installed version of Xcode. You may also need…

致 粉丝de信

致 粉丝 -本文呢看不下去别看&#xff0c;但是学业是真的重要&#xff08;平常有信奥&#x1f62b;&#xff09;&#xff0c;电脑没收……更新可能得到暑假&#xff0c; 同学&#xff1a;小没苯agoe &#xff08;aaa&#xff0c;学霸&#xff01;&#xff01;&#xff01;&…

GGML简单介绍

GGML是一个用于机器学习的张量库&#xff0c;可以在商用硬件上实现大型模型和高性能。它被llama.cpp和whisper.cpp使用 C语言编写 16位浮点支撑 整数量化支持(如4位、5位、8位) 自动分化 内置优化算法(如ADAM, L-BFGS) 针对苹果芯片进行优化 在x86架构上利用AVX / AVX2的内在特…