Java day19 List集合和作业

1、集合

1.1、概述

集合和数组意义都是一种容器工具,可以用来存储多个数据

集合和数组的区别:

  • 数组的长度固定,集合长度可变
  • 数组存储同一类型(包括兼容)的元素,集合中可以存储不同类型的数据
  • 数组中可以存放基本类型数据或者对象,集合中只能存放对象
  • 数组只要一个length属性和充Object中继承的方法
  • 集合由接口和实现类组成,在这其中定义了许多方法

集合框架三个要素

  • 接口
    1. 整个集合框架的上层结构,都是用接口进行组织的
    2. 接口中定义了集合中必须要有的基本方法
    3. 通过接口还把集合划分了几种不同的类型,每一种集合都有自己对应的接口。
  • 实现类
    1. 对于上层使用接口划分好的集合种类,每种集合的接口都会有对应的实现类
    2. 每一个接口的实现类很多苦有多个,每个的实现方式也会各有不同
  • 数据结构
    1. 每个实现类都实现了接口中所定义的最基本的方法,例如对数据存储、检索、操作等方法。
    2. 但是不同的实现类,它们存储数据的方式不同,也就是使用的数据结构不同

集合按照其存储结构可以分为两大类

  • java.util.Collection

    一次只能存储一个数据 单列

  • java.util.Map

    一次可以存储两个数据 双列

其他的集合接口,都是由这两个接口派生出来的:

Collection {List,Set{SortedSet},Queue{Deque}}

Map{SortedMap}

  • 这些都是Java集合框架中的主要接口,以及它们之间的继承关系
  • 接口中定义了该种集合具有的主要方法,以及集合的基本特点
  • 将来要真正要使用的是这些接口的实现类,每种实现类对接口的实现方式不同,那么其特带你也不同

1.2、Collection接口

Collection接口时单列集合类的父接口,其重要的两个接口

java.util.List

java.util.Set

Collection是父接口,其中定义了单列集合通用的一些方法

基本的方法:

//向集合中添加元素	
boolean 	add(E e)
//把一个指定集合中的所有数据,添加到当前集合中    
boolean 	addAll(Collection<? extends E> c)
//清空集合中所有的元素。    
void 		clear()
//判断当前集合中是否包含给定的对象。
boolean 	contains(Object o)
//判断当前集合中是否包含给定的集合的所有元素。    
boolean 	containsAll(Collection<?> c)
//判断当前集合是否为空。
boolean 	isEmpty()
//返回遍历这个集合的迭代器对象    
Iterator<E> iterator()
//把给定的对象,在当前集合中删除。
boolean 	remove(Object o)
//把给定的集合中的所有元素,在当前集合中删除。    
boolean 	removeAll(Collection<?> c)
//判断俩个集合中是否有相同的元素,如果有当前集合只保留相同元素,如果没有当前集合元素清空    
boolean 	retainAll(Collection<?> c)
//返回集合中元素的个数。    
int 		size()
//把集合中的元素,存储到数组中。    
Object[] 	toArray()
//把集合中的元素,存储到数组中,并指定数组的类型  
<T> T[] 	toArray(T[] a)

1.3、迭代器

遍历集合中的每一个元素-----java.util.Iterator

java.util.Iterator接口中,主要定义两个方法:

public interface Iterator {
    boolean hasNext();//返回当前迭代器中是否还有下一个对象
    Object next();//获取迭代器中的下一个对象
}

使用

public static void main(String[] args) {

    Collection c1 = new ArrayList();
    c1.add("hello1");
    c1.add("hello2");
    c1.add("hello3");

	//获取c1集合的迭代器对象
    Iterator iterator = c1.iterator();
    
    //判断迭代器中,是否还有下一个元素
    while(iterator.hasNext()){
        //如果有的话,就取出来
        Object obj = iterator.next();
        System.out.println(obj);
    }


}

1.4、foreach循环

jdk1.5及以上提供了增强for循环,也可以遍历集合

foreach循环的格式:

for(变量类型 变量名 : 集合){
    //操作变量
}

相当于,每次循环,使用指定遍历,去指向集合中的一个对象,然后在循环体中对该变量进行操作

例如:

public static void main(String[] args) {

    Collection<String> c1 = new ArrayList<>();
    c1.add("hello1");
    c1.add("hello2");
    c1.add("hello3");

	for(Object o:c1){
        System.out.println(o);
    }


}

Collection类型及其子类型的集合,还有数组,都可以使用foreach循环进行遍历其中的元素数据

1.5 数据结构

集合接口都会有不同的实现类,每种实现类的底层,采用了不同的数据结构对数据元素进行存储

数据存储的常用结构有:

  • 队列
  • 数组
  • 链表
  • 红黑树
  • 哈希表

数据结构:栈

栈(stack),又称堆栈,仅允许在栈的一端进行插入和删除操作,并且不允许在其他任何位置进行操作。

其特点是:先进后出,最先存进去的元素,最后才能取出来。

例如,薯片存在薯片桶中,我们当前只能取出最上面的一个薯片,而最早存放到薯片桶的薯片,反而是我们最后吃到的一片。

栈的入口、出口的都是栈的顶端位置:

image-20200803234656059

注意1,入栈也称为压栈,把数据存入到栈的顶端位置

注意2,出栈也称为弹栈,把栈顶位置的数据取出

思考,JVM中的栈区中,为什么把main方法标注在最低端位置?

数据结构:队列

队列(queue),仅允许在队列的一端进行插入,而在队列的另一端进行删除。

其特点是:先进先出,最先存进去的元素,可以最先取出来。

例如,火车穿过山洞的时候,第一节车厢先进去山洞的一端,并且这节车厢优先从山洞的另一端出来,后面的车厢依次从一端进入并另一端出来。

队列的入口、出口分别在队列的俩端:

image-20200804000210994

数据结构:数组

数组(array),内存中一块连续的空间,元素数据在其中按照下标索引依次存储,比较常用的数据结构。

其特点是:通过下标索引,可以快速访问指定位置的元素,但是在数组中间位置添加数据或者删除数据会比较慢,因为数组中间位置的添加和删除元素,为了元素数据能紧凑的排列在一起,那么就会引起其后面的元素移动位置。

所以,数组查询元素较快,中间位置的插入、删除元素较慢。

image-20200804001513327

可以看出,数组中间添加数据后,之后的数据都要依次移动位置。同理,中间位置删除的时候也是这样

数据结构:链表

链表(linked list),是有一个一个node节点组成,每个node节点中存储了一个数据,以及一个指向下一个node节点对象的引用(单向链表),如果是双向链表的话,还会存储另一个引用,指向了上一个node节点对象。

其特点是:

  • 查找元素慢,因为需要通过连接的节点,依次向后查找指定元素(没有直接的下标索引)
  • 新增和删除元素较快,例如删除,只需要让当前node节点中的引用指向另一个节点对象即可,原来的指向的node节点就相当于删除了。
image-20200804003227729

可以看出,只需要将数据2节点中的引用,指向数据4的节点对象即可

head表示链表的头部,tail表示链表的尾部

思考,是否能根据单向链表的特点,想象出双向链表的特点?

数据结构:红黑树

二叉树(Binary tree)是树形结构的一个重要类型。二叉树特点是每个结点最多只能有两棵子树,且有左右之分。

二叉树顶上的叫根结点,两边被称作“左子树”和“右子树”。

image-20200804004816435

二叉树中有一种叫做红黑树(Red/Black Tree),它最早被称为平衡二叉B树(symmetric binary B-trees),后来被称为红黑树。

红黑树是一种特殊化的平衡二叉树,它可以在进行插入和删除的时候,如果左右子数的高度相差较大,那么就通过特定操作(左旋、右旋)保持二叉查找树的平衡(动态平衡),从而获得较高的查找性能。

红黑树的每一个节点的左子树的所有数据都比自己小,而右子树的所有数据都比自己大,并且左右子树的高度近似

红黑树的约束:

  1. 根节点必须是黑色
  2. 其他节点可以是红色的或者黑色
  3. 叶子节点(特指null节点)是黑色的
  4. 每个红色节点的子节点都是黑色的
  5. 任何一个节点到其每一个叶子节点的所有路径上黑色节点数相同

注意,红黑树的指定颜色的目的,是利用颜色值作为二叉树的平衡对称性的检查

数据结构:哈希表

java中的哈希表(hash),在JDK1.8之前是采用数组+链表进行实现,根据数据的哈希值,把数据存在数组中,但是当前哈希值冲突的时候,再使用链表进行存储,那么在数组中,同一hash值的数据都存在一个链表里。

注意,之前学习过Object中hashCode方法的作用,hash值的特点以及和对象之间的关系

例如,
image-20200804020521179

例如,如果数据的哈希值相同,在数组使用使用链表存储哈希值相同的几个数据
image-20200804020823526

可以看出,当链表中元素过多,即hash值相等的元素较多时,查找的效率会变低

JDK1.8中,哈希表存储采用数组+链表+红黑树进行实现,当链表长度超过阈值(8)时,将链表转换为红黑树,这样可以大大提高查找的性能。

例如,
image-20200804021504751

思考,java的集合框架中,三个重要组成部分是什么?

接口、实现类、数据结构

1.6 List集合

java.util.List 接口继承了Collection接口,是常用的一种集合类型

list集合具有Collection集合的特点之外,还拥有自己的一些特点:

  • list是一种有序的集合
  • List是一种带索引的集合
  • List是一种可以存放重复数据的集合

list接口中常用方法:

//返回集合中指定位置的元素。
E		get(int index);
//用指定元素替换集合中指定位置的元素,并返回被替代的旧元素。
E		set(int index, E element);
//将指定的元素,添加到该集合中的指定位置上。
void	add(int index, E element);
//从指定位置开始,把另一个集合的所有元素添加进来
boolean addAll(int index, Collection<? extends E> c);
//移除列表中指定位置的元素, 并返回被移除的元素。
E		remove(int index);
//查收指定元素在集合中的所有,从前往后查到的第一个元素(List集合可以重复存放数据)
int		indexOf(Object o);
//查收指定元素在集合中的所有,从后往前查到的第一个元素(List集合可以重复存放数据)
int		lastIndexOf(Object o);
//根据指定开始和结束位置,截取出集合中的一部分数据
List<E> subList(int fromIndex, int toIndex);

1.7List实现类

List接口继承了Collection接口,Collection接口继承了Iterable接口

  • List接口的实现类:ArrayList
    1. ArrayListl是最常用的List集合类型,底层数据类型是用数组实现,所以它的特点是:增删慢,查找快
    2. 当集合需要进行大量数据增删操作的时候,ArrayList就不适用
  • List接口实现类:LinkedList
    1. java.util.LinkedList 存储数据采用的数据结构是链表(双向),所以它的特点:增删快,查找慢
    2. 所以当集合中大量数据需要进行增删操作的时候,就用LinkedList

System.currentTimeMillis(),可以获取当前时刻的时间戳

因为LinkedList中,定义了一些操作头节点和尾节点的方法:

//将指定元素插入此列表的开头
void 		addFirst(E e)
//将指定元素添加到此列表的结尾
void 		addLast(E e)
//返回此列表的第一个元素
E 			getFirst()
//返回此列表的最后一个元素    
E 			getLast()
//从此列表所表示的堆栈处弹出一个元素    
E 			pop()
//将元素推入此列表所表示的堆栈    
void 		push(E e)
//移除并返回此列表的第一个元素    
E 			removeFirst()
//移除并返回此列表的最后一个元素
E 			removeLast()

LinkedList类不仅实现了List接口,还有Queue接口以及子接口Deque也实现了

其中Queue是队列,Deque是双端队列

  • 目前采用双端队列来实现队列和栈的各种需求
  • pop和push都是栈结构的操作方法

Queue中方法和Deque中方法对比:

QueueDeque说明
add(e)addLast(e)向队尾插入元素,失败则抛出异常
offer(e)offerLast(e)向队尾插入元素,失败则返回false
remove()removeFirst()获取并删除队首元素,失败则抛出异常
poll()pollFirst()获取并删除队首元素,失败则返回null
element()getFirst()获取但不删除队首元素,失败则抛出异常
peek()peekFirst()获取但不删除队首元素,失败则返回null

Stack中方法和Deque中方法对比:

StackDeque说明
push(e)addFirst(e)向栈顶插入元素,失败则抛出异常
offerFirst(e)向栈顶插入元素,失败则返回false
pop()removeFirst()获取并删除栈顶元素,失败则抛出异常
pollFirst()获取并删除栈顶元素,失败则返回null
peek()peekFirst()获取但不删除栈顶元素,失败则返回null

所以,LinkedList集合也可以作为栈和队列的数据结构来使用

List接口实现类:Vector
image-20200804171238499

Vector内部也是采用了数组来存储数据,但是Vector中的方法大多数都是线程安全的方法,所以在多线并发访问的环境中,可以使用Vector来保证集合中元据操作的安全。

查看Vector中方法的定义,可以看到多大数方法都使用了synchronized关键字,来给当前方法加锁。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-1Df3Rjqm-1597849516238)(D:/briup-java/day13/corejava-day13/note/day13/corejava-day11.assets/image-20200804171751492.png)]

关于线程的相关问题,后面再具体的学习了解

2、作业

模仿一个麻将洗牌发牌的结果

萬: 一萬 ~ 九萬(每张牌4):  一条 ~ 九条(每张牌4):  一筒 ~ 九筒(每张牌4)
特殊牌:
	东南西北(每张牌4)
	发财(每张牌4)
	红中(每张牌4)
	白板(每张牌4)

四个玩家
	每个人十三张
	有一个人是4张
	拿牌一人一张


import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;

public class MahjongTest {
	@SuppressWarnings({ "unchecked", "rawtypes" })
	public static void main(String[] args) {

      
        List colors = new ArrayList();
        List numbers = new ArrayList();
        List winds = new ArrayList();
        List cards = new ArrayList();


        Collections.addAll(colors,"萬","條","筒");

        Collections.addAll(numbers,"一","二","三","四","五","六","七","八","九");

        Collections.addAll(winds, "东风","南风","西风","北风","红中","白板","發财");

		Map cardWeight = new HashMap();
        cardWeight.put("一",1);
        cardWeight.put("二",2);
        cardWeight.put("三",3);
        cardWeight.put("四",4);
        cardWeight.put("五",5);
        cardWeight.put("六",6);
        cardWeight.put("七",7);
        cardWeight.put("八",8);
        cardWeight.put("九",9);
        cardWeight.put("东风",100);
        cardWeight.put("南风",101);
        cardWeight.put("西风",102);
        cardWeight.put("北风",103);
        cardWeight.put("红中",104);
        cardWeight.put("白板",105);
        cardWeight.put("發财",106);
        cardWeight.put("萬", 30);
        cardWeight.put("條", 50);
        cardWeight.put("筒", 70);
        
        for(int k = 0;k<4;k++) {
        	for(int i=0;i<colors.size();i++){
                String color = (String) colors.get(i);
                for(int j=0;j<numbers.size();j++){
                    String number = (String) numbers.get(j);
                    int weight = (int) cardWeight.get(number)+(int)cardWeight.get(color);
                    cards.add(new Card(color,number,weight));
                }
            }

        }
        

        for(int j =0;j<4;j++) {
            for(int i = 0;i<winds.size();i++) {
            	String wind = (String) winds.get(i);
            	cards.add(new Card("", wind, (int) cardWeight.get(wind)));
            }
        }


        Collections.shuffle(cards);


        Map map = new LinkedHashMap();
        List player1 = new ArrayList();
        List player2 = new ArrayList();
        List player3 = new ArrayList();
        List player4 = new ArrayList();

        map.put("小番茄",player1);
        map.put(" 王  哥 ",player2);
        map.put(" 老  王 ",player3);
        map.put("王忠骅",player4);


        for(int i=0;i<cards.size();i++){

            Card card = (Card) cards.get(i);

            if(i<52){

                if(i%4==0){
                    player1.add(card);
                }
                else if(i%4==1){
                    player2.add(card);
                }
                else if(i%4==2){
                    player3.add(card);
                }else if(i%4==3) {
                	player4.add(card);
                }
            }

        }
        player1.add(cards.get(52));

        Comparator c = new Comparator() {
            @Override
            public int compare(Object o1, Object o2) {
                return ((Card) o1).weight>((Card) o2).weight?1:-1;
            }
        };


        Collections.sort(player1,c);
        Collections.sort(player2,c);
        Collections.sort(player3,c);
        Collections.sort(player4,c);


        
        for(Object key:map.keySet()){
            System.out.println(key+" : "+map.get(key)+"\n");
        }
        
        int temp = 0;
        int time = 0;
        for(int i =cards.size()-53;i>0;i--) {
        	time +=1 ;
        }
        System.out.println("剩余的牌:"+time+"张牌");
        for(int i =cards.size()-53;i>0;i--) {
        	if(temp!=14) {
        		temp +=1;
        		System.out.print(cards.get(i)+"    ");
        	}else {
        		temp = 1;
        		System.out.println();
        		System.out.print(cards.get(i)+"    ");
        	}
        	
        }
        System.out.print("王八");
    }

}


class Card{

    String color;
    String number;
    int weight;

    public Card(String color, String number, int weight) {
        this.color = color;
        this.number = number;
        this.weight = weight;
    }
    @Override
    public String toString() {
        return number+color;
    }
}

{
temp +=1;
System.out.print(cards.get(i)+" “);
}else {
temp = 1;
System.out.println();
System.out.print(cards.get(i)+” ");
}

    }
    System.out.print("王八");
}

}

class Card{

String color;
String number;
int weight;

public Card(String color, String number, int weight) {
    this.color = color;
    this.number = number;
    this.weight = weight;
}
@Override
public String toString() {
    return number+color;
}

}


  • 3
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值