Java基础08-集合框架—单列集合

embedded/2024/10/20 20:30:43/

一、集合框架

在这里插入图片描述

在这里插入图片描述

二、集合框架—单列集合

1、Collection 集合体系

Collection是单列集合的祖宗,它规定的方法(功能)是全部单列集合都会继承的。

在这里插入图片描述

Collection集合特点:

  • List系列集合:添加的元素是有序、可重复、有索引。

    1. ArrayList、LinekdList :有序、可重复、有索引。
  • Set系列集合:添加的元素是无序、不重复、无索引。

    1. HashSet:无序、不重复、无索引;
    2. LinkedHashSet:有序、不重复、无索引。
    3. TreeSet:按照大小默认升序排序、不重复、无索引。
1.2 Collection 常用方法
方法名说明
public boolean add( E e )把给定的对象添加到当前集合中
public void clear()清空集合中所有的元素
public boolean remove( E e )把给定的对象在当前集合中删除
public boolean contains( Object obj )判断当前集合中是否包含给定的对象
public boolean isEmpty()判断当前集合是否为空
public int size()返回集合中元素的个数。
public Object[ ] toArray()把集合中的元素,存储到数组中
public void addAll( Collection c )向集合添加多个数据,可以合并2个集合数据
java">public class CollcetionDemo {public static void main(String[] args) {Collection<String> c1= new ArrayList<>();//add方法添加数据,添加成功返回truec1.add("data1");c1.add("data2");c1.add("data3");c1.add("data4");//remove 移出指定数据,返回boolean值System.out.println(c1.remove("data4")); //true//contains 查找集合里面是否有对应的数据,返回Boolean值System.out.println(c1.contains("data1"));  //true//size  返回集合长度System.out.println(c1.size());  // 3//isEmpty 判断集合是否为空,返回Boolean值System.out.println(c1.isEmpty());  //false//toArray 将集合转换为数组,默认返回 ObjectObject array=c1.toArray();String[] array2=c1.toArray(new String[c1.size()]);  //通过new 一个字符串数组转化为特定的数据类型System.out.println(Arrays.toString(array2));  //[data3, data2, data1]//clear 将集合清空c1.clear();System.out.println(c1); //[]//addAll 向集合添加多个数据,可以合并集合Collection<String> c2=new ArrayList<>();c2.add("data5");c2.add("data6");//c2向c1添加c2的所有数据c1.addAll(c2);System.out.println(c1);  //[data5, data6]}
}
1.2、Collection 的遍历方式
1.2.1 迭代器

定义:迭代器是用来遍历集合的专用方式(数组没有迭代器),在Java中迭代器的代表是Iterator

Collection集合获取迭代器的方法说明
iterator iterator返回集合中的迭代器对象,该迭代器对象默认指向当前集合的第一个元素
Iterator迭代器中的常用方法说明
boolean hasNext()询问当前位置是否有元素存在,存在返回true ,不存在返回false
E next ( )获取当前位置的元素,并同时将迭代器对象指向下一个元素处。
java">public class Test02 {public static void main(String[] args) {//创建一个Collection集合对象,并为其添加数据Collection<String> c1=new ArrayList<>();c1.add("data1");c1.add("data2");c1.add("data3");//通过集合对象,调用c1的迭代器方法Iterator<String> it=c1.iterator();//通过迭代器调用方法进行遍历,迭代器默认指向第一个数据,指向后就会自动指向下一个数据System.out.println(it.next());  //data1System.out.println("-------------------");//通过循环判断指向的数据是否为空,不为空就执行迭代while (it.hasNext()){String data=it.next();System.out.println(data);/*因为前面迭代了一次,所有,只输出两个数据:* data2* data3* */}}
}
1.2.2 增强 for

格式:for ( 元素数据类型 变量名 : 集合/数组 ) { }

快捷生成:集合名/数组名.for 再回车

增强for可以用来遍历集合或者数组。

增强for遍历集合,本质就是迭代器遍历集合的简化写法。

java">public class Test03 {public static void main(String[] args) {//创建一个整型数据类型的Collection集合,并添加数据Collection<Integer> c1=new ArrayList<>();c1.add(30);c1.add(100);c1.add(10);//通过增强for循环,将c1的元素,赋值到data变量中,再输出就可以遍历了for(Integer data:c1){System.out.println(data);/*3010010*/}}
}
1.2.3 Lambda 表达式

得益于JDK 8开始的新技术Lambda表达式,提供了一种更简单、更直接的方式来遍历集合。

方法名说明
default void forEach( Consumer<? super T> action )结合lambda遍历集合
java">public class Test03 {public static void main(String[] args) {//创建一个整型数据类型的Collection集合,并添加数据Collection<String> c1=new ArrayList<>();c1.add("data1");c1.add("data2");c1.add("data3");//没有缩写c1.forEach(new Consumer<String>() {@Overridepublic void accept(String s) {System.out.println(s);}});//缩写1c1.forEach((String s)->  {System.out.println(s);});//缩写2c1.forEach( s->  {System.out.println(s);});//缩写3c1.forEach( s->System.out.println(s));}
}

2、List系列集合

List集合因为支持索引,所以多了很多与索引相关的方法,当然,Collection的功 能List也都继承了。

注意:List为接口只能new它的实现类ArrayList或LinkedList,因为Collection是所有集合的父类,所有它的方法,所有集合的能用。

List系列集合特点:有序,可重复,有索引。

  • ArrayList: 有序,可重复,有索引。
  • LinkedList:有序,可重复,有索引。
  • 它们两个底层实现不同!适合的场景不同!
List集合方法说明
void add( int index, E elment )在此集合中的指定位置插入指定的元素
E remove ( ind index)删除指定索引处的元素,返回被删除的元素
E set ( int index , E element )修改指定索引处的元素,返回被修改的元素
E get (int index )返回指定索引
java">public class ListDemo {public static void main(String[] args) {List<String> list=new ArrayList<>();//添加数据list.add("小明");list.add("小车");list.add("猫猫");System.out.println(list); //[小明, 小车, 猫猫]//在指定位置插入数据list.add(1,"甜甜");System.out.println(list); //[小明, 甜甜, 小车, 猫猫]//删除指定索引数据list.remove(0);System.out.println(list);  //[甜甜, 小车, 猫猫]//修改指定下标数据list.set(1,"苦苦");System.out.println(list); //[甜甜, 苦苦, 猫猫]for (int i = 0; i < list.size(); i++) {System.out.print(list.get(i));  //不换行输出:甜甜苦苦猫猫}}
}
2.1 List 遍历方法

①for循环 ( 因为List集合有索引)
②迭代器
③增强for循环
④Lambda表达式

java">public class ListDemo {public static void main(String[] args) {List<String> list=new ArrayList<>();//添加数据list.add("小明");list.add("小车");list.add("猫猫");list.add("甜甜");System.out.print(list); //[小明, 小车, 猫猫, 甜甜]System.out.println();//迭代器遍历Iterator<String> it=list.iterator();//通过循环判断指向的数据是否为空,不为空就执行迭代while (it.hasNext()){System.out.print(it.next()); //小明小车猫猫甜甜}System.out.println();//for循环遍历for (int i = 0; i < list.size(); i++) {System.out.print(list.get(i));  //小明小车猫猫甜甜}System.out.println();//增强for循环遍历for (String data : list) {System.out.print(data);  //小明小车猫猫甜甜}System.out.println();//Lambda表达式遍历list.forEach(new Consumer<String>() {@Overridepublic void accept(String s) {System.out.print(s);  //小明小车猫猫甜甜}});//Lambda表达式遍历缩写list.forEach((String s)->  {System.out.println(s); 小明小车猫猫甜甜});}
}
2.2 ArrayList 集合的底层原理

ArrayList特点:查询快,增删慢。

①基于数组实现的。

②查询速度快 (注意:是根据索引查询数据快) :查询数据通过地址值和索引定位, 查询任意数据耗时相同。

③删除效率低:可能需要把后面很多的数据进行前移。添加效率极低:可能需要把后面很多的数据后移,再添加元素;或者也可能需要进行数组的扩容。

ArrayList底层原理:

①利用无参构造器创建的集合,会在底层创建一个默认长度为0的数组

②添加第一个元素时,底层会创建一个新的长度为10的数组

③存满时,会扩容1.5倍

④如果一次添加多个元素,1.5倍还放不下,则新创建数组的长度以实际为准

ArrayList使用场景:

数据量大且查询场景多的时候。

2.3 LinkedList 集合的底层原理
2.3.1 LinkList集合特点:

①基于双链表实现的。

链表:链表中的结点是独立的对象,在内存中是不连续的,每个结点包含数据值和下一个结点的地址。

单向链表和双向链表的区别就在于,单向链表只能从头节点开始找数据,双向链表可以从头节点或尾节点开始找数据。

链表特点:查询慢,无论查询哪个数据都要从头开始找;链表增删相对快。

②查询慢增删相对较快,但对首尾元素进行增删改查的速度是极快的。

LinkedList操作首位的方法说明
public void addFirst ( E e )在列表开头插入一个数据
public void addLast( E e )在列表结尾插入一个数据
public E getFirst()获取列表中第一个数据,并返回
public E getLast()获取列表中最后一个数据,并返回
public E removeFirst()删除列表第一个数据,并返回
public E removeLast()删除列表最后一个数据,并返回
2.3.2 LinkedList 应用场景:

①用来设计队列(队列特点:先进先出)

java">public class LinkedListDemo {public static void main(String[] args) {//创建一个队列(队列特点:先进先出)//如同排队,最先排的在前面,最后排的在最后面。LinkedList<String> linkedList  =new LinkedList<>();//添加数据,在尾部添加数据(入队列)linkedList.addLast("data01");linkedList.addLast("data02");linkedList.addLast("data03");linkedList.addLast("data04");System.out.println(linkedList);  //[data01, data02, data03, data04]//删除数据,并返回,只删除头部数据,(出队列)for (int i = 0; i < linkedList.size(); i++) {String data= linkedList.removeFirst();System.out.print(data+" "); //data01 data02 data03 data04i--;//防止移出后长度改变}}
}

②可以用来设计栈(栈特点:后进先出,先进后出)

拓展:可以通过 push方法入栈,pop方法出栈。

java">public class LinkedListDemo {public static void main(String[] args) {//创建一个栈(先进后出)//如同枪的弹夹,最前放的子弹在最后面,最后放的子弹在最前面。LinkedList<String> linkedList  =new LinkedList<>();//添加数据,在尾部添加数据(入栈)linkedList.addFirst("data01");linkedList.addFirst("data02");linkedList.addFirst("data03");linkedList.addFirst("data04");linkedList.push("data5");System.out.println(linkedList);  //[data04, data03, data02, data01]//删除数据,并返回,只删除尾部数据,(出栈)System.out.println(linkedList.removeFirst()); //data5System.out.println(linkedList.removeFirst());  //data4System.out.println(linkedList.removeFirst());  //data3System.out.println(linkedList.pop());          //data2System.out.println(linkedList.pop());          //data1}
}

3、set系列集合

在这里插入图片描述

Set系列集合特点:无序,添加数据的顺序和获取出的数据顺序不一致;不重复、无索引;

注意:Set要用到的常用方法,基本上就是Collection提供的!自己几乎没有额外新增一些常用功能!

实现类:

  • HashSet:无序、不重复、无索引。
  • LinkedHashSet:有序、不重复、无索引
  • TreeSet:排序、不重复、无索引。
java">public class HashSetDemo {public static void main(String[] args) {//创建一个Set的实现类HashSet,多态的运用Set<Integer> set1=new HashSet<>();set1.add(222);set1.add(666);set1.add(444);set1.add(111);set1.add(666);//里面的元素是无序的、不重复的、无索引的。System.out.println(set1);  //[666, 444, 222, 111]//创建一个LinkedHashSetSet<Integer> set2=new LinkedHashSet<>();set2.add(222);set2.add(666);set2.add(444);set2.add(111);set2.add(666);//里面的元素是 有序的、不重复的、无索引的。System.out.println(set2);  //[222, 666, 444, 111]//创建一个 TreeSetSet<Integer> set3=new TreeSet<>();set3.add(222);set3.add(666);set3.add(444);set3.add(111);set3.add(666);//里面的元素是 可排序的(默认升序)、不重复的、无索引的。System.out.println(set3);  //[111, 222, 444, 666]}
}
3.1 HashSet 集合的底层原理

HashSet 是基于哈希表实现。

哈希表是一种增删改查数据,性能都较好的数据结构。

注意:在正式了解HashSet集合的底层原理前,我们需要先搞清楚一个前置知识:哈希值!

HashSet集合默认不能对内容一样的两个不同对象去重复!比如内容一样的两个学生对象存入到HashSet集合中去, HashSet集合是不能去重复的!(因为:两个对象的hash值不一样,通过计算其放置的位置就不一样,所有无法去重)

结论:如果希望Set集合认为2个内容一样的对象是重复的必须重写对象的hashCode()和equals()方法。( 在实体类中 右击 -> equals and hashCode -> 一直next )

3.1.1 哈希值

定义:就是一个int类型的数值,Java中每个对象都有一个哈希值(对象的一个标志)。

对象哈希值的特点

Java中的所有对象,都可以调用Obejct类提供的hashCode方法,返回该对象自己的哈希值。

同一个对象多次调用hashCode()方法返回的哈希值是相同的。

不同的对象,它们的哈希值一般不相同,但也有可能会相同(哈希碰撞),因为int长度的限制。

java">//学生类
public class Students {private String name;private  int  age;public Students(){}public Students(String name, int age) {this.name = name;this.age = age;}
}//测试类
public class Test01 {public static void main(String[] args) {//创建两个不同的对象Students s1=new Students("小明",18);Students s2=new Students("小白",19);//获取对象的hash值(为整型数据)int hash01=s1.hashCode();int hash02=s2.hashCode();System.out.println(hash01);   //1967205423System.out.println(hash02);   //42121758System.out.println(s2.hashCode());  //42121758 :同一个对象的哈希值是不变的}
}
3.1.2 哈希表

JDK8之前,哈希表=数组+链表。

JDK8开始,哈希表=数组+链表+红黑树

在这里插入图片描述

在这里插入图片描述

3.2 LinkedHashSet 集合的底层原理

特点:有序、不重复、无索引。

依然是基于哈希表(数组、链表、红黑树)实现的。

实现有序的方法:它的每个元素都额外的多了一个双链表的机制记录它前后元素的位置。

由于元素要记录其上,一个节点、下一个节点、头节点、尾节点,所有LinkedHashSet比较占内存。

在这里插入图片描述

3.3 TreeSet 集合的底层原理

特点:不重复、无索引、可排序|(默认升序排序,按照元素的大小,由小到大排序)

底层是基于红黑树实现的排序(平衡二叉树)。

原理:将第一个元素作为平衡二叉树的根节点,下一个元素和根元素比较,小于就在根元素的左边,大于就在根节点的右边;以此类推,最小的就在左边了,最大的就在右边了;最后再从左往右依次遍历。

在这里插入图片描述

注意:

  1. 对于数值类型: Integer , Double,默认按照数值本身的大小进行升序排序。
  2. 对于字符串类型:默认按照首字符的编号升序排序。
  3. TreeSet集合存储自定义类型的对象时,必须指定排序规则。
3.3.1 TreeSet 自定义排序规则

TreeSet集合存储自定义类型的对象时,必须指定排序规则,支持如下两种方式来指定比较规则。

方式一:让自定义的类( 如学生类)实现Comparable接口,重写里面的compareTo方法来指定比较规则。

方式二:通过调用TreeSet集合有参数构造器,可以设置Comparator对象( 比较器对象,用于指定比较规则。

public TreeSet ( Comparator<? super E> comparator)

java">//学生类(通过实现 Comparable<Students> 接口来自定义规则)
public class Students implements Comparable<Students>{private String name;private  int  age;private  double height;public Students(){}public Students(String name, int age,double height) {this.name = name;this.age = age;this.height=height;}//重写compareTo方法实现安装规则排序@Overridepublic int compareTo(Students o) {//如果认为左边对象大于右边对象返回正整数//如果认为左边对象小于右边对象返回负整数//如果认为左边对象等于右边对象返回日//需求:按照年龄升序排序、return this.age-o.age;}//重写toString方法@Overridepublic String toString() {return "Students{" +"name='" + name + '\'' +", age=" + age +", height=" + height +'}';}public String getName() {return name;}public void setName(String name) {this.name = name;}public int getAge() {return age;}public void setAge(int age) {this.age = age;}public double getHeight() {return height;}public void setHeight(double height) {this.height = height;}
}//测试类
public class Test01 {public static void main(String[] args) {//创建两个不同的对象Students s1=new Students("小明",18,167.8);Students s2=new Students("小白",19,156.7);Students s3=new Students("小黑",20,170.5);Students s4=new Students("小甜",19,178.5);//通过TreeSet构造器传入omparator<Students>()对象来进行自定义排序//如果两种排序方式都有,默认是这种Set<Students> set= new TreeSet<>(new Comparator<Students>() {@Overridepublic int compare(Students o1, Students o2) {return Double.compare(o1.getHeight(),o2.getHeight());}});set.add(s1);set.add(s2);set.add(s3);set.add(s4);//方式一:按照年龄升序排序的,由于小白和小甜的年龄相同,所有只保留一个:// [Students{name='小明', age=18, height=167.8}, Students{name='小白', age=19, height=156.7}, Students{name='小黑', age=20, height=170.5}]//    System.out.println(set);//方式二://[Students{name='小白', age=19, height=156.7}, Students{name='小明', age=18, height=167.8}, Students{name='小黑', age=20, height=170.5}, Students{name='小甜', age=19, height=178.5}]System.out.println(set);}
}

4、不同集合所适合的场景、注意事项

4.1 不同集合所推荐所使用的场景

1、如果希望记住元素的添加顺序,需要存储重复的元素,又要频繁的根据索引查询数据?

用ArrayList集合(有序、可重复、有索引) ,底层基于数组的。 (常用)

2、如果希望记住元素的添加顺序,且增删首尾数据的情况较多?

用LinkedList集合 (有序、可重复、有索引),底层基于双链表实现的。

3.如果不在意元素顺序,也没有重复元素需要存储,只希望增删改查都快?

用HashSet集合 (无序,不重复,无索引),底层基于哈希表实现的。 (常用)

4.如果希望记住元素的添加顺序,也没有重复元素需要存储,且希望增删改查都快?

用LinkedHashSet集合 (有序,不重复,无索引),底层基于哈希表和双链表。

5.如果要对元素进行排序,也没有重复元素需要存储?且希望增删改查都快?

用TreeSet集合,基于红黑树实现。

4.2、注意事项(集合的并发修改异常问题)

使用迭代器遍历集合时,又同时在删除集合中的数据,程序就会出现并发修改异常的错误。

由于增强for循环遍历集合就是迭代器遍历集合的简化写法,因此,使用增强for循环遍历集合,又在同时删
N 除集合中的数据时,程序也会出现并发修改异常的错误。

java">public class Test02 {public static void main(String[] args) {List<String> list= new ArrayList<>();list.add("王二小");list.add("李玉刚");list.add("王小二");list.add("罗小黑");list.add("金角大王");list.add("银角大王");//通过迭代器来删除,名字中有带”王“字的Iterator<String> it=list.iterator();while (it.hasNext()){String name=it.next();if(name.contains("王")){//  list.remove(name);  //直接通过删除会报并非修改错误(java.util.ConcurrentModificationException)it.remove();  //迭代器,提供了remove()方法,会拿到当前遍历的数据进行删除}}System.out.println(list);  //[李玉刚, 罗小黑]//因为增强for循环,是基于 迭代器来弄的,但是又无法拿到迭代器的方法,所以,使用增强for循环进行删除数据时会报错//        for (String name : list) {
//            if(name.contains("王")){
//                list.remove(name);  //直接通过删除会报并非修改错误(java.util.ConcurrentModificationException)
//            }
//        }}
}

5、Colection的其他相关知识

5.1 可变参数

定义:就是一种特殊形参,定义在方法、构造器的形参列表里,格式是:数据类型…参数名称;

特点:可以不传数据给它;可以传一个或者同时传多个数据给它;也可以传一个数组给它。

好处:常常用来灵活的接收数据。

注意:

  1. 可变参数在方法内部就是一个数组。
  2. 一个形参列表中可变参数只能有一个
  3. 可变参 数必须放在形参列表的最后面
java">public class ChangeParameter {public static void main(String[] args) {//可以不传入参数也可以传入1个或多个test1();  //输出:0,[]test1(10);  //输出:1,[10]test1(1,2,3,4); //输出:4,[1, 2, 3, 4]test2(10,1,1,1); //输出:3,[1, 1, 1]}public  static void  test1(int...num){//实际上可变参数是亿数组形式存在的System.out.println(num.length);  //System.out.println(Arrays.toString(num));}//注意:可变参数只能有一个,并且必须在形参列表的最后。public static void test2(int age,int...num){System.out.println(num.length);  //System.out.println(Arrays.toString(num));}}
5.2、Collections

是一个用来操作集合的工具类

Collections提供的常用静态方法说明
public static boolean addAll (Collection <? super T> , c , T… elemnets)给集合批量添加元素
public static void shuffle ( List<?> list )打乱List集合中的元素顺序
public static void sort sort ( List list )对List集合中的元素进行升序排序
public static void sort( List list , Comparator<? super T> c )对List集合中元素,按照比较器对象指定的规则进行排序
java">public class CollectionsDemo {public static void main(String[] args) {//创建一个ArrayList对象List<String> names=new ArrayList<>();//以前添加数据,只能一个一个添加啊names.add("张三");//Collections.addAll,批量添加数据Collections.addAll(names,"李四","王二","麻子");System.out.println(names);  //[张三, 李四, 王二, 麻子]//Collection.shuffle:打乱List集合的元素Collections.shuffle(names);System.out.println(names);  //[麻子, 张三, 王二, 李四],每次运行都会打乱//Collections.sort对List集合进行升序排序(数值按大小排,字符按字母拼音排;当有对象需要排序时,可以用实现了Comparable接口或者比较器排序)List<String> list=new ArrayList<>();Collections.addAll(list,"b","e","t","a");Collections.sort(list);System.out.println(list); //[a, b, e, t]}
}
5.3 案例:斗地主

1、分析业务需求:

总共有54张牌
点数::“3”,“4”,“5”,“6”,“7”,“8”,“9”,“10”,“J”,“Q”,“K”,“A”,“2”

花色: “♠”, “🖤”,“♣”, “♦”

大小王:“👮‍♂️”,“🃏”

斗地主:发出51张牌,剩下3张做为底牌。

2、实现分析:

在启动游戏房间的时候,应该提前准备好54张牌。

接着,需要完成洗牌、发牌、对牌排序、看牌。

3、代码实现:

​ 实现效果图:

在这里插入图片描述

java">//测试类
public class GameDemo {public static void main(String[] args) {Room room=new Room();room.start();}
}
java">//卡牌类
public class Card {//牌的号码private String number;//牌的花色private String decor;//牌的大小,方便后面排序:1,2,3...private int  size;public Card() {}public Card(String number, String decor, int size) {this.number = number;this.decor = decor;this.size = size;}public String getNumber() {return number;}public void setNumber(String number) {this.number = number;}public String getDecor() {return decor;}public void setDecor(String decor) {this.decor = decor;}public int getSize() {return size;}public void setSize(int size) {this.size = size;}@Overridepublic String toString() {return decor+number;}
}
java">//房间类,用来创建卡牌,和洗牌、分牌、排排import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;//打牌房间,创建和保存一副新牌。
public class Room {//创建一个牌盒,用来新存牌List<Card> newCards=new ArrayList<>();//通过构造器来创建新牌public Room(){//牌号String[]  number={"3","4","5","6","7","8","9","10","J","Q","K","A","2"};//花色String[] decor={ "♠", "🖤","♣", "♦"};//小王、大王String[] kings={"🃏","👮‍"};//牌的大小int size=0;//除开大小王,每张牌有四个花色,遍历没张牌。for (String num : number) {//大小与花色无关,所以只在牌号这里++size++;for (String d : decor) {//创建一张牌Card card=new Card(num,d,size);//将创建的一张牌存到,newCards集合的牌盒中。newCards.add(card);}}//单独创建小王和大王牌(大小王没有牌号)Card minKing=new Card("",kings[0],++size);Card maxKing=new Card("",kings[1],++size);//将小王和大王,存到牌盒中Collections.addAll(newCards,minKing,maxKing);//查看新创建的一副牌(要重写牌的toString方法(Card类),只能看地址)System.out.println("新牌:"+newCards);}//创建一个游戏开始方法public void start(){//游戏开始,随机打乱牌。Collections.shuffle(newCards);System.out.println("打乱:"+newCards);distribute();}//分发牌,分发给3个不同用户,并留3张作为底牌public void distribute(){//创建3个List集合,当中3个用户,来获取牌List<Card>  user01=new ArrayList<>();List<Card>  user02=new ArrayList<>();List<Card>  user03=new ArrayList<>();//将打乱的牌进行分发,每轮只发一张牌(-3是留3张底牌)for (int i = 0; i < newCards.size()-3; i++) {//通过%3来判断把牌分发给哪个用户if(i%3==0){user01.add(newCards.get(i));}else if(i%3==1){user02.add(newCards.get(i));}else if(i%3==2){user03.add(newCards.get(i));}}//查看分发完牌后的3个用户的牌System.out.println("用户1:"+user01);System.out.println("用户2:"+user02);System.out.println("用户3:"+user03);//用户3要抓牌,将最后3张牌截取出来(返回结果还是List集合)List<Card> residue=newCards.subList(newCards.size()-3,newCards.size());//用户3要抓牌,user03= draw(user03,residue);System.out.println("用户3抓牌后:"+user03);piXu(user01);piXu(user02);piXu(user03);System.out.println("排序完user1:"+user01);System.out.println("排序完user1:"+user02);System.out.println("排序完user1:"+user03);}//抓牌,将最后三张牌分发给抓牌的用户,并返回。public List<Card> draw(List<Card> user,List<Card> residue){user.addAll(residue);return user;}//齐牌,将3用户的牌进行排序好public void piXu(List<Card> userCard){userCard.sort(new Comparator<Card>() {@Overridepublic int compare(Card o1, Card o2) {return o1.getSize()-o2.getSize();}});}
}

http://www.ppmy.cn/embedded/129076.html

相关文章

Javascript算法——双指针法移除元素、数组去重、比较含退格字符、有序数组平方

数组移除元素&#xff08;保证数组仍连续&#xff09; 暴力求解法&#xff08;两层for循环&#xff09;,length单词拼写错误❌二次嵌套for的length设置 /*** param {number[]} nums* param {number} val* return {number}*/ var removeElement function(nums, val) {let leng…

动态规划之打家劫舍

大纲 题目思路第一步&#xff1a;确定下标含义第二步&#xff1a;确定递推公式第二步&#xff1a;dp数组如何初始化第三步&#xff1a;确定遍历顺序第四步&#xff1a;举例推导dp数组 总结 最近有人询问我 LeetCode 「打家劫舍」系列问题&#xff08;英文版叫 House Robber&…

mysql多表关系与查询

一、多表关系 1.多表操作分类 1.1 多对一 关系举例&#xff1a; 多对一&#xff1a;多名学生在一个班级里 一对多主要是靠 “外键” 实现。在 “多” 的表中建立外键&#xff0c;指向 "一"的主键 一对多的关系在实际生产当中使用非常常见。 一对多的核心解决方案是…

使用React Router实现前端的权限访问控制

前段时间学习了React Router&#xff0c;发现没有Vue里面的路由功能强大&#xff0c;没有直接提供路由中间件&#xff0c;不能像Vue里面一样在路由配置上设置任意的额外属性&#xff0c;但是可以通过一些技巧来实现这些功能。 1、配置菜单 后台管理系统一般都会在左侧显示菜单…

SQL第19课——使用存储过程

介绍什么是存储过程&#xff1f;为什么要使用存储过程&#xff1f;如何使用存储过程&#xff1f;创建和使用存储过程的基本语法&#xff1f; 19.1 存储过程 到目前为止&#xff0c;使用的大多数SQL语句都是针对一个或多个表的单条语句。 对于一些复杂的操作需要多条语句才能…

超GPT3.5性能,无限长文本,超强RAG三件套,MiniCPM3-4B模型分享

MiniCPM3-4B是由面壁智能与清华大学自然语言处理实验室合作开发的一款高性能端侧AI模型&#xff0c;它是MiniCPM系列的第三代产品&#xff0c;具有4亿参数量。 MiniCPM3-4B模型在性能上超过了Phi-3.5-mini-Instruct和GPT-3.5-Turbo-0125&#xff0c;并且与多款70亿至90亿参数的…

爬虫逆向学习(十二):一个案例入门补环境

此分享只用于学习用途&#xff0c;不作商业用途&#xff0c;若有冒犯&#xff0c;请联系处理 反爬前置信息 站点&#xff1a;aHR0cDovLzEyMC4yMTEuMTExLjIwNjo4MDkwL3hqendkdC94anp3ZHQvcGFnZXMvaW5mby9wb2xpY3k 接口&#xff1a;/xjzwdt/rest/xmzInfoDeliveryRest/getInfoDe…

线程池原理(一)

一、常用线程池体系结构图如下&#xff1a; 由上边的体系图可以知道&#xff0c;要想了解线程池 ThreadPoolExecutor 的实现原理&#xff0c;则需要先 了解下 Executor、ExecutorService、AbstractExecutorService 的实现&#xff0c;下面就分别看下 这3个类的实现 二、Executo…