【数据结构与算法】ArrayList 和 顺序表

文章目录

  • 🌲List
  • 🌲1. 线性表
  • 🌲2. 顺序表
    • 🌿2.1 MyArrayList
      • 2.1.1 类中重写所有接口方法
      • 1.新增元素
      • 2.在pos位置新增元素(指定位置)
      • 3.判定是否包含了某个特定元素
      • 4.查找特定元素对应的位置
      • 5.获取pos下标的元素
      • 6.给pos位置的元素替换成value
      • 7.删除数据
      • 8.获取顺序表长度
      • 9.清空顺序表
      • 10.打印顺序表
      • 需要的自定义异常
  • 🌲3.ArrayList 简介
  • 🌲4. ArrayList 的使用
    • 🌿4.1 ArrayList 的构造
    • 🌿4.2 ArrayList常见操作
    • 🌿4.3 ArrayList的遍历
    • 🌿4.4 ArrayList的扩容机制(java8源码实现讲解)
  • 🌲5. ArrayList的具体使用
    • 🌿5.1 删除字符 (要求使用集合)
    • 🌿5.2 杨辉三角
    • 🌿5.3 扑克牌洗牌
  • 6.🌸ArrayList的问题

在正式学习顺序表前,先简单了解一下 List

🌲List

在这里插入图片描述
在这里插入图片描述

在这里插入图片描述
在这里插入图片描述

🌲1. 线性表

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

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

在这里插入图片描述

🌲2. 顺序表

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

顺序表底层是一个数组,为什么不直接操作数组就好了,还需要单独写个类?

在这里插入图片描述

这个数组里有几个有效数据?-----6个

在这里插入图片描述

在Java里数组没有元素默认为0,判断的时候遇到0就停止,然后总数就是元素个数,那如果这6个元素中加了一个0呢?还是6个元素,但是数组认为只有5个元素,这就是为什么我们需要顺序表

在使用ArrayList之前,我们自己实现一个顺序表,方便我们更加深入的理解顺序表,才能熟练使用它

🌿2.1 MyArrayList

public class MyArrayList implements IList {public int[] array;public int usedSize;//成员变量默认为0public static final int DEFAULT_CAPACITY = 10;public MyArrayList() {this.array = new int[DEFAULT_CAPACITY];}

成员变量包含数组,数组里的有效元素个数,数组长度(可以使用final修饰让数据不被改变)
###🌿 2.1.1 接口IList

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

注意:接口中的方法默认为public abstract 修饰

这些是我们要实现的所有方法,自己实现一遍,能更好的理解ArrayList

2.1.1 类中重写所有接口方法

1.新增元素

// 新增元素,默认在数组最后新增
public void add(int data) { //默认在尾部插入数据//判满if(isFull()){grow();//扩容}this.array[this.usedSize]=data;this.usedSize++;}public void grow(){this.array= Arrays.copyOf(this.array,2*this.array.length);}public boolean isFull(){return this.usedSize== array.length;}

默认在数组尾部新增

①需要判断数组是否是满的,满的就需要扩容,
②不满的话就进行元素插入,判断数组满不满状态的函数实现
③最后数组长度+1

2.在pos位置新增元素(指定位置)

public void add(int pos, int data) { //插入到指定位置//pos合法性try{checkPos(pos);if(isFull()){grow();//扩容}//挪动数据for (int i = usedSize-1; i >=pos ; i--) {array[i+1]=array[i];}array[pos]=data;this.usedSize++;}catch (PosIllegal e){System.out.println("插入元素pos位置不合法");e.printStackTrace();//提示异常位置}}private void checkPos(int pos) throws PosIllegal{if(pos < 0 || pos > usedSize) { //注意:usedSize能插入,只要前驱存在就可以插入throw new PosIllegal("Pos位置不合法!!");}}

①先判断pos位置合法性,既不能是负数,又必须要有前驱信息的支持
②判断数组元素是否满了,继续调用isFull()函数
③我们插入数据的时候,需要先把插入元素后面的元素都往后挪一位,挪数据实现从数组的最后一个元素开始往后挪,一次挪到当pos位置空出,没有元素的时候即可
④挪完数据之后,我们把pos位置赋值为data,并且把数组大小扩容一位,方便再进行新增元素

3.判定是否包含了某个特定元素

 public boolean contains(int toFind) {for (int i = 0; i <this.usedSize ; i++) {if(array[i]==toFind){return true;}}return false;}

4.查找特定元素对应的位置

// 查找某个元素对应的位置
public int indexOf(int toFind) {for (int i = 0; i < this.usedSize; i++) {if(this.elem[i] == toFind){return i;}}return -1;
}

5.获取pos下标的元素

private void checkPos2(int pos) throws PosIllegal{if(pos < 0 || pos >= usedSize) {throw new PosIllegal("Pos位置不合法!!");}}private void checkEmpty() {if(isEmpty()) {throw new EmptyException("顺序表为空!");}}public boolean isEmpty(){return  usedSize==0;}@Overridepublic int get(int pos) {try{checkEmpty();checkPos2(pos);return array[pos];}catch (PosIllegal e){System.out.println("插入位置pos不合法");e.printStackTrace();}catch (EmptyException e){System.out.println("顺序表位空");e.printStackTrace();}return -1;}

①先判断pos位置合法性
②判断数组是否为空(可有可无)

6.给pos位置的元素替换成value

①先要进行合法性判断再替换

 public void set(int pos, int value) { //更新   pos位置更新为valuetry{checkEmpty();checkPos2(pos); array[pos]=value;}catch (PosIllegal e){System.out.println("插入位置pos不合法");e.printStackTrace();}catch (EmptyException e){System.out.println("顺序表位空");e.printStackTrace();}}

7.删除数据

 public void remove(int toRemove) {try{checkEmpty();int pos=indexOf(toRemove);if (pos==-1)return ;for (int i = pos; i <this.usedSize-1 ; i++) {array[i]=array[i+1];}this.usedSize--;}catch (EmptyException e){e.printStackTrace();}}

①顺序表不为空
②顺序表当中有我们要删除的元素
③找到它的下标
④把i+1的值赋给i,i还要小于usedSize-1(只要涉及到删除数据,如果是引用数据类型,那么就要把elem[i] = null;否则就会发生内存泄漏)

8.获取顺序表长度

// 获取顺序表长度
public int size() {return this.usedSize;
}

9.清空顺序表

// 清空顺序表
public void clear() {//因为是基本类型,所以置为0即可this.usedSize = 0;/*当它是引用类型时for (int i = 0; i < this.usedSize; i++) {this.elem[i] = null;}this.usedSize = 0;*/
}

①基本类型置为0即可,若是引用类型则循环打印置为null,再置为0

注意:
此处可以把elem置为null可以吗?可以,但是很暴力,数组直接被回收了,顺序表只执行了一次就没了,再次使用的时候还需开辟新的数组,相当于我们每次使用的时候还需new一次,很麻烦也没必要

10.打印顺序表

public void display() {for (int i = 0; i < this.usedSize; i++) {System.out.print(array[i]+" ");}/*这里面所有都是 0for (int x : array) {System.out.print(x+" ");}*/}
}

需要的自定义异常

在这里面添加,获取pos下标不合法的时候我们也可以写我们需要的异常类来更好的实现我们需要的异常,实现异常的抛出是我们赋值命名的异常名:

public class MyArrayListEmptyException extends RuntimeException{public MyArrayListEmptyException(){}public MyArrayListEmptyException(String message){super(message);}
}
public class MyArraylistIndexOutofException extends RuntimeException{public MyArraylistIndexOutofException(){}public MyArraylistIndexOutofException(String message){super(message);}
}

好,自己实现一遍顺序表是不是思路清晰了很多,我们正式进入顺序表介绍

🌲3.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底层是一段连续的空间,并且可以动态扩容,是一个动态类型的顺序表

🌲4. ArrayList 的使用

🌿4.1 ArrayList 的构造

在这里插入图片描述
进入ArrayList的源码,我们来详细了解

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述
提问:都是空数组,那我们main函数中add的值都是存在哪里的?

答:add函数过程中会扩容1.5倍 下面我们讲到扩容机制再详细说

在这里插入图片描述
在这里插入图片描述

在这里插入图片描述

方法一ArrayList()不带参数的构造方法的使用:

ArrayList<Integer> arrayList = new ArrayList<>();
arrayList.add(1);//往数组最后的一个位置存元素
arrayList.add(2);
arrayList.add(3);
arrayList.add(4);
System.out.println(arrayList);//用字符串的形式打印出来所有的元素
System.out.println(arrayList.size());//获取当前有效数据的个数
System.out.println(arrayList.get(1));//获取指定下标的元素

方法二的使用:

ArrayList<Integer> arrayList2 = new ArrayList<>(arrayList);
arrayList2.add(99);
arrayList2.add(199);
System.out.println(arrayList2);

arrayList2承接了arrayList1的数据(使用其他的集合 来构造当前的List,底层源码实现是数组的拷贝)

方法三的使用:

ArrayList<Integer> arrayList3 = new ArrayList<>(15)

指定初始化数组容量大小

在源码的实现里:
①:第一次add的时候,我们底层的数组才变成了10,如果只是调用了不带参数的构造方法,默认还是0
②:grow函数就是扩容函数,扩容的方式是1.5倍的扩容

例如整体的举例使用:

public static void main(String[] args) {// ArrayList创建,推荐写法// 构造一个空的列表List<Integer> list1 = new ArrayList<>();// 构造一个具有10个容量的列表List<Integer> list2 = new ArrayList<>(10);list2.add(1);list2.add(2);list2.add(3);// list2.add("hello"); // 编译失败,List<Integer>已经限定了,list2中只能存储整形元素// list3构造好之后,与list中的元素一致ArrayList<Integer> list3 = new ArrayList<>(list2);// 避免省略类型,否则:任意类型的元素都可以存放,使用时将是一场灾难List list4 = new ArrayList();list4.add("111");list4.add(100);
}

🌿4.2 ArrayList常见操作

在这里插入图片描述

add方法

ArrayList<Integer> arrayList = new ArrayList<>();
arrayList.add(0,1);
arrayList.add(1,2);
arrayList.add(2,99);
System.out.println(arrayList);

需要注意的是:在我们实现元素插入赋值的时候,前驱必须存在

addAll方法:

ArrayList<Integer> arrayList2 = new ArrayList<>();
arrayList2.addAll(arrayList);
arrayList2.add(19);System.out.println(arrayList2);

在这里插入图片描述

remove方法:

public class Main{public static void main(String[] args) {MyArrayList array=new MyArrayList();ArrayList<Integer> list=new ArrayList<Integer>();list.add(0,1);list.add(1,2);list.add(2,3);list.add(3,4);list.add(4,5);ArrayList<Integer> list2=new ArrayList<Integer>();list2.addAll(list);list2.add(99999999);list2.remove(new Integer(5));System.out.println(list2);}
}

在这里插入图片描述
lastIndexOf方法:

int index = arrayList.lastIndexOf(new Integer(99));
System.out.println(index);

subList方法 和 set方法:

ArrayList<Integer> arrayList = new ArrayList<>();
arrayList.add(0,1);
arrayList.add(1,2);
arrayList.add(2,99);
arrayList.add(3,199);
arrayList.add(4,299);
System.out.println(arrayList);List<Integer> list = arrayList.subList(1,3);//区间左闭右开
System.out.println(list);

相当于字符串的截取,区间左闭右开
这里面我们如果把list里面的数值改变了,是否会影响原来的arraylist数组呢?-----会改变
在这里插入图片描述

🌿4.3 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) {  //也可以用int 这个过程相当于拆箱System.out.print(integer + " ");}System.out.println();Iterator<Integer> it = list.listIterator();while(it.hasNext()){System.out.print(it.next() + " ");}System.out.println();}

两种迭代器打印代码如下:

在这里插入图片描述
在这里插入图片描述

注意:

  1. ArrayList最常使用的遍历方式是:for循环+下标 以及 foreach
  2. 迭代器是设计模式的一种,后序容器接触多了在仔细学一学,讲一讲

感兴趣的同学可以在IDEA中点到源码,读源码学习

🌿4.4 ArrayList的扩容机制(java8源码实现讲解)

我们这里用的是 java8 源码,更好理解,java17 重写了,但是效果并不影响

ArrayList是一个动态类型的顺序表,即:在插入元素的过程中会自动扩容

Object[] elementData; // 存放元素的空间
private static final Object[] DEFAULTCAPACITY_EMPTY_ELEMENTDATA = {}; // 默认空间为0
private static final int DEFAULT_CAPACITY = 10; // 默认容量大小
public boolean add(E e) {ensureCapacityInternal(size + 1); // Increments modCount!!elementData[size++] = e;return true;
}
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++;// overflow-conscious codeif (minCapacity - elementData.length > 0)grow(minCapacity);
}
private static final int MAX_ARRAY_SIZE = Integer.MAX_VALUE - 8;
private void grow(int minCapacity) {// 获取旧空间大小int oldCapacity = elementData.length;// 预计按照1.5倍方式扩容int newCapacity = oldCapacity + (oldCapacity >> 1);// 如果用户需要扩容大小 超过 原空间1.5倍,按照用户所需大小扩容if (newCapacity - minCapacity < 0)newCapacity = minCapacity;// 如果需要扩容大小超过MAX_ARRAY_SIZE,重新计算容量大小if (newCapacity - MAX_ARRAY_SIZE > 0)newCapacity = hugeCapacity(minCapacity);// 调用copyOf扩容elementData = Arrays.copyOf(elementData, newCapacity);
}
private static int hugeCapacity(int minCapacity) {// 如果minCapacity小于0,抛出OutOfMemoryError异常if (minCapacity < 0)throw new OutOfMemoryError();return (minCapacity > MAX_ARRAY_SIZE) ? Integer.MAX_VALUE : MAX_ARRAY_SIZE;
}

总结:
检测是否真正需要扩容,如果是调用grow准备扩容
预估需要库容的大小
①初步预估按照1.5倍大小扩容
②如果用户所需大小超过预估1.5倍大小,则按照用户所需大小扩容
③真正扩容之前检测是否能扩容成功,防止太大导致扩容失败使用copyOf进行扩容
④.授予copeOf进行扩容

🌲5. ArrayList的具体使用

🌿5.1 删除字符 (要求使用集合)

在这里插入图片描述
在这里插入图片描述

🌿5.2 杨辉三角

杨辉三角

在这里插入图片描述
我们把图形抽象为一个直角三角形

在这里插入图片描述
要求的返回值是这样的–二维数组
在这里插入图片描述

在这里插入图片描述
ret是整个数组

public List<List<Integer>> generate(int numRows) {List<List<Integer>> ret=new ArrayList<>();//第一行List<Integer> list0=new ArrayList<>();list0.add(1);ret.add(list0);//从第2行开始求每个元素for (int i = 1; i <numRows ; i++) {List<Integer> curRow = new ArrayList<>();//每一行curRow.add(1);  //第一列//中间List<Integer> preRow = ret.get(i - 1);//获得上一行for (int j = 1; j < i; j++) {int val1 = preRow.get(j);int val2 = preRow.get(j - 1);curRow.add(val1 + val2);}//尾巴curRow.add(1);ret.add(curRow);}return ret;//返回目标数组}
}

🌿5.3 扑克牌洗牌

自己写一副扑克牌

①:完成刚买牌的顺序打印出来
②:我们再完成洗牌随机打乱顺序
③:三个人轮流每个人揭5张牌
④:输出最后剩余的牌

1.我们需要先单独创建一个Card类,定义花色和数字,添加构造方法以及getter和setter方法,重写ToString方法

class Card {private String suit;private int rank;public Card(String suit, int rank) {this.suit = suit;this.rank = rank;}public String getSuit() {return suit;}public void setSuit(String suit) {this.suit = suit;}public int getRank() {return rank;}public void setRank(int rank) {this.rank = rank;}@Overridepublic String toString() {return "[ " + suit+" "+rank+" ]";}
}

2.牌按照花色和顺序打印出来,再把花色和序号拼接在一起组成每个牌每个花色

public static final String[] suits = {"♥","♠","♣","♦"};public static List<Card> buyCard() {List<Card> desk = new ArrayList<>();for (int i = 0; i < 4; i++) {for (int j = 1; j <= 13 ; j++) {String suit = suits[i];Card card = new Card(suit,j);desk.add(card);}}return desk;
}

3.洗牌使用random类中的nextInt函数并且交换每个元素的下标,让它遍历的时候随机和其他元素下标交换,让下标随机数取元素长度里的任何一个下标,正向遍历也可以,反向遍历更好

public static void shuffle(List<Card> cardList) {for (int i = cardList.size()-1; i > 0 ; i--) {Random random = new Random();int index = random.nextInt(i);swap(cardList,i,index);}
}
private static void swap(List<Card> cardList,int i,int j) {Card tmp = cardList.get(i);cardList.set(i,cardList.get(j));cardList.set(j,tmp);
}

4.三个人每个人都轮流揭五张牌,最后揭的牌需要删除,方便后面我们打印剩余的牌

for (int i = 0; i < 5; i++) {for (int j = 0; j < 3; j++) {//每次揭牌都去获取 cardList的0下标的数据【删除】Card card = cardList.remove(0);List<Card> hand = hands.get(j);hand.add(i,card);//这里使用add 不能是set/*hands.get(j).add(card);*/}
}

5.当我们此时打印cardList就是剩余的牌了,然后把所有的代码执行结果打印出来

附上代码:

CardDemo

public class CardDemo {public static final String[] suits = {"♥","♠","♣","♦"};public List<Card> buyCard() {List<Card> cardList = new ArrayList<>();for (int i = 1; i <= 13; i++) {for (int j = 0; j < 4; j++) {int rank = i;String suit = suits[j];Card card = new Card(suit,rank);cardList.add(card);}}return cardList;}public void shuffle(List<Card> cardList) {Random random = new Random();for (int i = cardList.size()-1; i > 0 ; i--) {int index = random.nextInt(i);swap(cardList,i,index);}}private void swap(List<Card> cardList,int i,int j) {/*Card tmp =  cardList[i];cardList[i] = cardList[j];cardList[j] = tmp;*/Card tmp = cardList.get(i);cardList.set(i,cardList.get(j));cardList.set(j,tmp);}public List<List<Card>> play(List<Card> cardList) {List<Card> hand0 = new ArrayList<>();List<Card> hand1 = new ArrayList<>();List<Card> hand2 = new ArrayList<>();List<List<Card>> hand = new ArrayList<>();hand.add(hand0);hand.add(hand1);hand.add(hand2);for (int i = 0; i < 5; i++) {for (int j = 0; j < 3; j++) {Card card = cardList.remove(0);//怎么把对应的牌 放到对应的人的手里面hand.get(j).add(card);}}return hand;}
}

Card

public class Card {private String suit;private int rank;public Card(String suit, int rank) {this.suit = suit;this.rank = rank;}@Overridepublic String toString() {/*return "Card{" +"suit='" + suit + '\'' +", rank=" + rank +'}';*/return "{"+suit + rank +"} ";}
}

Main

public static void main(String[] args) {CardDemo cardDemo = new CardDemo();//1. 买52张牌List<Card> cardList = cardDemo.buyCard();System.out.println(cardList);//2. 洗牌cardDemo.shuffle(cardList);System.out.println(cardList);//3. 3个人 每个人 轮流揭牌5张List<List<Card>> ret = cardDemo.play(cardList);for (int i = 0; i < ret.size(); i++) {System.out.println("第"+(i+1)+"个人的牌:"+ret.get(i));}System.out.println("剩下的牌:");System.out.println(cardList);}

6.🌸ArrayList的问题

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

这些问题该如何解决呢?

使用链表就可以解决

下一篇文章揭晓链表的神奇应用

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

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

相关文章

OceanBase 推出单机版 ,为中小规模业务提供高性价比方案

近日&#xff0c;OceanBase正式推出了全新的单机版数据库。这款产品基于OceanBase自主研发的单机分布式一体化架构&#xff0c;具有精简的架构设计和出色的兼容性&#xff0c;能够为中小规模业务场景提供高性价比的数据库解决方案&#xff0c;充分满足客户在不同业务规模下的多…

如何在 Vue 3 中实现百度地图位置选择器组件

如何在 Vue 3 中实现百度地图位置选择器组件 前言 在开发前端应用时&#xff0c;地图选择器是一个非常常见的需求。尤其是在一些需要用户选择地址的场景&#xff0c;如电商平台、旅游网站、酒店预定等&#xff0c;百度地图组件能提供准确的地理位置服务。在本文中&#xff0c…

Python中如何用正则表达式精准匹配IP地址?

在网络编程和数据处理时&#xff0c;我们经常需要从文本中提取或验证IP地址。Python的正则表达式(re模块)是完成这个任务的利器。但你知道怎么写才能准确匹配各种合法的IP地址吗&#xff1f;今天我们就来详细探讨这个问题。 为什么需要IP正则表达式&#xff1f; 假设你正在分…

spring--声明式事务

声明式事务 1、回顾事务 要么都成功&#xff0c;要么都失败&#xff01; 事务在项目开发中&#xff0c;十分重要&#xff0c;涉及数据的一致性问题 确保完整性和一致性 事务ACID&#xff1a; 原子性&#xff1a;事务是原子性操作&#xff0c;由一系列动作组成&#xff0c;…

Kotlin 学习-集合

/*** kotlin 集合* List:是一个有序列表&#xff0c;可通过索引&#xff08;下标&#xff09;访问元素。元素可以在list中出现多次、元素可重复* Set:是元素唯一的集合。一般来说 set中的元素顺序并不重要、无序集合* Map:&#xff08;字典&#xff09;是一组键值对。键是唯一的…

WPF 五子棋项目文档

WPF 五子棋项目文档 1. 项目概述 本项目是一个使用 Windows Presentation Foundation (WPF) 技术栈和 C# 语言实现的桌面版五子棋&#xff08;Gomoku&#xff09;游戏。它遵循 MVVM&#xff08;Model-View-ViewModel&#xff09;设计模式&#xff0c;旨在提供一个结构清晰、可…

计算机操作系统——死锁(详细解释和处理死锁)

系列文章目录 计算机操作系统-计算机系统中的死锁 文章目录 系列文章目录前言一、资源问题&#xff1a; 计算机系统当中的死锁&#xff1a; 二、死锁的定义、必要条件和处理方法&#xff1a; 1.死锁的定义&#xff1a;2.产生死锁的必要条件&#xff1a;3.处理死锁的方法&#…

Springboot项目正常启动,访问资源却出现404错误如何解决?

我在自己的springboot项目中的启动类上同时使用了SprinBootApplication和ComponentScan注解, 虽然项目能够正常启动,但是访问资源后,返回404错误,随后在启动类中输出bean,发现controller创建失败: 而后我将ComponentScan去掉后资源就能访问到了. 原因 SprinBootApplication本身…

第十五届蓝桥杯C/C++B组省赛真题讲解(分享去年比赛的一些真实感受)

试题A——握手问题 一、解题思路 直接用高中学的排列组合思路 二、代码示例 #include<bits/stdc.h> using namespace std; int fun(int n) {int sum0;for(int i0;i<n;i){for(int ji1;j<n;j)sum; } return sum; } int main() {cout<<fun(50)-fun(7); }三、…

动态规划(6)——01背包问题

欢迎来到博主的专栏&#xff1a;算法解析 博主ID&#xff1a;代码小号 文章目录 牛客网——【模板】01背包题目解析题目1算法原理题目1题解代码。问题2算法原理问题2题解代码01背包问题的滚动数组优化 牛客网——【模板】01背包 题目解析 关于I/O相关的东西博主就不多赘述了&a…

TQTT_KU5P开发板教程---实现流水灯

文档实现功能介绍 本文档是学习本开发板的基础&#xff0c;通过设置计数器使led0到led7依次闪烁&#xff0c;让用户初步认识vivado基本的开发流程以及熟悉项目的创建。本开发板的所有教程所使用的软件都是vivado2024.1版本的。可以根据网上的教程下载与安装。 硬件资源 此次教程…

Spring 中的 @Cacheable 缓存注解

1 什么是缓存 第一个问题&#xff0c;首先要搞明白什么是缓存&#xff0c;缓存的意义是什么。 对于普通业务&#xff0c;如果要查询一个数据&#xff0c;一般直接select数据库进行查找。但是在高流量的情况下&#xff0c;直接查找数据库就会成为性能的瓶颈。因为数据库查找的…

SEER: Self-Aligned Evidence Extraction for Retrieval-AugmentedGeneration

一、动机 如何从检索到的段落中提取证据&#xff0c;以降低计算成本并提升最终的RAG性能&#xff0c;然而这一问题仍然具有挑战性。 现有方法 严重依赖于基于启发式的增强&#xff0c;面临以下几个问题&#xff1a; &#xff08;1&#xff09;由于手工制作的上下文过滤&…

毫米波测试套装速递!高效赋能5G/6G、新材料及智能超表面(RIS)研发

德思特&#xff08;Tesight&#xff09;作为全球领先的测试测量解决方案提供商&#xff0c;始终致力于为前沿技术研发提供高精度、高效率的测试工具。 针对毫米波技术在高频通信、智能超表面&#xff08;RIS&#xff09;、新材料等领域的快速应用需求&#xff0c;我们推出毫米…

三维激光测量助力企业检测效率提升3倍

智能制造与数字化浪潮席卷下&#xff0c;三维扫描技术已成为工业检测领域不可或缺的工具。面对传统检测手段的精度瓶颈与效率局限&#xff0c;三维扫描仪&#xff0c;以毫米级精度、非接触式测量与超高速扫描三大核心优势&#xff0c;为汽车制造、航空航天、消费电子等行业的品…

SQL:Normalization(范式化)

目录 Normalization&#xff08;范式化&#xff09; 为什么需要 Normalization&#xff1f; &#x1f9e9; 表格分析&#xff1a; 第一范式&#xff08;1NF&#xff09; 什么是第一范式&#xff08;First Normal Form&#xff09;&#xff1f; 第二范式&#xff08;2NF&am…

#MES系统运维问题分析思路

一套适用于90% MES运维现场问题的排查分析思维模型&#xff0c;叫做&#xff1a; &#x1f50d; MES系统问题分析七步法&#xff08;现场实战适用&#xff09; ✅ 第一步&#xff1a;明确问题现象&#xff08;What&#xff09; 问题要说清楚&#xff0c;“不能操作”这种模糊描…

达梦数据库-学习-18-ODBC数据源配置(Linux)

一、环境信息 名称值CPU12th Gen Intel(R) Core(TM) i7-12700H操作系统CentOS Linux release 7.9.2009 (Core)内存4G逻辑核数2DM版本1 DM Database Server 64 V8 2 DB Version: 0x7000c 3 03134284194-20240703-234060-20108 4 Msg Versi…

js 效果展示 拿去练手

自学完整功能&#xff0c;拿去练手。 鼠标移动放大 通过网盘分享的文件&#xff1a;图片放大 链接: https://pan.baidu.com/s/1w8SjtKi4kUNDnZtRDfYMeQ?pwd95p6 提取码: 95p6 通过网盘分享的文件&#xff1a;图片动画效果 链接: https://pan.baidu.com/s/1Pjphx-Cc4HQQNNujr…

使用 TFIDF+分类器 范式进行企业级文本分类(二)

1.开场白 上一期讲了 TF-IDF 的底层原理&#xff0c;简单讲了一下它可以将文本转为向量形式&#xff0c;并搭配相应分类器做文本分类&#xff0c;且即便如今的企业实践中也十分常见。详情请见我的上一篇文章 从One-Hot到TF-IDF&#xff08;点我跳转&#xff09; 光说不练假把…