数据结构 - 2(顺序表10000字详解)

一:List

1.1 什么是List

在集合框架中,List是一个接口,继承自Collection。
在这里插入图片描述
Collection也是一个接口,该接口中规范了后序容器中常用的一些方法,具体如下所示:
在这里插入图片描述

Iterable也是一个接口,Iterable接口表示实现该接口的类是可以逐个元素进行遍历的,

站在数据结构的角度来看,List就是一个线性表,即n个具有相同类型元素的有限序列,在该序列上可以执行增删改查以及变量等操作。

List中常用的方法如下所示:

方法解释
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

1.2 List的使用

注意:List是个接口,并不能直接用来实例化。

如果要使用,必须去实例化List的实现类。在集合框架中,ArrayList和LinkedList都实现了List接口。

使用实例如下:

List<String> arrayList = new ArrayList<>(); // 使用ArrayList实现
List<Integer> linkedList = new LinkedList<>(); // 使用LinkedList实现//添加元素
arrayList.add("Apple");
arrayList.add("Banana");
arrayList.add("Orange");//添加元素
linkedList.add(10);
linkedList.add(20);
linkedList.add(30);

我们通过向上转型,分别调用了ArrayList和LinkedList中的add重写方法,这两个方法在ArrayList和LinkedList中都有自己的实现方式

二: ArrayList的使用

2.1 什么是线性表

线性表(linear list)是n个具有相同特性的数据元素的有限序列。 线性表是一种在实际中广泛使用的数据结构,常见的线性表:顺序表、链表、栈、队列…

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

比如说:
在这里插入图片描述
顺序表是用一段物理地址连续的存储单元依次存储数据元素的线性结构,一般情况下采用数组存储。在数组上完成数据的增删查改。

2.2ArrayList简介

在这里插入图片描述
【说明】

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

2.3 ArrayList的使用

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

ArrayList(Collection<? extends E> c) 是一个构造函数,它接受一个实现了 Collection 接口的对象 c。这个构造函数会将 c 中的所有元素添加到新创建的 ArrayList 中。

通常情况下,ArrayList 是按照元素的添加顺序来存储的,而 ArrayList(Collection<? extends E> c) 可以方便地将另一个集合的元素全部添加到当前的 ArrayList 中。

例如,假设有一个 List 对象 list,可以使用如下代码创建一个新的 ArrayList,并将 list 中的所有元素添加到新的 ArrayList 中:

ArrayList<String> arrayList = new ArrayList<>(list);

在上述代码中,ArrayList<String> arrayList 是一个新创建的 ArrayList 对象,它包含了 list 中的所有元素。

注意:ArrayList(Collection<? extends E> c) 的泛型参数要与 ArrayList 的泛型参数类型一致或构成子类父类的关系,即它们需要是相同类型或者是其子类型。

2.4 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

使用实例:

public static void main(String[] args) {List<String> list = new ArrayList<>();list.add("JavaSE");list.add("JavaWeb");list.add("JavaEE");list.add("JVM");list.add("测试课程");System.out.println(list);// 获取list中有效元素个数System.out.println(list.size());// 获取和设置index位置上的元素,注意index必须介于[0, size)间System.out.println(list.get(1));list.set(1, "JavaWEB");System.out.println(list.get(1));// 在list的index位置插入指定元素,index及后续的元素统一往后搬移一个位置list.add(1, "Java数据结构");System.out.println(list);// 删除指定元素,找到了就删除,该元素之后的元素统一往前搬移一个位置list.remove("JVM");System.out.println(list);// 删除list中index位置上的元素,注意index不要超过list中有效元素个数,否则会抛出下标越界异常list.remove(list.size()-1);System.out.println(list);// 检测list中是否包含指定元素,包含返回true,否则返回falseif(list.contains("测试课程")){list.add("测试课程");}// 查找指定元素第一次出现的位置:indexOf从前往后找,lastIndexOf从后往前找list.add("JavaSE");System.out.println(list.indexOf("JavaSE"));System.out.println(list.lastIndexOf("JavaSE"));// 使用list中[0, 4)之间的元素构成一个新的SubList返回,但是和ArrayList共用一个elementData数组List<String> ret = list.subList(0, 4);System.out.println(ret);list.clear();System.out.println(list.size());
}

2.5 ArrayList的遍历

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

public static void main(String[] args) {List<Integer> list = new ArrayList<>();list.add(1);list.add(2);list.add(3);list.add(4);list.add(5);// 使用下标+for遍历for (int i = 0; i < list.size(); i++) {System.out.print(list.get(i) + " ");}System.out.println();// 借助foreach遍历for (Integer integer : list) {System.out.print(integer + " ");}System.out.println();//迭代器遍历Iterator<Integer> it = list.listIterator();while(it.hasNext()){System.out.print(it.next() + " ");}System.out.println();
}

下面我们讲解一下使用迭代器遍历的方式

迭代器是用于遍历集合(如列表、数组等)中的元素的一种接口。它提供了一种统一的方式来访问和处理集合中的元素,而不需要暴露集合的内部实现细节。

迭代器有以下几个主要的方法:

  • hasNext(): 检查迭代器中是否还有下一个元素,如果有则返回 true,否则返回 false
  • next(): 返回迭代器的下一个元素,并将迭代器的位置向后移动。
  • remove(): 从迭代器指向的集合中移除迭代器返回的最后一个元素。

使用迭代器,你可以按顺序访问集合中的每一个元素,而不需要知道集合的内部结构或者索引。这样可以提供更灵活和独立的遍历方式。

在这段代码中,Iterator<Integer> it = list.listIterator(); 这行代码的作用是创建一个整数类型的迭代器 it,并将其初始化为列表的迭代器。这样我们就可以使用 it 来遍历并访问列表中的元素。

while(it.hasNext()){System.out.print(it.next() + " ");}

在上述示例中,it.hasNext() 检查迭代器中是否还有下一个元素,如果有,则执行循环内部代码。it.next() 返回迭代器的下一个元素,并将迭代器的位置向后移动。你可以在循环内部处理当前元素,例如打印出来。

迭代器是一次性的,即只能从头到尾进行一次遍历。如果需要重新遍历集合,你需要重新创建一个新的迭代器。

注意:

  1. ArrayList最长使用的遍历方式是:for循环+下标 以及 foreach
  2. 迭代器是设计模式的一种,后序容器接触多了再给大家铺垫

2.6ArrayList的扩容机制

ArrayList是一个动态类型的顺序表,当我们向 Java 的 ArrayList 中添加元素时,ArrayList 会自动扩容,以容纳更多的元素。ArrayList 的扩容机制如下:

  1. 初始容量:每个 ArrayList 对象都有一个初始容量。在创建 ArrayList 对象时,如果没有指定初始容量大小,则默认为10。这意味着初始时 ArrayList 可以容纳最多10个元素。

  2. 操作次数:当我们向 ArrayList 中添加新元素时,ArrayList 会根据当前存储的元素数量和内部数组的长度进行判断。每次添加元素的操作都会增加 ArrayList 的操作次数。

  3. 扩容策略:当 ArrayList 的操作次数达到其内部数组长度时,就会触发扩容操作。ArrayList 的默认扩容因子是1.5倍,即每次扩容后的容量为当前容量的1.5倍。

  4. 数组拷贝:扩容时,ArrayList 会创建一个新的数组,将原有元素拷贝到新数组中。这个过程涉及到数组的创建和数据的拷贝,所以在扩容操作时可能会对性能产生一定的影响。

需要注意的是,扩容是一个相对耗时的操作,因为它涉及到数据的拷贝和存储空间的重新分配。因此,在知道需要存储大量元素的情况下,为 ArrayList 显式指定一个初始容量,可以减少扩容操作的次数,提高性能。

ArrayList 的扩容策略是在底层数组容量不足时,将当前容量乘以一个扩容因子来进行扩容。默认情况下,ArrayList 的扩容因子是 1.5 倍。

注意:ArrayList 的扩容因子是可调的,可以通过构造函数来指定。我们可以使用 ArrayList(int initialCapacity, float loadFactor) 构造函数来同时指定初始容量和扩容因子。

三:模拟实现一个ArrayList

3.1方法框架

public class SeqList {private int[] array;private int size;// 默认构造方法SeqList(){  }// 将顺序表的底层容量设置为initcapacitySeqList(int initcapacity){  }// 新增元素,默认在数组最后新增public void add(int data) { }// 在 pos 位置新增元素public void add(int pos, int data) { }// 判定是否包含某个元素public boolean contains(int toFind) { return true; }// 查找某个元素对应的位置public int indexOf(int toFind) { return -1; }// 获取 pos 位置的元素public int get(int pos) { return -1; }// 给 pos 位置的元素设为 valuepublic void set(int pos, int value) {  }//删除第一次出现的关键字keypublic void remove(int toRemove) {  }// 获取顺序表长度public int size() { return 0; }// 清空顺序表public void clear() {  }// 打印顺序表,注意:该方法并不是顺序表中的方法,为了方便看测试结果给出的public void display() {  }
}

3.2 模拟实现ArrayList

 class MyArrayList {private int[] array;private int size;// 默认构造方法public MyArrayList() {// 初始化底层数组,初始容量为10array = new int[10];// 初始大小为0size = 0;}// 将顺序表的底层容量设置为initCapacitypublic MyArrayList(int initCapacity) {if (initCapacity < 0) {throw new IllegalArgumentException("容量不能小于0");}// 初始化底层数组,初始容量为initCapacityarray = new int[initCapacity];// 初始大小为0size = 0;}// 在数组最后新增元素public void add(int data) {// 如果数组已满,则扩容if (size == array.length) {resize();}// 在数组末尾新增元素array[size] = data;// 更新大小size++;}// 在指定位置新增元素public void add(int pos, int data) {// 检查位置是否合法if (pos < 0 || pos > size) {throw new IndexOutOfBoundsException("索引超出范围");}// 如果数组已满,则扩容if (size == array.length) {resize();}// 将指定位置及其后面的元素后移一位for (int i = size - 1; i >= pos; i--) {array[i + 1] = array[i];}// 在指定位置插入元素array[pos] = data;// 更新大小size++;}// 判定是否包含某个元素public boolean contains(int toFind) {// 遍历数组查找元素for (int i = 0; i < size; i++) {if (array[i] == toFind) {return true;}}return false;}// 查找某个元素对应的位置public int indexOf(int toFind) {// 遍历数组查找元素for (int i = 0; i < size; i++) {if (array[i] == toFind) {return i;}}// 未找到元素,返回-1return -1;}// 获取指定位置的元素public int get(int pos) {// 检查位置是否合法if (pos < 0 || pos >= size) {throw new IndexOutOfBoundsException("索引超出范围");}// 返回指定位置的元素return array[pos];}// 设置指定位置的元素public void set(int pos, int value) {// 检查位置是否合法if (pos < 0 || pos >= size) {throw new IndexOutOfBoundsException("索引超出范围");}// 更新指定位置的元素array[pos] = value;}// 删除第一次出现的指定元素public void remove(int toRemove) {// 遍历数组查找要删除的元素for (int i = 0; i < size; i++) {if (array[i] == toRemove) {// 将要删除元素后面的元素前移一位for (int j = i + 1; j < size; j++) {array[j - 1] = array[j];}// 更新大小size--;return;}}}// 获取顺序表长度public int size() {return size;}// 清空顺序表public void clear() {// 将数组清空for (int i = 0; i < size; i++) {array[i] = 0;}// 大小置为0size = 0;}// 扩容数组private void resize() {// 创建新的数组,长度为当前容量的两倍int[] newArray = new int[array.length * 2];// 将原数组中的元素复制到新数组中for (int i = 0; i < size; i++) {newArray[i] = array[i];}// 更新底层数组array = newArray;}// 打印顺序表public void display() {// 遍历数组打印元素for (int i = 0; i < size; i++) {System.out.print(array[i] + " ");}System.out.println();}
}

这是一个自定义的MyArrayList类,模拟实现了一个动态数组。以下是每个功能的解释:

  • 构造方法:使用默认构造方法创建一个初始容量为10的数组,并将大小初始化为0。使用带有参数的构造方法可以设置初始容量。
  • add方法:在数组最后新增元素,如果数组已满,则扩容。
  • add方法(重载):在指定位置新增元素,如果数组已满,则扩容。为了将指定位置的元素后移,我们需要从后往前遍历数组。
  • contains方法:遍历数组查找是否包含某个元素,如果找到则返回true,否则返回false
  • indexOf方法:遍历数组查找某个元素对应的位置,如果找到则返回元素的索引,否则返回-1。
  • get方法:获取指定位置的元素,如果位置合法则返回元素,否则抛出IndexOutOfBoundsException异常。
  • set方法:设置指定位置的元素,如果位置合法则更新元素值,否则抛出IndexOutOfBoundsException异常。
  • remove方法:删除第一次出现的指定元素,将后面的元素前移一位,并更新大小。
  • size方法:获取顺序表的长度,即元素的个数。
  • clear方法:清空顺序表,将数组

3.3 测试功能

接着我们再写一个测试类,用于测试功能:

public class Main {public static void main(String[] args) {MyArrayList list = new MyArrayList();// 测试默认构造方法System.out.println("测试默认构造方法:");System.out.println("顺序表是否为空:" + (list.size() == 0));System.out.println("顺序表的大小:" + list.size());list.display();// 测试 add 方法System.out.println("\n测试 add 方法:");list.add(1);list.add(2);list.add(3);list.display();// 测试 add(pos, data) 方法System.out.println("\n测试 add(pos, data) 方法:");list.add(1, 5);list.display();// 测试 contains 方法System.out.println("\n测试 contains 方法:");System.out.println("顺序表中是否包含元素 2:" + list.contains(2));System.out.println("顺序表中是否包含元素 4:" + list.contains(4));// 测试 indexOf 方法System.out.println("\n测试 indexOf 方法:");System.out.println("元素 2 在顺序表中的位置:" + list.indexOf(2));System.out.println("元素 4 在顺序表中的位置:" + list.indexOf(4));// 测试 get 方法System.out.println("\n测试 get 方法:");System.out.println("位置 2 上的元素:" + list.get(2));// 测试 set 方法System.out.println("\n测试 set 方法:");list.set(1, 4);list.display();// 测试 remove 方法System.out.println("\n测试 remove 方法:");list.remove(2);list.display();// 测试 size 方法System.out.println("\n测试 size 方法:");System.out.println("顺序表的大小:" + list.size());// 测试 clear 方法System.out.println("\n测试 clear 方法:");list.clear();list.display();System.out.println("顺序表是否为空:" + (list.size() == 0));}
}
  • 运行结果如下:

    测试默认构造方法: 顺序表是否为空:true 顺序表的大小:0测试 add 方法: 1 2 3 测试 add(pos, data) 方法: 1 5 2 3 测试 contains 方法: 顺序表中是否包含元素 2:true 顺序表中是否包含元素 4:false测试 indexOf 方法: 元素 2 在顺序表中的位置:2 元素 4 在顺序表中的位置:-1测试 get 方法: 位置 2 上的元素:2测试 set 方法: 1 4 2 3 测试 remove 方法: 1 4 3 测试 size 方法: 顺序表的大小:3测试 clear 方法:顺序表是否为空:true
    

可见输出都符合我们的预期,说明我们模拟实现的ArrayList在功能上是完好的,并且没有什么缺陷。

四:ArrayList的问题及思考

  1. ArrayList底层使用连续的空间,任意位置插入或删除元素时,需要将该位置后序元素整体往前或者往后搬移,故时间复杂度为O(N)
  2. 增容需要申请新空间,拷贝数据,释放旧空间。会有不小的消耗。
  3. 增容一般是呈2倍的增长,势必会有一定的空间浪费。例如当前容量为100,满了以后增容到200,我们再继
    续插入了5个数据,后面没有数据插入了,那么就浪费了95个数据空间。

所以应该使用 ArrayList 的场景包括:

  1. 需要频繁进行随机访问的场景。

不应该使用 ArrayList 的场景包括:

  1. 需要频繁进行插入和删除操作,并对性能要求较高的场景。

  2. 列表中的元素数量比较少,可能造成内存浪费的场景。

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

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

相关文章

【Vue面试题二十三】、你了解vue的diff算法吗?说说看

文章底部有个人公众号&#xff1a;热爱技术的小郑。主要分享开发知识、学习资料、毕业设计指导等。有兴趣的可以关注一下。为何分享&#xff1f; 踩过的坑没必要让别人在再踩&#xff0c;自己复盘也能加深记忆。利己利人、所谓双赢。 面试官&#xff1a;你了解vue的diff算法吗&…

【Vue面试题二十一】、Vue中的过滤器了解吗?过滤器的应用场景有哪些?

文章底部有个人公众号&#xff1a;热爱技术的小郑。主要分享开发知识、学习资料、毕业设计指导等。有兴趣的可以关注一下。为何分享&#xff1f; 踩过的坑没必要让别人在再踩&#xff0c;自己复盘也能加深记忆。利己利人、所谓双赢。 面试官&#xff1a;Vue中的过滤器了解吗&am…

Java字符串String

【char】类型代表字符类型&#xff0c;【String】类型代表字符串类型&#xff1b; 1.String类 1.1 声明字符串 在Java中字符串必须包含在一对双引号&#xff08;“ "&#xff09;之内。双引号包含的都是字符串。 声明字符串语法&#xff1a; String str; //声明字符串语…

排序算法-选择排序法(SelectionSort)

排序算法-选择排序法&#xff08;SelectionSort&#xff09; 1、说明 选择排序法也是枚举法的应用&#xff0c;就是反复从未排序的数列中取出最小的元素&#xff0c;加入另一个数列中&#xff0c;最后的结果即为已排序的数列。选择排序法可使用两种方式排序&#xff0c;即在所…

苍穹外卖(七) Spring Task 完成订单状态定时处理

Spring Task 完成订单状态定时处理, 如处理支付超时订单 Spring Task介绍 Spring Task 是Spring框架提供的任务调度工具&#xff0c;可以按照约定的时间自动执行某个代码逻辑。 应用场景: 信用卡每月还款提醒 火车票售票系统处理未支付订单 入职纪念日为用户发送通知 点外…

操作系统学习笔记4-死锁问题

文章目录 1、死锁逻辑图2、死锁三胞胎3、死锁的原因及必要条件4、死锁处理策略之死锁预防5、死锁处理策略之死锁避免&#xff08;银行家算法&#xff09;6、死锁处理策略之死锁检测与解除 1、死锁逻辑图 2、死锁三胞胎 3、死锁的原因及必要条件 4、死锁处理策略之死锁预防 5、死…

python openai宠物名字生成器

文章目录 OpenAICompletion宠物名字生成器提示词工程 prompt enginering 构建应用程序结果展示 OpenAI OpenAI 已经训练了非常擅长理解和生成文本的领先的语言模型。我们的 API 提供对这些模型的访问&#xff0c;可用于处理几乎任何涉及”语言处理“的任务。 Completion 补全…

18 | 生产环境多数据源的处理方法有哪些

工作中我们时常会遇到跨数据库操作的情况&#xff0c;这时候就需要配置多数据源&#xff0c;那么如何配置呢&#xff1f;常用的方式及其背后的原理支撑是什么呢&#xff1f;我们下面来了解一下。 首先看看两种常见的配置方式&#xff0c;分别为通过多个 Configuration 文件、利…

【完美世界】云曦篇开播时间定档,推迟两周,石昊新形态帅翻,怒斩战王

Hello,小伙伴们&#xff0c;我是小郑继续为大家深度解析国漫资讯。 完美世界动画更新最新资讯&#xff0c;石昊在血色平原与云曦重逢并英雄救美。 官方公布了云曦特别篇的先导预告&#xff0c;播出时间推迟了两周。 石昊在特别篇中出现了新形态&#xff0c;以雷帝甲胄为主&…

Leetcode—88.合并两个有序数组【简单】

2023每日刷题&#xff08;一&#xff09; Leetcode—88.合并两个有序数组 题解 因为这两个数组已经排好序&#xff0c;我们可以把两个指针分别放在两个数组的末尾&#xff0c;即 nums1 的m − 1 位和 nums2 的 n − 1 位。每次将较大的那个数字复制到 nums1 的后边&#xff0…

Kafka SASL认证授权(六)全方位性能测试

Kafka SASL认证授权(六)全方位性能测试。 官网地址:https://kafka.apache.org/ 一、场景 线上已经有kafka集群,服务运行稳定。但是因为产品升级,需要对kakfa做安全测试,也就是权限验证。 但是增加权限验证,会不会对性能有影响呢?影响大吗?不知道呀! 因此,本文就此…

【Hyper-V】Windows的Hyper-V管理器创建的虚拟机上怎么复制粘贴文件

在hyper-V 管理器中创建的虚拟机里面&#xff0c;发现它是不能直接复制粘贴文件的&#xff0c;那只能粘贴纯文本内容&#xff0c;也就是模拟输入内容&#xff0c;这是虚拟系统是被隔离的&#xff0c;也带来不便之处&#xff0c;要怎么解决这个限制呢。 例如&#xff0c;打开一…

基于静电放电优化的BP神经网络(分类应用) - 附代码

基于静电放电优化的BP神经网络&#xff08;分类应用&#xff09; - 附代码 文章目录 基于静电放电优化的BP神经网络&#xff08;分类应用&#xff09; - 附代码1.鸢尾花iris数据介绍2.数据集整理3.静电放电优化BP神经网络3.1 BP神经网络参数设置3.2 静电放电算法应用 4.测试结果…

电动力学专题研讨:运动电荷之间的相互作用是否满足牛顿第三定律?

电动力学专题研讨&#xff1a;运动电荷之间的相互作用是否满足牛顿第三定律&#xff1f;​​​​​​​ 两个稳恒电流元之间的相互作用不一定服从牛顿第三定律常见的解释是&#xff1a;稳恒电流元是不能孤立存在的&#xff0c;因此不能得出结论 符号约定 两个运动点电荷之间的力…

文心一言 VS 讯飞星火 VS chatgpt (113)-- 算法导论10.2 5题

五、用go语言&#xff0c;使用单向循环链表实现字典操作 INSERT、DELETE 和 SEARCH&#xff0c;并给出所写过程的运行时间。 文心一言&#xff1a; 在Go语言中&#xff0c;我们首先需要定义一个Node结构体来表示单向循环链表的节点&#xff0c;然后再定义一个LinkedList结构体…

Redis 分布式锁 @Klock 注解详解及使用教程

文章目录 一、作用二、参数三、锁的流程四、SpringBoot 集成1. pom 依赖2. yaml 配置3. 使用方式 五、变量级锁和方法级锁六、常见应用场景1. 页面重复提交2. 定时任务3. 核心业务 七、锁的粒度与锁的时间 一、作用 注解 klock 是基于 Redis 的分布式锁&#xff0c;作用在分布…

CCF CSP认证 历年题目自练Day29

题目一 试题编号&#xff1a; 202112-1 试题名称&#xff1a; 序列查询 时间限制&#xff1a; 300ms 内存限制&#xff1a; 512.0MB 样例1输入 3 10 2 5 8 样例1输出 15 样例2输入 9 10 1 2 3 4 5 6 7 8 9 样例2输出 45 题目分析&#xff08;个人理解&#xff09; 还是…

Chrome Extensions v3 迁移清单

一、前置问题 1.1为什么需要迁移 v3&#xff1f; Chrome 计划完全停止 v2 版本维护&#xff0c;后续 v2 版本将无法上架谷歌插件商店&#xff0c;除此之外&#xff0c;未来新版本 Chrome 对于 v2 版本插件的限制会越来越大&#xff0c;比如安全性限制 iframe 嵌套只能通过沙盒…

云原生Kubernetes:Rancher管理k8s集群

目录 一、理论 1.Rancher 2.Rancher 安装及配置 二、实验 1.Rancher 安装及配置 三、问题 1. Rancher 部署监控系统报错 四、总结 一、理论 1.Rancher (1) 概念 Rancher 简介 Rancher 是一个开源的企业级多集群 Kubernetes 管理平台&#xff0c;实现了 Kubernetes …