集合、Collection、Set、List、Map接口和数据结构


一、集合

1.1 概念

集合:集合是java中提供的一种容器,可以用来存储多个数据,并且可以存储任意类型的数据!
容量可以随着存储的数据增大而修改

集合和数组的区别:

  • 数组的长度是固定的。集合的长度是可变的。
  • 数组中存储的是同一类型的元素,可以存储基本数据类型值。集合存储的都是对象。而且对象的类型可以不一致。在开发中一般当对象多的时候,使用集合进行存储。

1.2 集合体系

在这里插入图片描述

1.3 Collection接口

Collection:是所有单列集合类的根接口,用于存储一系列符合某种规则的元素。

集合按存储结构分为:

  • 单列集合java.util.Collection
  • 双列集合java.util.Map

两个子接口:

  • java.util.List
    List的特点是元素有序、元素可重复。
    List接口的主要实现类:
    • java.util.ArrayList
    • java.util.LinkedList
  • java.util.Set
    set集合中的元素不可重复、没有索引
    Set接口的主要实现类有:
    • java.util.HashSet
    • java.util.LinkedHashSet

1.4 Collection常用方法

方法名说明
public boolean add(E e)把给定的对象添加到当前集合中 。
public boolean remove(E e)把给定的对象在当前集合中删除。
public boolean contains(E e)判断当前集合中是否包含给定的对象。
public boolean isEmpty()判断当前集合是否为空。
public int size()返回集合中元素的个数。
public Object[] toArray()把集合中的元素,存储到数组中。
public void clear()清空集合中所有的元素。

代码演示

		//使用多态创建实现类类对象
		Collection<String> c=new ArrayList<>();
		c.add("张三");//添加方法
		c.add("李四");
		Object[] array = c.toArray();//将集合转换为数组
		for (int i = 0; i < array.length; i++) {
			System.out.println(array[i]);
		}
		c.remove("李四");//删除方法
		System.out.println(c.contains("张三"));//包含方法
		c.clear();//将所有存储数据删除
		System.out.println(c);
		System.out.println(c.size());//输出存储数据个数
		System.out.println(c.isEmpty());//判断是否为空集合

1.5 Iterator迭代器

collection中提供的用于迭代数据的方法,通过该方法可以返回当前集合的迭代器对象,通过迭代器对象提供的方法可以获取迭代集合中的数据

public Iterator iterator(): 获取集合对应的迭代器,用来遍历集合中的元素的。
  • Iterator接口的常用方法
方法名说明
public E next()返回迭代的下一个元素。
public boolean hasNext()如果仍有元素可以迭代,则返回 true。
		//使用多态创建实现类类对象
		Collection<String> c=new ArrayList<>();
		c.add("张三"); 
		c.add("李四");
		c.add("王五");
		//通过iterator方法获取对应集合的迭代器对象
		Iterator<String> i=c.iterator();
		while(i.hasNext()){//当前集合中是否还有下一个元素
			System.out.println(i.next());//获取当前元素
		}
  • 原理:

    通过方法判断是否还存在数据,存在调用方法获取

1.6 增强for循环

增强for循环 (也称for each循环)是JDK1.5以后出来的一个高级for循环,专门用来遍历数组和集合的。它的内部原理其实是个Iterator迭代器,所以在遍历的过程中,不能对集合中的元素进行增删操作。

1.6.1 格式

for(元素的数据类型  变量 : Collection集合or数组){ 
  	//写操作代码
}

1.6.2 原理

在遍历集合时,依次取出集合数据,赋值给中间变量,在循环体中对变量进行操作,再次执行时将数据进行覆盖

	//使用多态创建实现类类对象
	Collection<String> c=new ArrayList<>();
	c.add("张三"); 
	c.add("田七");
	c.add("周八");
	//通过iterator方法获取对应集合的迭代器对象
	Iterator<String> i=c.iterator();
	while(i.hasNext()){//当前集合中是否还有下一个元素
		System.out.println(i.next());//获取当前元素并指向下一个
	}
	//for(集合中存储数据的类型 变量名:集合 ){}
	for (String s : c) {
		System.out.println(s);
	}
	//先取出张三存储在s中循环使用s,之后取出李四赋值s继续使用
	//每次循环 会依次取出数据进行变量的赋值
	//变量的值每次循环都会重新赋值

面试题


for循环与增强for循环的区别

1、语法不同:

  • for循环语法中书写初始值、判断条件、迭代语句
  • 增强for循环中书写保存每次取出数据的变量声明以及遍历的数据

2、执行流程不同

  • for循环按照初始值、判断条件、迭代语句、循环体语句、判断语句 …执行
  • 增强for循环依次取出遍历容器中的数据赋值给临时变量之后使用

3、功能不同

  • for循环进行容器操作时,使用的是容器提供的方式进行获取并且可以进行修改
  • 增强for循环每次使用临时变量保存,不会修改容器中的数据

4、使用场景不同

  • for循环可以在执行时根据条件进行终止与操作
  • 增强for循环只能从头到尾遍历所有数据

二、List接口

2.1 概念

java.util.List接口继承自Collection接口,是单列集合的一个重要分支,习惯性地会将实现了List接口的对象称为List集合。在List集合中允许出现重复的元素,所有的元素是以一种线性方式进行存储的,在程序中可以通过索引来访问集合中的指定元素。另外,List集合还有一个特点就是元素有序,即元素的存入顺序和取出顺序一致。

2.2 特点

1、数据有序->存入位置与取出顺序相同
2、拥有索引->可以通过索引精确获取对应数据
3、数据重复->不同索引存储的数据可以相同

2.3 List集合常用方法

List作为Collection集合的子接口,不但继承了Collection接口中的全部方法,而且还增加了一些根据元素索引来操作集合的特有方法。

方法名说明
public void add(int index, E element)将指定的元素,添加到该集合中的指定位置上。
public E get(int index)返回集合中指定位置的元素·。
public E remove(int index)移除列表中指定位置的元素, 返回的是被移除的元素。
public E set(int index, E element)用指定元素替换集合中指定位置的元素,返回值的更新前的元素。

2.4 List接口的实现类

2.4.1 ArrayList

java.util.ArrayList集合数据存储的结构是数组结构。元素增删慢,查找快,由于日常开发中使用最多的功能为查询数据、遍历数据,所以ArrayList是最常用的集合。

2.4.1.1 常用方法
方法名说明
public void add(int index, E element)将指定的元素,添加到该集合中的指定位置上。
public E get(int index)返回集合中指定位置的元素·。
public E remove(int index)移除列表中指定位置的元素, 返回的是被移除的元素。
public E set(int index, E element)用指定元素替换集合中指定位置的元素,返回值的更新前的元素。
public boolean add(E e)将指定的元素添加到此列表的尾部
2.4.1.2 示例
		ArrayList<String> list=new ArrayList<>();
		list.add("张三");
		//add()方法将指定元素添加至集合末尾
		//list集合运允许重复添加相同的数据
		list.add("李四");
		//add(int,obj)方法将指定元素插入指定索引位置
		//原数据依次向后移动
		list.add(1,"王五");
		
		//get(int)方法获取指定索引位置数据
		System.out.println(list.get(2));
		
		//remove(int)方法 删除指定索引的数据 并返回删除的数据
		String remove = list.remove(2);
		
		//set(int,obj)方法 使用新的数据替换指定索引数据
		list.set(1, "王二麻子");
		
		//ArrayList重写了toString将数据以[数据1,数据2]字符串的形式返回
		System.out.println(list.toString());
2.4.1.3 原理

在这里插入图片描述

import java.util.Arrays;
public class MyArrayList {
	//ArrayList底层使用数组 
	//所有数据存储在对应数组中
	//设置默认长度10
	private String [] values=new String[2];
	
	//实际存储数据个数
	private int size=0;
	
	
	//get(int)方法
	public String get(int index){
		return values[index];
	}
	
	//size()方法
	public int size(){
		return size;
	}
	
	//add(String)方法
	public void add(String str){
		values[size++]=str;
		//添加后进行判断
		//如果添加后数组满了创建新的数组进行存储
		if(size==values.length){
			//将旧数组的数据赋值到新数组
			values = Arrays.copyOf(values, 2*size);
		}
	}
	public void add(int index,String str){
		System.arraycopy(values, index, values, index+1, size-index);
		values[index]=str;
		size++;
		if(size==values.length){
			//将旧数组的数据赋值到新数组
			values = Arrays.copyOf(values, 2*size);
		}
	}
	@Override
	public String toString() {
		StringBuffer sb=new StringBuffer("[");
		for (int i = 0; i < size; i++) {
			sb.append(values[i]);
			if(i!=size-1){
				sb.append(",");
			}
		}
		sb.append("]");
		return sb.toString();
	}
}

2.4.2 LinkedList

java.util.LinkedList集合数据存储的结构是双向链表结构。方便元素添加、删除的集合,查找修改慢。

2.4.2.1 常用方法

由于其特殊的存储结构。所以额外提供了对起始位置数据的操作方法

方法名说明
public void addFirst(E e)将指定元素插入此列表的开头。
public void addLast(E e)将指定元素添加到此列表的结尾。
public E getFirst()返回此列表的第一个元素。
public E getLast()返回此列表的最后一个元素。
public E removeFirst()移除并返回此列表的第一个元素。
public E removeLast()移除并返回此列表的最后一个元素。
public E pop()从此列表所表示的堆栈处弹出一个元素。
public void push(E e)将元素推入此列表所表示的堆栈。
public boolean isEmpty()如果列表不包含元素,则返回true。
2.4.2.2 示例
		LinkedList<String> list=new LinkedList<>();
		
		list.add("a");
		list.add("b");
		list.add("c");
		
		//list.add(0, "new");
		//对首位添加
		list.addFirst("first");
		list.addLast("last");

		//在使用上除了对首位末位操作外与ArrayList没有区别
		//但是LinkedList存储数据的结构为双向链表
		String pop = list.pop();
		System.out.println(pop);
		System.out.println(list);
2.4.2.3 原理

在这里插入图片描述

public class MyLinkedList {
	
	private int size=0;//集合中数据存储数据的个数
	
	private Node first;//首位数据块
	private Node last;//末位数据块

	public int size(){
		return size;
	}
	
	public void add(String str){
		//使用添加的数据创建一个节点对象
		if(size==0){
			//如果当前添加的是第一个
			Node n=new Node(null, str,null);
			//如果是第一个 那么当前保存的首末位应都为当前新创建的对象
			first=n;
			last=n;
		}else {
			//将原本的最后一块变为当前块的前一块
			Node n=new Node(last,str,null);
			//将当前块地址告诉前一块
			last.next=n;
			//将新添加的块设置为最后一块
			last=n;
		}
		size++;
	}
	public String get(int index){
		if(index>=size){
			return null;
		}else{
			Node n=first;
			for (int i = 0; i < index; i++) {
				n=n.next;
			}
			return n.value;
		}
	}
	public Node getFirst() {
		return first;
	}
	public Node getLast() {
		return last;
	}
 
	//创建内部类 保存每一块的数据
    private class Node{
    	//每一块数据只保存
    	//上一块的地址
        Node prev;
        //下一块的地址
        Node next;
        //当前块保存的数据
        String value;

        public Node(Node prev, String value, Node next) {
            this.value = value;
            this.next = next;
            this.prev = prev;
        }

		@Override
		public String toString() {
			return "Node [value=" + value + "]";
		}
    }
}

面试题


1、ArrayListLinkedList的区别

  • ArrayList 底层使用数组形式对数据进行存储
    • 查询修改快: 数组可以直接通过索引获取对应位置数据
    • 添加删除慢: 在对首位或中间数据进行添加与删除操作时,需要将之后的数据向后或向前移动,随着数据的增大移动的次数也会增大,导致执行的效率降低
  • LinkedList 底层使用双向链表形式对数据进行存储
    • 查询修改慢: 底层使用双向链表形式对数据进行存储,每一块只保存当前数据以及前后块地址,在进行查找时,如果查找的是非首末位块,需要依次向后查找
    • 添加删除快: 链表每块保存数据添加与删除时只影响前后块位置的修改

2、在实际开发过程中经常使用ArrayList进行数据的存储

  • 1、在数据量一定的情况下对ArrayList首位添加删除效率仍然比LinkedList对末位前一位的查找效率高
  • 2、在实际开发中添加数据一般都是直接添加至末位,更多的时候是对数据的查找与修改

三、Set接口

3.1 概念

java.util.Set接口和java.util.List接口一样,同样继承自Collection接口,它与Collection接口中的方法基本一致,并没有对Collection接口进行功能上的扩充,只是比Collection接口更加严格了。与List接口不同的是,Set接口中元素无序,并且都会以某种规则保证存入的元素不出现重复。

Set集合有多个子类,这里我们介绍其中的java.util.HashSetjava.util.LinkedHashSet这两个集合。

3.2 特点

  • Set集合中的元素无序、不可重复
  • Set集合没有索引

3.3 Set接口的实现类

3.3.1 HashSet

3.3.1.1 概念

java.util.HashSetSet接口的一个实现类,它所存储的元素是不可重复的,并且元素都是无序的(即存取顺序不一致)。java.util.HashSet底层的实现其实是一个java.util.HashMap支持,由于我们暂时还未学习,先做了解。

HashSet是根据对象的哈希值来确定元素在集合中的存储位置,因此具有良好的存取和查找性能。保证元素唯一性的方式依赖于:hashCodeequals方法。

3.3.1.2 HashSet集合的特点
  • HashSet集合中的元素不可重复
  • HashSet集合没有索引
  • HashSet集合是无序的(存储元素的顺序与取出元素顺序可能不一致)
		HashSet<Integer> set=new HashSet<>();
		set.add(2);
		set.add(3);
		set.add(5);
		set.add(1);
		set.add(4);
		set.add(4);
		System.out.println(set);//[1,2,3,4,5]
3.3.1.3 原理

JDK的版本不同,HashSet集合的数据结构有所不同:

  • JDK8之前:数组+链表
  • JDK8之后:数组+链表+红黑树(当链表长度超过阈值(8)时,将链表转换为红黑树)

以上数据结构我们称之为是哈希表

在这里插入图片描述

3.3.2 LinkedHashSet

3.3.2.1 概念

在HashSet下面有一个子类java.util.LinkedHashSet,它是链表和哈希表组合的一个数据存储结构。

3.3.2.2 特点
  • LinkedHashSet集合中的元素不可重复
  • LinkedHashSet集合没有索引
  • LinkedHashSet集合是有序的(存储元素的顺序与取出元素顺序一致)
3.3.2.3 示例
		LinkedHashSet<Integer> set=new LinkedHashSet<>();
		set.add(5);
		set.add(3);
		set.add(4);
		set.add(1);
		set.add(2);
		set.add(2);
		//LinkedHashSet底层是链表+hash表
		//添加数据就是创建新的链表块加入链表
		//因为链表每一块只保存关联信息,所以在遍历时必须依次执行
		//执行的顺序就是添加的顺序从而导致有序(存入顺序与取出顺序相同)
		System.out.println(set);

四、Map接口

4.1 概念

java.util.Map接口用于存储双列数据结构,现实生活中,我们常会看到这样的一种集合:IP地址与主机名,身份证号与个人,系统用户名与系统用户对象等,这种一一对应的关系,就叫做映射。

Map集合: 以Key-Value键值对的形式进行数据存储的双列集合

4.2 Map与Collection集合区别

  • Collection集合

    单列集合,一次只能添加一个元素
    有的是有索引,有的没有索引
    有的集合可以存储重复的元素,有的则不可以
    有的元素是无序的,有的是有序的
    
  • Map集合

    Map集合是双列集合,由Key和Value组成
    Key是不允许重复的,Value是允许重复
    Key允许存null值的,但是只能存储唯一的一个
    时set集合底层的实现原理
    

4.3 Map集合中常用的子类

4.3.1 HashMap

存储数据采用的哈希表结构,元素的存取顺序不能保证一致。由于要保证键的唯一、不重复,需要重写键的hashCode()方法、equals()方法。

4.3.2 LinkedHashMap

4.3.2.1 概念

HashMap下有个子类LinkedHashMap,存储数据采用的哈希表结构+链表结构。通过链表结构可以保证元素的存取顺序一致;通过哈希表结构可以保证的键的唯一、不重复,需要重写键的hashCode()方法、equals()方法。

4.3.2.2 特点
  • 有序的,而且key不允许重复
  • 数据结构: 哈希表 + 链表

4.4 Map接口中常用的方法

方法名说明
public V put(K key, V value)把指定的键与指定的值添加到Map集合中。
public V remove(Object key)把指定的键 所对应的键值对元素 在Map集合中删除,返回被删除元素的值。
public V get(Object key)根据指定的键,在Map集合中获取对应的值。
boolean containsKey(Object key)判断集合中是否包含指定的键。
public Set keySet()获取Map集合中所有的键,存储到Set集合中。
public Set<Map.Entry<K,V>> entrySet()获取到Map集合中所有的键值对对象的集合(Set集合)。
		HashMap<Integer, String> map=new HashMap<>();
		map.put(3, "王五");
		map.put(1, "张三");
		map.put(2, "李四");
		map.put(3, "王五1");
		//put方法同时添加k-v键值对数据
		//在进行添加时首先获取key的hash值进行判断
		//是否存在,如果不存在则直接添加 
		//存在则将value
		String put = map.put(4, "赵六");
		System.out.println(put);
		String put1 = map.put(4, "赵六1");
		System.out.println(put1);
		//put方法会返回与value类型相同的数据
		//如果在添加时,key是新添加的会返回null
		//如果添加的key以存在则会将数覆盖,将被覆盖的数据返回
		
		
		//删除指定Key的键值对  并返回删除的value
		String remove = map.remove(4);
		System.out.println("remove:"+remove);
		//如果删除的key不存在 返回null
		String remove1 = map.remove(4);
		System.out.println("remove1:"+remove1);
		
		//获取指定key对应的value值
		System.out.println("get:"+map.get(2));
		//如果不存在对应的key返回null
		System.out.println("get1:"+map.get(6));
		//是否存在指定key 
		System.out.println("contains:"+map.containsKey(2));
		
		System.out.println(map);

4.5 map遍历

4.5.1 keySet

  1. 获取Map中所有的键,由于键是唯一的,所以返回一个Set集合存储所有的键。方法提示:keyset()
  2. 遍历键的Set集合,得到每一个键。
  3. 根据键,获取键所对应的值。方法提示:get(K key)
		HashMap<String, String> map=new HashMap<>();
		map.put("小鱼儿", "花无缺");
		map.put("曹博文", "黄超");
		map.put("海绵宝宝", "派大星");
		map.put("喜羊羊", "灰太狼");
//		1. 获取Map中所有的键,由于键是唯一的,所以返回一个Set集合存储所有的键。方法提示:keySet()
		Set<String> keySet = map.keySet();
//		2. 遍历键的Set集合,得到每一个键。
		for (String string : keySet) {
//		3. 根据键,获取键所对应的值。方法提示:get(K key)
			System.out.println(string+"<=>"+map.get(string));
		}

4.5.2 entrySet

Map中存放的是两种对象,一种称为key(键),一种称为value(值),它们在在Map中是一一对应关系,这一对对象又称做Map中的一个Entry(项)Entry将键值对的对应关系封装成了对象。即键值对对象,这样我们在遍历Map集合时,就可以从每一个键值对(Entry)对象中获取对应的键与对应的值。

  • 获取Entry

Map集合中通过entrySet() 方法获取Entry对象

public Set<Map.Entry<K,V>> entrySet(): 获取到Map集合中所有的键值对对象的集合(Set集合)
  • Entry对象中的常用方法

既然Entry表示了一对键和值,那么也同样提供了获取对应键和对应值得方法

方法名说明
public K getKey()获取Entry对象中的键。
public V getValue()获取Entry对象中的值。
  • Entry图解
    在这里插入图片描述
  1. 获取Map集合中,所有的键值对(Entry)对象,以Set集合形式返回。方法提示:entrySet()
  2. 遍历包含键值对(Entry)对象的Set集合,得到每一个键值对(Entry)对象。
  3. 通过键值对(Entry)对象,获取Entry对象中的键与值。 方法提示:getkey() getValue()
		HashMap<String, String> map=new HashMap<>();
		map.put("小鱼儿", "花无缺");
		map.put("曹博文", "黄超");
		map.put("海绵宝宝", "派大星");
		map.put("喜羊羊", "灰太狼");
//		1.  获取Map集合中,所有的键值对(Entry)对象,以Set集合形式返回。方法提示:entrySet()
		Set<Entry<String,String>> entrySet = map.entrySet();
//		2.  遍历包含键值对(Entry)对象的Set集合,得到每一个键值对(Entry)对象。
		for(Entry<String,String> e:entrySet){
//		3.  通过键值对(Entry)对象,获取Entry对象中的键与值。  方法提示:getkey() getValue()    
			System.out.println(e.getKey()+"<=>"+e.getValue());
		}

面试题


1、List集合与Set集合的区别

  • List接口,有序可重复
    常用实现类ArrayList、LinkedList,额外实现了通过索引操作的方法
  • Set接口,无序不可重复
    常用实现类HashSet,底层使用的map的方法,底层存储数据的结构为数组+链表(jdk8以后达到8之后转换为红黑树),set接口无索引操作,增强了对colleation接口的实现方法

2、HashMap与HashTable区别

  • hashMap是HashTable的替代
  • hashMap线程不安全,HashTable线程安全
  • hashMap的key可以使用null作为key
  • HashTable的key不允许为null作为key

3、List、Map、Set 三个接口,存取元素时,各有什么特点?

  • List:以特定次序来持有元素,可有重复元素。
  • Set:无法拥有重复元素,内部排序。
  • Map:保存key-value 值,value 可多值,但Key值唯一。

4、Arraylist 与Vector 区别

  • 同步性:Vector 是线程安全的(同步),而ArrayList 是线程序不安全的;
  • 数据增长:当需要增长时,Vector 默认增长一倍,而ArrayList 却是一半。

4.6 模拟斗地主案例

  • 需求

按照斗地主的规则,完成洗牌发牌的动作。
在这里插入图片描述

  • 具体规则
1. 组装54张扑克牌将
2. 54张牌顺序打乱
3. 三个玩家参与游戏,三人交替摸牌,每人17张牌,最后三张留作底牌。
4. 查看三人各自手中的牌(按照牌的大小排序)、底牌

注意: 手中扑克牌从大到小的摆放顺序:大王,小王,2,A,K,Q,J,10,9,8,7,6,5,4,3
  • 需求分析

    • 准备牌

    完成数字与纸牌的映射关系:

    使用双列Map(HashMap)集合,完成一个数字与字符串纸牌的对应关系(相当于一个字典)。

    • 洗牌

    通过数字完成洗牌发牌

    • 发牌

    将每个人以及底牌设计为ArrayList,将最后3张牌直接存放于底牌,剩余牌通过对3取模依次发牌。

    存放的过程中要求数字大小与斗地主规则的大小对应。

    将代表不同纸牌的数字分配给不同的玩家与底牌。

    • 看牌

    通过Map集合找到对应字符展示。

    通过查询纸牌与数字的对应关系,由数字转成纸牌字符串再进行展示。

  • 代码实现

public class Poker {
    public static void main(String[] args) {
        /*
         * 1组装54张扑克牌
         */
        // 1.1 创建Map集合存储
        HashMap<Integer, String> pokerMap = new HashMap<Integer, String>();
        // 1.2 创建 花色集合 与 数字集合
        ArrayList<String> colors = new ArrayList<String>();
        ArrayList<String> numbers = new ArrayList<String>();

        // 1.3 存储 花色 与数字
        Collections.addAll(colors, "♦", "♣", "♥", "♠");
        Collections.addAll(numbers, "2", "A", "K", "Q", "J", "10", "9", "8", "7", "6", "5", "4", "3");
        // 设置 存储编号变量
        int count = 1;
        pokerMap.put(count++, "大王");
        pokerMap.put(count++, "小王");
        // 1.4 创建牌 存储到map集合中
        for (String number : numbers) {
            for (String color : colors) {
                String card = color + number;
                pokerMap.put(count++, card);
            }
        }
        /*
         * 2 将54张牌顺序打乱
         */
        // 取出编号 集合
        Set<Integer> numberSet = pokerMap.keySet();
        // 因为要将编号打乱顺序 所以 应该先进行转换到 list集合中
        ArrayList<Integer> numberList = new ArrayList<Integer>();
        numberList.addAll(numberSet);

        // 打乱顺序
        Collections.shuffle(numberList);

        // 3 完成三个玩家交替摸牌,每人17张牌,最后三张留作底牌
        // 3.1 发牌的编号
        // 创建三个玩家编号集合 和一个 底牌编号集合
        ArrayList<Integer> noP1 = new ArrayList<Integer>();
        ArrayList<Integer> noP2 = new ArrayList<Integer>();
        ArrayList<Integer> noP3 = new ArrayList<Integer>();
        ArrayList<Integer> dipaiNo = new ArrayList<Integer>();

        // 3.2发牌的编号
        for (int i = 0; i < numberList.size(); i++) {
            // 获取该编号
            Integer no = numberList.get(i);
            // 发牌
            // 留出底牌,最后三张做为底牌
            if (i >= 51) {
                dipaiNo.add(no);
            } else {
                if (i % 3 == 0) {
                    noP1.add(no);
                } else if (i % 3 == 1) {
                    noP2.add(no);
                } else {
                    noP3.add(no);
                }
            }
        }

        // 4 查看三人各自手中的牌(按照牌的大小排序)、底牌
        // 4.1 对手中编号进行排序
        Collections.sort(noP1);
        Collections.sort(noP2);
        Collections.sort(noP3);
        Collections.sort(dipaiNo);

        // 4.2 进行牌面的转换
        // 创建三个玩家牌面集合 以及底牌牌面集合
        ArrayList<String> player1 = new ArrayList<String>();
        ArrayList<String> player2 = new ArrayList<String>();
        ArrayList<String> player3 = new ArrayList<String>();
        ArrayList<String> dipai = new ArrayList<String>();

        // 4.3转换
        for (Integer i : noP1) {
            // 4.4 根据编号找到 牌面 pokerMap
            String card = pokerMap.get(i);
            // 添加到对应的 牌面集合中
            player1.add(card);
        }

        for (Integer i : noP2) {
            String card = pokerMap.get(i);
            player2.add(card);
        }
        for (Integer i : noP3) {
            String card = pokerMap.get(i);
            player3.add(card);
        }
        for (Integer i : dipaiNo) {
            String card = pokerMap.get(i);
            dipai.add(card);
        }

        //4.5 查看
        System.out.println("令狐冲:"+player1);
        System.out.println("石破天:"+player2);
        System.out.println("鸠摩智:"+player3);
        System.out.println("底牌:"+dipai);
    }
}

五、数据结构

5.1 常见的数据结构

数据存储的常用结构有:栈、队列、数组、链表和红黑树。

5.2 栈

stack,又称堆栈,它是运算受限的线性表,其限制是仅允许在标的一端进行插入和删除操作,不允许在其他任何位置进行添加、查找、删除等操作。

  • 栈的特点

    • 先进后出(即,存进去的元素,要在后它后面的元素依次取出后,才能取出该元素)。例如,子弹压进弹夹,先压进去的子弹在下面,后压进去的子弹在上面,当开枪时,先弹出上面的子弹,然后才能弹出下面的子弹。
    • 栈的入口、出口的都是栈的顶端位置。
      在这里插入图片描述
  • 栈的名词

    • 压栈:就是存元素。即,把元素存储到栈的顶端位置,栈中已有元素依次向栈底方向移动一个位置。
    • 弹栈:就是取元素。即,把栈的顶端位置元素取出,栈中已有元素依次向栈顶方向移动一个位置。

5.3 队列

队列queue,简称队,它同堆栈一样,也是一种运算受限的线性表,其限制是仅允许在表的一端进行插入,而在表的另一端进行删除。

  • 队列的特点
    • 先进先出(即,存进去的元素,要在后它前面的元素依次取出后,才能取出该元素)。例如,小火车过山洞,车头先进去,车尾后进去;车头先出来,车尾后出来。
    • 队列的入口、出口各占一侧。。例如,下图中的左侧为入口,右侧为出口。
      在这里插入图片描述

5.4 数组

数组:Array,是有序的元素序列,数组是在内存中开辟一段连续的空间,并在此空间存放元素。就像是一排出租屋,有100个房间,从001到100每个房间都有固定编号,通过编号就可以快速找到租房子的人。

  • 数组的特点
    • 查找元素快:通过索引,可以快速访问指定位置的元素
      在这里插入图片描述
    • 增删元素慢
    • 指定索引位置增加元素:需要创建一个新数组,将指定新元素存储在指定索引位置,再把原数组元素根据索引,复制到新数组对应索引的位置。如下图
      在这里插入图片描述
    • 指定索引位置删除元素: 需要创建一个新数组,把原数组元素根据索引,复制到新数组对应索引的位置,原数组中指定索引位置元素不复制到新数组中。如下图
      在这里插入图片描述

5.5 链表

链表:linked list,由一系列结点node(链表中每一个元素称为结点)组成,结点可以在运行时i动态生成。每个结点包括两个部分:一个是存储数据元素的数据域,另一个是存储下一个结点地址的指针域。我们常说的链表结构有单向链表与双向链表,那么这里给大家介绍的是单向链表

  • 单向链表数据格式
    在这里插入图片描述
  • 链表的特点

    多个结点之间,通过地址进行连接。例如,多个人手拉手,每个人使用自己的右手拉住下个人的左手,依次类推,这样多个人就连在一起了。
    ![在这里插入图片描述](https://img-blog.csdnimg.cn/d4bc026bc30b49a88d6df0e30ae8b657.png#pic_center

  • 查找元素慢:想查找某个元素,需要通过连接的节点,依次向后查找指定元素
  • 增删元素快
  • 增加元素:只需要修改连接下个元素的地址即可。
    在这里插入图片描述
  • 删除元素:只需要修改连接下个元素的地址即可。
    在这里插入图片描述

5.6 红黑树

5.6.1 二叉树

binary tree ,是每个结点不超过2的有序树(tree)

简单的理解,就是一种类似于我们生活中树的结构,只不过每个结点上都最多只能有两个子结点。

二叉树是每个节点最多有两个子树的树结构。顶上的叫根结点,两边被称作“左子树”和“右子树”。
在这里插入图片描述

5.6.2 红黑树

二叉树的一种比较有意思的叫做红黑树,红黑树本身就是一颗二叉查找树,将节点插入后,该树仍然是一颗二叉查找树。也就意味着,树的键值仍然是有序的。
在这里插入图片描述

  • 红黑树的约束

    • 节点可以是红色的或者黑色的
    • 根节点是黑色的
    • 叶子节点(特指空节点)是黑色的
    • 每个红色节点的子节点都是黑色的
    • 任何一个节点到其每一个叶子节点的所有路径上黑色节点数相同
  • 红黑树的特点

    • 速度特别快,趋近平衡树,查找叶子元素最少和最多次数不多于二倍

每日一点点进步
不进则退

  • 1
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

璃尔 °

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值