当前位置: 首页 > news >正文

【数据结构篇】线性表1 --- 顺序表、链表 (万字详解!!)

前言:这篇博客我们重点讲 线性表中的顺序表、链表

线性表(linear list)是n个具有相同特性的数据元素的有限序列

线性表是一种在实际中广泛使用的数据结构,常见的线性表:顺序表、链表、栈、队列...

线性表在逻辑上是线性结构,也就说是连续的一条直线。但是在物理结构上并不一定是连续的,线性表在物理上存储时,通常以数组和链式结构的形式存储。 

 顺序表(ArrayList)

什么是顺序表? 

顺序表是用一段物理地址连续的存储单元,依次存储数据元素的线性结构,一般情况下采用数组存储。在数组上完成数据的增删查改。

 也就是说,顺序表  底层结构就是 一个数组。是使用数组 来完成的一种结构。

那现在有一个数组,如果有一组数据 1,2,3,4,5,6,7 , 我们现在想把这组数据放到数组里去。

我们先放进1,2,3 , 问当前数组里有多少个有效数据? 很明显是 3 个。

那怎么利用程序判断他有 3 个有效数据呢?

我们需要先定义一个变量 usedSize , 放进一个数据 usedSize++,放一个就加一下。这不就能确定有几个有效数据了吗。

代码实现 (MyArrayList)

接下来我们利用代码来实现顺序表的增删查改等方法: 

--- 打印顺序表 

就是遍历数组 

--- 新增元素 

1.新增元素,默认在数组最后新增

 这么写没问题吗?如果满了怎么办?

所有我们要写一个方法来判断是否满了 :

新增元素前我们要判断是否满了,满了的话要扩容 

新增看看效果:

  

2.在指定位置新增元素 

我们的逻辑应该是把指定位置之后的数据 都向后,把指定位置空出来,再在指定位置插入数据 。

那具体该如何挪数据? 

我们要从最后的位置开始挪 ,不能从第一个开始挪,不然会把之后的数据盖掉。

 

那我们现在确定了挪的方法,接下来我们看看代码如何实现: 

注意:我们这里是要判断pos的位置是否合法的 ,

pos不能小于0,也不能跳着放(大于usedSize).

为此我们还搞了个异常 

(ps:异常之前讲过 链接 https://blog.csdn.net/iiiiiihuang/article/details/130671801?spm=1001.2014.3001.5501 )

我们看看运行效果 :

看看位置不合法时的运行结果: 

--- 判断是否包含某个元素

运行结果  


--- 查找某个元素具体位置(下标)

运行结果 

--- 获取 pos 位置的元素

还要判断位置是否合法。

运行结果 

--- 给pos位置 的值设为 value 

 这里同样要先判断 pos 位置是否合法,那我们可以单独写一个方法,来判断。(方法的封装)

运行结果 

--- 获取顺序表长度

--- 删除第一次出现的关键字 

代码实现 

 

注意:usedSize - 1 防止越界,这里是 this.elem[i] = this.elem[i + 1], 那 i 走到倒数第二位就行了

运行结果 

--- 清除顺序表 

 

ps (小提一嘴): 现在的都是整型这么写可以,但是的是 引用类型 的时候要一个一个 置为 null ,删除也要有类似操作。

完整代码

import java.util.ArrayList;
import java.util.Arrays;/*** @Author: iiiiiihuang*/
public class MyArrayList {private int[] elem;//存放数据元素。private int usedSize;//代表当前顺序表中有效数据个数。private  static  final int DEFAULT_SIZE = 10;/*** 默认构造方法*/public MyArrayList() {this.elem = new int[DEFAULT_SIZE];}/*** 指定容量* @param initCapacity*/public MyArrayList(int initCapacity) {this.elem = new int[initCapacity];}/*** 打印顺序表中的所有元素*/public void display() {for (int i = 0; i < this.usedSize; i++) {System.out.print(this.elem[i] + " ");}}public boolean isFull() {if(this.usedSize == this.elem.length){return true;}return false;}/*** 新增元素,默认在数组最后新增* @param date*/public void add(int date){if(isFull()){//扩容this.elem = Arrays.copyOf(this.elem, 2*this.elem.length);}this.elem[this.usedSize] = date;this.usedSize++;}//判断pos位置是否合法private void checkPos(int pos){if(pos < 0 || pos >= usedSize){throw new PosOutOfBoundsException(pos + "位置不合法");}}/*** 在指定位置(pos)新增元素* @param pos* @param date*/public void add(int pos, int date) {//判断pos位置是否合法if(pos < 0 || pos > usedSize){throw new PosOutOfBoundsException(pos + "位置不合法");}if(isFull()){this.elem = Arrays.copyOf(this.elem, 2*this.elem.length);}for (int i = this.usedSize - 1; i >= pos; i--) {this.elem[i + 1] = this.elem[i];}this.elem[pos] = date;usedSize++;}/*** 判断是否包含某个元素* @param toFind* @return*/public boolean contains(int toFind){for (int i = 0; i < this.usedSize; i++) {if(this.elem[i] == toFind){return true;}}return false;}/*** 查找某个元素具体位置(下标)* @param toFind* @return*/public int indexOf(int toFind){for (int i = 0; i < this.usedSize; i++) {if(this.elem[i] == toFind){return i;}}return -1;}/*** 获取 pos 位置的元素* @param pos* @return*/public int get(int pos) {//判断pos位置是否合法checkPos(pos);return this.elem[pos];}/*** 给pos位置 的值设为 value* @param pos* @param value*/public void set(int pos, int value) {checkPos(pos);this.elem[pos] = value;}/*** 获取顺序表长度*/public int size() {return this.usedSize;}/*** 删除第一次出现的关键字* @param toRemove*/public void remove(int toRemove) {//获取要删除元素下标int index = indexOf(toRemove);if(index == -1){System.out.println("没有这个数据");return;}//usedSize - 1 防止越界for (int i = index; i < this.usedSize - 1; i++) {this.elem[i] = this.elem[i + 1];}usedSize--;}/*** 清除顺序表*/public void clear() {this.usedSize = 0;}
}

上述是自己实现一个顺序表结构,那以后用到顺序表都要我们自己重新实现吗? 当然不用啦! 

Java里面已经帮你处理好了,有现成的 ,就是 ArrayList

ArrayList
 

在集合框架中,ArrayList是一个普通的类,实现了List接口 。 

1. ArrayList是以泛型方式实现的,使用时必须要先实例化
2. ArrayList实现了RandomAccess接口,表明ArrayList支持随机访问
3. ArrayList实现了Cloneable接口,表明ArrayList是可以clone的
4. ArrayList实现了Serializable接口,表明ArrayList是支持序列化
5. 和Vector不同,ArrayList不是线程安全的,在单线程下可以使用,在多线程中可以选择          Vector或者CopyOnWriteArrayList
6. ArrayList底层是一段连续的空间,并且可以动态扩容,是一个动态类型的顺序表 

我们可以在 IDEA 里看到 ArrayList 的源码

接下来我们 来介绍一下 ArrayList 的几种用法。

ArrayList 的实例化

 这两种方法都行,区别就在于,方法一 可以调用的方法更多一些。 但是方法二 发生了向上转型,

一般情况下,我们用方法二多一点。

(ps: 向上转型 前面介绍过了 链接  https://blog.csdn.net/iiiiiihuang/article/details/130484383?spm=1001.2014.3001.5501 )

ArrayList的构造 

方法解释
ArrayList()无参构造
ArrayList(Collection<? extends E> c)利用其他 Collection 构建 ArrayList
ArrayList(int initialCapacity)指定顺序表初始容量

当我们调用不带参数的构造方法时,默认在第一次 add 时才会分配大小为10的内存

扩容按1.5倍进行扩容 

  

ArrayList常见操作
 

方法解释
boolean add(E e)尾插 e
void add(int index, E element)将 e 插入到 index 位置
boolean addAll(Collection<? extends E> c)尾插 c 中的元素
E remove(int index)删除 index 位置元素
boolean remove(Object o)删除遇到的第一个 o
E get(int index)获取下标 index 位置元素
E set(int index, E element)将下标 index 位置元素设置为 element
void clear()清空
boolean contains(Object o)判断 o 是否在线性表中
int indexOf(Object o)返回第一个 o 所在下标
int lastIndexOf(Object o)返回最后一个 o 的下标
List<E> subList(int fromIndex, int toIndex)截取部分 list

注意:这个remove怎么用? 

 

要这么写才能删掉 等于2 的元素 

演示一下 subList

截取到2,3    (Java里一般都是左闭右开的 [ , , )   ) 

如果我们把 list3 的 0 下标该成 188 会方生什么?

我们发现,list2 的 1 下标的位置(list3 的 0下标)也变成了188  . 为什么? 

这是因为list3, 截取的时候并没有真正的把这个数据拿出来,只是指向了1 下标那儿的地址 ,所有更新值肯定会影响 list2.

ArrayList的遍历
 

ArrayList 可以使用三方方式遍历:使用迭代器 ,for循环+下标、foreach 

 上面是直接 用sout 遍历 的,是因为重写了 toString 方法。 

---- 迭代器 

一般情况下,能够直接通过 sout 输出 引用指向对象当中的内容的时候,此时一定重写了 toString 方法。 

那我们看看ArrayList 里有没有 toString (ctrl + F) 搜索一下。发现没有。

 

但是 ArrayList  还继承了 AbstractList,我们去 AbstractList 里找找。发现还没有。

但是 AbstractList 还继承了 AbstractCollection ,

我们在 AbstractCollection 这里找到了 toString。

下面画线那个部分就是 迭代器 (遍历当前集合)

--- 用法一 

--- 用法二 

上面两个用那个都行 

--- 从后往前打印 

ps : 这个方法不行,因为这个不能传参 

----  for循环+下标

---- foreach 

 

 

ArrayList 的优缺点 

优点 

 1.可以通过下标 进行随机访问,顺序表适合对静态的数据进行 查找 和 更新

缺点 

1.添加元素的效率比较低 (假如在 0 位置添加元素,就需要把后面所有的元素都往后移)

2.删除的效率也低(假如删除 0 位置元素,也需要移动后面所有的元素)

3.扩容 按1.5 倍扩容,有浪费 空间的情况。

(顺序表不适合用来 插入和删除 数据)

顺序表适合对静态的数据进行 查找 和 更新,不适合用来 插入和删除 数据,这时候就需要用 链表来做。接下来我们来介绍链表。

链表 (LinkedList)

什么是链表?
 

链表 是一种 物理存储结构上非连续 的存储结构,数据元素的 逻辑顺序 是通过链表中的 引用链接次序实现的 。

链表是由一个一个 节点 连成的 :(这个是单向 不带头 非循环 链表的节点)

 

单向 不带头 非循环 链表 

除此之外还有很多 类型的 链表,一般从三个方向去分 

  • 单向    双向
  • 不带头   带头
  • 非循环   循环  

 经过排列组合就会有下面这几种类型的链表:

  • 单向 不带头 非循环 链表
  • 单向 不带头 循环 链表
  • 单向 带头 非循环 链表
  • 单向 带头 循环 链表
  • 双向 不带头 非循环 链表
  • 双向 不带头 循环 链表
  • 双向 带头 非循环 链表
  • 双向 带头 循环 链表

上面我们画了不带头的 链表,接下来我们了解一下 带头的是啥样的?

再来看看 循环的

等我们把单向的介绍完,在介绍双向的 。

我们重点讲 单向 不带头 非循环 链表 和 双向 不带头 非循环 链表 (这两种是工作,笔试面试考试重点)

单向 不带头 非循环 链表 

代码实现 

节点

上述可知 链表是由一个一个 节点 组成的,所以我们可以把这个节点定义成个内部类 。

还得有一个 指向 第一个节点 的属性:

插入数据 

--- 头插法 

  

注意:如果我们把下面的语句反过来写可以吗? 变成 head = node;  node.next = head;

 

 不可以,先把node 置为 head, node 的下一个指向 head, 那不就是 自己指向自己了吗,后面的节点就都丢失了。

我们插入看看效果 

 --- 尾插法

先找到最后一个节点,

所以循环里要写成 cur.next != null, 在到最后一个节点这就不进入循环了,那此时cur 就是最后一个节点,而不能写成cur != null, 这样会遍历完整个链表,停不住。 

 

运行看看效果: 

似乎是可以的,但是如果现在链表了一个节点也没有,再插入呢?

报错了!!—— 空指针异常 ,为啥呀? 我们返回代码哪里看一看,调试一下:

我们发现当 链表里一个节点都没有的时候,head  = null,那cur = head, cur 也是 null,

cur都为空了,哪来的 next ,那当然就报出来空指针异常了。

所以接下来我们改进一下代码: 

那我们再运行一下代码,就没有任何问题了

--- 任意位置插入(第一个数据节点为0号下标)
 

很明显,我们要确定 插入位置的前一个节点, 那如果你要插入 2 位置,那你就要找到 1 位置节点,那从 0 位置到 1 位置要走一步,也就是 index - 1 步。

找到要插入位置的前一个节点。这个是写方法 里面,还是单独封装看你喜好。

(我用的 while 循环,如果用for 循环的话,i < index - 1,  我觉得while 循环好理解点。)

 

 找到位置了,我们就可以插入了。 

先判断插入位置合不合法(类比上面的顺序表的部分)

都要先和后边的节点建立联系哦  

看看效果

打印链表 

 

但是用上面的方式走完之后,我自己都不知道头节点在哪里了 ,很可怕耶,

所以我们定义一个 cur节点 来代替 头节点 往下走。

 

 单链表的长度

 

查找单链表中是否包含关键字key

删除第一次出现关键字为key的节点
 

还是要找到删除节点的前一个,

为什么,循环那里要 cur.next != null, 因为,cur.next 不能是null,因为如果它是 null 的话,

那cur.next.val 就找不到值,那就会引起空指针异常,所以只要走到倒数第一个停住就好了(cur走到最后一个节点时不进入循环) 

看看效果:

删除所有值为key的节点
 

注意 :我们删除的是 cur 对应的值,cur 从第二个节点开始走,那如果第一个也是23(要删除的值)呢 ,所以我们要单独删除头节点,且在最后,不能放在前面。

运行结果 

清除链表 

完整代码 

/*** @Author: iiiiiihuang*/
public class MySingleLinkedList {//把节点定义成个内部类static class ListNode {public int val;//节点的值域public ListNode next;//下一个节点的地址public ListNode(int val) {this.val = val;}}public ListNode head;//头节点/*** 头插法* @param data*/public void addFirst(int data) {//给插入的数据创个节点ListNode node = new ListNode(data);node.next = head;head = node;}/*** 尾插法* @param data*/public void addLast(int data) {ListNode node = new ListNode(data);ListNode cur = head;if(cur == null) {head = node;return;}//先找到最后一个节点while (cur.next != null) {cur = cur.next;}cur.next = node;}/*** 打印链表*/public void display() {ListNode cur = head;while(cur != null) {System.out.print(cur.val + " ");cur = cur.next;}System.out.println();}/*** 任意位置插入* @param index* @param data*/public void addIndex(int index,int data) {ListNode node = new ListNode(data);//先判断插入位置合不合法if(index < 0 || index > size()){throw new IndexOutOfBoundsException();}if(index == 0) {addFirst(data);return;}if(index == size()) {addLast(data);return;}ListNode cur = findIndexSubOne(index);node.next = cur.next;cur.next = node;}//找到要插入位置的前一个节点private ListNode findIndexSubOne(int index) {ListNode cur = head;while (index - 1 != 0) {cur = cur.next;index--;}return cur;}/*** 单链表的长度* @return*/public int size() {ListNode cur = head;int count = 0;while (cur != null) {count++;cur = cur.next;}return count;}/*** 查找单链表中是否包含关键字key* @param key* @return*/public boolean contains(int key) {ListNode cur = head;while (cur != null) {if(cur.val == key) {return true;}cur = cur.next;}return false;}/*** 删除第一次出现关键字为key的节点* @param key*/public void remove(int key) {if(head == null) {return;}//单独删除头节点if(head.val == key) {head = head.next;return;}//找到删除节点的前一个ListNode cur = findRemSubOne(key);if(cur == null) {System.out.println("没有你要删除的数字");return;}ListNode rem = cur.next;cur.next = rem.next;}//找到删除节点的前一个节点private ListNode findRemSubOne(int key) {ListNode cur = head;//这里跳过了头节点while (cur.next != null) {if (cur.next.val == key) {return cur;}cur = cur.next;}return null;}/*** 删除所有值为key的节点* @param key*/public void removeAllKey(int key) {ListNode cur = head.next;ListNode prev = head;while (cur != null) {if(cur.val == key) {prev.next = cur.next;} else {prev = cur;}cur = cur.next;}//删除头节点if(head.val == key) {head = head.next;}}/*** 清除链表*/public void clear() {this.head = null;}
}

 双向 不带头 非循环 链表

画图看看结构

代码实现 

创建节点内部类 

上面有的方法这也有 😀😀

插入数据

--- 头插法 

链表为空时,必须单独分情况,因为如果不分会:

运行结果 

--- 尾插法 

 

打印链表

和上面一样 

查找链表中是否包含关键字key 

和上面一样 

 链表的长度

和上面一样

运行结果 

任意位置插入,第一个数据节点为0号下标

运行结果

删除第一次出现关键字为key的节点

代码 

头尾分开来,不然会空指针异常 。

运行结果 

但是上面的代码还有问题

如果只有一个节点时,head = head.next; 那此时head 就是 null,那此时再head.prev 就会引起空指针异常 

所以要改成这样:

删除所有值为key的节点

和上面几乎一致,只有一点不一样。 

运行结果 

清除链表 

最简单粗暴的 

或者把每一个都置为空 

 

完整代码

import java.util.List;/*** @Author: iiiiiihuang*/
public class MyLinkedList {static class ListNode {private int val;private ListNode prev;private ListNode next;public ListNode(int val) {this.val = val;}}public ListNode head;public ListNode last;/*** 头插法* @param data*/public void addFirst(int data){ListNode node = new ListNode(data);if(head == null) {head = node;last = node;}else {node.next = head;head.prev = node;head = node;}}/*** 尾插法* @param data*/public void addLast(int data){ListNode node = new ListNode(data);if(head == null) {head = node;last = node;} else {last.next = node;node.prev = last;node = last;}}/*** 任意位置插入,第一个数据节点为0号下标* @param index* @param data*/public void addIndex(int index,int data){ListNode node = new ListNode(data);checkIndex(index);if(index == 0) {addFirst(data);return;}if(index == size()) {addLast(data);return;}ListNode cur = searchIndex(index);node.prev = cur.prev;node.next = cur;cur.prev.next = node;cur.prev = node;}//找到插入位置private ListNode searchIndex(int index) {ListNode cur = head;while (index != 0) {cur = cur.next;index--;}return cur;}//检查index的位置是否合法private void checkIndex(int index) {if(index < 0 || index > size()) {throw new IndexOutOfBoundsException("位置不合法");}}/*** 查找关键字key是否在链表当中* @param key* @return*/public boolean contains(int key){ListNode cur = head;while (cur != null) {if(cur.val == key) {return true;}cur = cur.next;}return false;}/*** 删除第一次出现关键字为key的节点* @param key*/public void remove(int key){ListNode cur = head;while (cur != null) {if(cur.val == key) {//删除头节点if(cur == head) {head = head.next;if(head != null) {//只有一个节点时head.prev = null;} else {last = null;}} else {//删除中间节点 和 尾巴节点if(cur.next != null) {//删除中间节点cur.prev.next = cur.next;cur.next.prev = cur.prev;} else {cur.prev.next = cur.next;last = last.prev;}}return;} else {cur = cur.next;}}}/*** 删除所有值为key的节点* @param key*/public void removeAllKey(int key){ListNode cur = head;while (cur != null) {if(cur.val == key) {//删除头节点if(cur == head) {head = head.next;if(head != null) {//只有一个节点时head.prev = null;} else {last = null;}} else {//删除中间节点 和 尾巴节点if(cur.next != null) {//删除中间节点cur.prev.next = cur.next;cur.next.prev = cur.prev;} else {cur.prev.next = cur.next;last = last.prev;}}}cur = cur.next;}}/*** 得到链表的长度* @return*/public int size(){ListNode cur = head;int count = 0;while (cur != null) {count++;cur = cur.next;}return count;}/*** 打印链表*/public void display(){ListNode cur = head;while (cur != null) {System.out.print(cur.val + " ");cur = cur.next;}System.out.println();}/*** 清除链表*/public void clear(){ListNode cur = head;while (cur != null) {//先记录下数据ListNode curNext = cur.next;cur.prev = null;cur.next = null;cur = curNext;}head = null;last = null;}
}

 

 LinkedList的使用

先实例化一下 

 

我们之前写的方法他都有,你只要调用就好了。😁😁😁 

 

 

LinkedList 的 常见方法 

方法解释
boolean add(E e)尾插 e
void add(int index, E element)将 e 插入到 index 位置
boolean addAll(Collection<? extends E> c)尾插 c 中的元素
E remove(int index)删除 index 位置元素
boolean remove(Object o)删除遇到的第一个 o
E get(int index)获取下标 index 位置元素
E set(int index, E element)将下标 index 位置元素设置为 element
void clear()清空
boolean contains(Object o)判断 o 是否在线性表中
int indexOf(Object o)返回第一个 o 所在下标
int lastIndexOf(Object o)返回最后一个 o 的下标
List<E> subList(int fromIndex, int toIndex)截取部分 list

 

LinkedList 的总结 

1. LinkedList实现了List接口
2. LinkedList的底层使用了双向链表
3. LinkedList没有实现RandomAccess接口,因此LinkedList不支持随机访问
4. LinkedList的任意位置插入和删除元素时效率比较高,时间复杂度为O(1)
5. LinkedList比较适合任意位置插入或删除的场景  

ArrayList和LinkedList的区别(顺序表和链表的区别)(面试题)
 

不同点ArrayListLinkedList
存储空间上物理上一定连续逻辑上连续,但物理上不一定连续
随机访问支持O(1) (有下标)不支持:O(N)
头插需要搬移元素,效率低O(N)只需修改引用的指向,时间复杂度为O(1)
插入空间不够时需要扩容没有容量的概念
应用场景元素高效存储+频繁访问时任意位置插入和删除频繁时

╰(*°▽°*)╯╰(*°▽°*)╯╰(*°▽°*)╯╰(*°▽°*)╯╰(*°▽°*)╯完 ╰(*°▽°*)╯╰(*°▽°*)╯╰(*°▽°*)╯╰(*°▽°*)╯╰(*°▽°*)╯

相关文章:

【数据结构篇】线性表1 --- 顺序表、链表 (万字详解!!)

前言&#xff1a;这篇博客我们重点讲 线性表中的顺序表、链表 线性表&#xff08;linear list&#xff09;是n个具有相同特性的数据元素的有限序列。 线性表是一种在实际中广泛使用的数据结构&#xff0c;常见的线性表&#xff1a;顺序表、链表、栈、队列... 线性表在逻辑上是…...

C语言每日一练--Day(17)

本专栏为c语言练习专栏&#xff0c;适合刚刚学完c语言的初学者。本专栏每天会不定时更新&#xff0c;通过每天练习&#xff0c;进一步对c语言的重难点知识进行更深入的学习。 今日练习题关键字&#xff1a;数对 截取字符串 &#x1f493;博主csdn个人主页&#xff1a;小小unico…...

8月琐碎但值得的事情

8月份结束了&#xff0c;最近心态比较好&#xff0c;慢点就慢点&#xff0c;没有那么着急了&#xff0c;可能是因为着急也没啥办法&#xff0c; 8月是比较开心的一个月&#xff0c;可能是做的事情更有盼头了&#xff0c;可能是看了喜欢的书&#xff0c;可能是我变瘦了&#xff…...

苹果Mac系统如何优化流畅的运行?提高运行速度

Mac系统的稳定性和流畅性一直备受大家称赞&#xff0c;这也是大多数人选择Mac的原因&#xff0c;尽管如此&#xff0c;我们仍不时地对Mac进行优化、调整&#xff0c;以使其比以前更快、更流畅地运行。以下是小编分享给各位的Mac优化方法&#xff0c;记得保存哦~ 一、释放被过度…...

Python 类和对象

类的创建 Python语言中&#xff0c;使用class关键字来创建类&#xff0c;其创建方式如下&#xff1a; class ClassName(bases):# class documentation string 类文档字符串&#xff0c;对类进行解释说明class_suiteclass是关键字&#xff0c;bases是要继承的父类&#xff0c;…...

VC++使用Microsoft Speech SDK进行文字TTS朗读

Microsoft Speech SDK下载地址 https://www.microsoft.com/en-us/download/details.aspx?id10121 需要msttss22L.exe、SpeechSDK51.exe、SpeechSDK51LangPack.exe三个&#xff0c;下载后全部安装 使用VS2005建立一个win32控制台项目 朗读"hello word"、中文“你好”…...

FFmpeg4.3.1+h264在windows下编译与VS2017项目集成

前言 在Android音视频开发中&#xff0c;网上知识点过于零碎&#xff0c;自学起来难度非常大&#xff0c;不过音视频大牛Jhuster提出了《Android 音视频从入门到提高 - 任务列表》&#xff0c;结合我自己的工作学习经历&#xff0c;我准备写一个音视频系列blog。本文是音视频系…...

mapboxGL3新特性介绍

概述 8月7日&#xff0c;mapboxGL发布了3版本的更新&#xff0c;本文带大家一起来看看mapboxGL3有哪些新的特性。 新特新 如上图所示&#xff0c;是mapboxGL官网关于新版的介绍&#xff0c;大致翻译如下&#xff1a; 增强了web渲染的质量、便捷程度以及开发人员体验&#xff…...

类ChatGPT大模型LLaMA及其微调模型

1.LLaMA LLaMA的模型架构:RMSNorm/SwiGLU/RoPE/Transfor mer/1-1.4T tokens 1.1对transformer子层的输入归一化 对每个transformer子层的输入使用RMSNorm进行归一化&#xff0c;计算如下&#xff1a; 1.2使用SwiGLU替换ReLU 【Relu激活函数】Relu(x) max(0,x) 。 【GLU激…...

50个简洁的提示提高代码可读性和效率(0-10)

这篇文章整理了50个简洁的提示&#xff0c;可以提高您的代码可读性和效率。这些提示来自个人项目、彻底的代码审查和与资深开发人员的启发性讨论。 无论您是新手还是经验丰富的开发人员&#xff0c;这篇文章都应该能够帮助您学到一些东西。 这个列表包括常见的Python模式、核…...

Linux —— 进程信号

一&#xff0c;信号概念 信号是进程之间事件异步通知的一种方式&#xff0c;属于软中断&#xff1b; 系统定义的信号 每个信号都有一个编号和一个宏定义名称&#xff08;可在signal.h查看&#xff09;&#xff1b;编号34以上的为实时信号&#xff1b; [wz192 Desktop]$ kill -…...

Android笔记 自定义控件时drawText字符串宽度的3种计算方式

String str "hello"; canvas.drawText(str, x, y, mPaint);//1. 粗略计算文字宽度&#xff1a; float width mPaint.measureText(str);//2. 计算文字的矩形&#xff0c;可以得到宽高&#xff1a; Rect rect new Rect(); mPaint.getTextBounds(str, 0, str.length(…...

ChatRWKV 学习笔记和使用指南

0x0. 前言 Receptance Weighted Key Value&#xff08;RWKV&#xff09;是pengbo提出的一个新的语言模型架构&#xff0c;它使用了线性的注意力机制&#xff0c;把Transformer的高效并行训练与RNN的高效推理相结合&#xff0c;使得模型在训练期间可以并行&#xff0c;并在推理…...

Particle Life粒子生命演化的MATLAB模拟

Particle Life粒子生命演化的MATLAB模拟 0 前言1 基本原理1.1 力影响-吸引排斥行为1.2 距离rmax影响 2 多种粒子相互作用2.1 双种粒子作用2.1 多种粒子作用 3 代码 惯例声明&#xff1a;本人没有相关的工程应用经验&#xff0c;只是纯粹对相关算法感兴趣才写此博客。所以如果有…...

golang中byte和rune的区别?

golang中byte和rune的区别&#xff1f; rune和byte在go语言中都是字符类型&#xff0c;从源码来看他们都是别名形式 // byte is an alias for uint8 and is equivalent to uint8 in all ways. It is // used, by convention, to distinguish byte values from 8-bit unsigned…...

AI图像行为分析算法 opencv

AI图像行为分析算法通过pythonopencv深度学习框架对现场操作行为进行全程实时分析&#xff0c;AI图像行为分析算法通过人工智能视觉能够准确判断出现场人员的作业行为是否符合SOP流程规定&#xff0c;并对违规操作行为进行自动抓拍告警。OpenCV是一个基于Apache2.0许可&#xf…...

MATLAB制图代码【第二版】

MATLAB制图代码【第二版】 文档描述 Code describtion: This code is version 2 used for processing the data from the simulation and experiment. Time : 2023.9.3 Author: PEZHANG 这是在第一版基础上&#xff0c;迭代出的第二版MATLAB制图代码&#xff0c;第二版的特点是…...

5.0: Dubbo服务导出源码解析

#Dubbo# 文章内容 Dubbo服务导出基本原理分析Dubbo服务注册流程源码分析Dubbo服务暴露流程源码分析服务导出的入口方法为ServiceBean.export(),此方法会调用ServiceConfig.export()方法,进行真正的服务导出。 1. 服务导出大概原理 服务导出的入口方法为ServiceBean.export…...

python自动化测试-自动化基本技术原理

1 概述 在之前的文章里面提到过&#xff1a;做自动化的首要本领就是要会 透过现象看本质 &#xff0c;落实到实际的IT工作中就是 透过界面看数据。 掌握上面的这样的本领可不是容易的事情&#xff0c;必须要有扎实的计算机理论基础&#xff0c;才能看到深层次的本质东西。 …...

lodash 之 _.isEmpty

lodash.isEmpty() 是 Lodash 库中的一个函数&#xff0c;用于检查给定值是否为空。它可以用于判断对象、数组、字符串等不同类型的值是否为空。 const _ require(lodash);console.log(_.isEmpty(null)); // 输出: trueconsole.log(_.isEmpty(undefined)); // 输出: trueconso…...

layui数据表格实现表格中嵌套表格,并且可以折叠展开

效果&#xff1a; 思路&#xff1a; 1、最外层的表格先渲染&#xff0c;在done回调中向每个tr后面插入一个用来嵌套子级表格的tr。 tr的class和table的id需要用索引 i 关联 //向每一行tr后面追加显示子table的trlet trEles $(".layui-table-view[lay-idlist] tbody tr&…...

云端笔记系统-自动化测试

文章目录 1. 思维导图编写 Web 自动化测试用例2. 创建测试项目3. 根据思维导图设计【云端笔记】自动化测试用例3.1. 准备工具类3.2. 测试注册页面3.3. 测试登陆页面3.4. 测试添加博客页3.5. 测试我的博客列表页3.6. 测试修改博客页3.7. 测试博客列表页3.8. 测试博客详情页3.9. …...

将帅要避免五个方面的弱点:蛮干、怕死、好名、冲动、溺爱民众

将帅要避免五个方面的弱点&#xff1a;蛮干、怕死、好名、冲动、溺爱民众 【安志强趣讲《孙子兵法》第28讲】 【原文】 是故屈诸侯者以害&#xff0c;役诸侯者以业&#xff0c;趋诸侯者以利。 【注释】 趋&#xff1a;归附、依附。 【趣讲白话】 所以&#xff0c;用祸患威逼诸侯…...

2023开学礼《乡村振兴战略下传统村落文化旅游设计》许少辉八一新书成都理工大学图书馆

2023开学礼《乡村振兴战略下传统村落文化旅游设计》许少辉八一新书成都理工大学图书馆...

vue的第3篇 第一个vue程序

一 vue的mvvm实践者 1.1 介绍 Model&#xff1a;模型层&#xff0c; 在这里表示JavaScript对象 View&#xff1a;视图层&#xff0c; 在这里表示DOM(HTML操作的元素) ViewModel&#xff1a;连接视图和数据的中间件&#xff0c; Vue.js就是MVVM中的View Model层的实现者 在M…...

线性求逆元

先暴力求出 1 n ! \frac 1 {n!} n!1​往回推出 1 i ! \frac 1 {i!} i!1​ 1 i ( i − 1 ) ! i ! \Large \frac 1 i\frac{(i-1)!}{i!} i1​i!(i−1)!​...

第一章 USB应用笔记之USB初步了解

USB应用笔记之USB初步了解 文章目录 USB应用笔记之USB初步了解前言USB的优点&#xff1a;USB版本发展USB速度以及电气接口USB传输过程USB开发抓包工具&#xff1a;USB传输方式1.控制传输特点:2.中断传输的特点3. 批量传输的特点4.实时传输&#xff08;同步传输&#xff09;的特…...

小白入门python

建议用vscode进行代码学习 vscode下载地址:Download Visual Studio Code - Mac, Linux, Windows 左侧点击扩展安装python,右下角选择python版本&#xff0c;记得配置系统环境变量&#xff0c;python在系统(cmd)的版本由环境变量优先级决定,在编程软件中由自己选择解释器...

《Kubernetes部署篇:Ubuntu20.04基于containerd部署kubernetes1.24.17集群(多主多从)》

一、架构图 如下图所示: 二、环境信息 1、部署规划主机名K8S版本系统版本内核版本IP地址备注k8s-master-631.24.17Ubuntu 20.04.5 LTS5.15.0-69-generic192.168.1.63master节点 + etcd节点k8s-master-641.24.17Ubuntu 20.04.5 LTS5.15.0-69-generic192.168.1.64master节点 + …...

Adobe Illustrator 2023 for mac安装教程,可用。

Adobe Illustrator 是行业标准的矢量图形应用程序&#xff0c;可以为印刷、网络、视频和移动设备创建logos、图标、绘图、排版和插图。数以百万计的设计师和艺术家使用Illustrator CC创作&#xff0c;从网页图标和产品包装到书籍插图和广告牌。此版本是2023版本&#xff0c;适配…...