美文网首页
3/12day09_Map集合_集合的嵌套_斗地主发牌案例_冒泡

3/12day09_Map集合_集合的嵌套_斗地主发牌案例_冒泡

作者: 蹦蹦跶跶的起床啊 | 来源:发表于2020-03-12 19:02 被阅读0次

    反馈和复习

    a.比较器口诀: 升序 前-后(源码)
    b.为什么保证元素的唯一性.重写hashCode和equals
        因为Hash表结构,底层就是根据hashCode和equals来判断两个元素是否重复
    1.Collection: 7+1
    2.List: 7+1+4
        ArrayList: 7+1+4
        LinkedList: 7+1+4+8
    3.Set:7+1
        HashSet:7+1   无序
        LinkedHashSet:7+1 有序
        TreeSet:7+1 无序(有自然顺序的)
    4.Collections    
         shuffle(List list); 打乱集合顺序
         sort(List list); 对集合元素进行排序(默认升序)
         sort(List list,Comparator 比较器); 自定义排序规则(升序 前-后)
    

    今日内容

    • Map集合(和Collection没有直接联系)
    • 集合的嵌套(集合的元素还是集合)
    • 斗地主发牌案例[重要]
    • 冒泡排序算法(a,算法过程 b,算法的代码实现)

    Map集合(接口)[重点]

    概述

    所有实现类都没有特有方法 ,是个双列集合



    特点:

    • Collection<E>泛型只有一个, Map<K,V>泛型有两个
    • Collection 中的集合,元素是孤立存在的(理解为单身),向集合中存储元素采用一个个元素的方式存储。
    • Map 中的集合,元素是成对存在的(理解为夫妻)。每个元素由键与值两部分组成,通过键可以找对所对应的
      值。
    • Collection 中的集合称为单列集合, Map 中的集合称为双列集合。
      注意 Map 中的集合不能包含重复的键,值可以重复;每个键只能对应一个值。

    Map的实现类及其特点

    Map接口三个常见的实现类:

    • HashMap 底层采用哈希表结构 无序
    • LinkedHashMap 底层采用链表+哈希表结构 有序 (单列链表结构)
    • TreeMap 底层采用红黑树结构 无序,但是键有自然顺序.可以对元素的键进行排序,排序方式有两种:自然排序和比较器排序

    重点:
    Map中为了保证键的唯一性, 如果键是自定义类型,必须重写键的hashCode和equals方法

    Map的通用方法

    • 增: public V put(K key, V value); 添加一个键值对,返回值类型为V, 返回的就是null
    • 删:public V remove(Object key);根据键删除键值对,返回值类型为 V
    • 改: 用的就是增的方法, put(K key, Value);因为键是唯一的, 添加重复的键,就相当于是修改原键所对应的值了.
    • 查:public V get(Object key) ;根据键获取对应的值,返回值类型为 V
    • 其他:
      public Set<K> keySet() : 获取Map集合中所有的键,存储到Set集合中。
      public Set<Map.Entry<K,V>> entrySet() : 获取到Map集合中所有的键值对对象的集合(Set集合)。
      public boolean containKey(Object key) :判断该集合中是否有此键

    tips:
    使用put方法时,若指定的键(key)在集合中没有,则没有这个键对应的值,返回null,并把指定的键值添加到集合中;
    若指定的键(key)在集合中存在,则返回值为集合中键对应的值(该值为替换前的值),并把指定键所对应的值,替换成指定的新值。

    Map的遍历[非常重要]

    迭代器,增强for,for循环都不可用. 因为 Map和Collection没有关系, 没有索引

    • 遍历方式一以键找值
      1.获取Map中所有的键,由于键是唯一的,所以返回一个Set集合存储所有的键。方法提示: keyset()
      2.遍历键的Set集合,得到每一个键。
      3.根据键,获取键所对应的值。方法提示: get(K key)


    第一种方式称为:以键找值
    public class TestMap01 {
        public static void main(String[] args) {
            //第一种遍历方式:以键找值
            //1.创建一个Map的实现类对象
            HashMap<String, Integer> map = new HashMap<String, Integer>();
            //2.添加几个
            map.put("张三", 18);
            map.put("李四", 28);
            map.put("王五", 38);
            map.put("赵六", 48);
            map.put("前妻", 8);
            map.put("王八", 88);
            //3.获取所有的键
            Set<String> keys = map.keySet();
            //4.遍历这个keys集合
            for (String key : keys) {
                //5.以键找值
                Integer value = map.get(key);
                System.out.println(key + "..." + value);
            }
        }
    }    
    
    • 遍历方式二键值对方式
      Entry键值对对象:
      Map 中存放的是两种对象,一种称为key(键),一种称为value(值),它们在在 Map 中是一一对应关系,这一对对象又称做 Map 中的一个 Entry(项) 。 Entry 将键值对的对应关系封装成了对象。即键值对对象,这样我们在遍历 Map 集合时,就可以从每一个键值对( Entry )对象中获取对应的键与对应的值。
      在Map集合中也提供了获取所有Entry对象的方法:
      public Set<Map.Entry<K,V>> entrySet() : 获取到Map集合中所有的键值对对象的集合(Set集合)。
      获取了Entry对象 , 表示获取了一对键和值,那么同样Entry中 , 分别提供了获取键和获取值的方法:
      public K getKey() :获取Entry对象中的键。
      public V getValue() :获取Entry对象中的值。
    第二种方式称为:键值对方式
    public class TestMap02 {
        public static void main(String[] args) {
            //第一种遍历方式:以键找值
            //1.创建一个Map的实现类对象
            HashMap<String, Integer> map = new HashMap<String, Integer>();
            //2.添加几个
            map.put("张三", 18);
            map.put("李四", 28);
            map.put("王五", 38);
            map.put("赵六", 48);
            //Map集合遍历的第二种方式:键值对方式
            //3.获取Map中所有的键值对
            Set<Map.Entry<String, Integer>> entries = map.entrySet();
            //4.遍历这个entries集合
            for (Map.Entry<String, Integer> entry : entries) {
                //5.从entry中取出键和值
                String key = entry.getKey();
                Integer value = entry.getValue();
                //6.打印
                System.out.println(key+"..."+value);
            }
        }
    }
        
    

    HashMap存储自定义类型

    HashMap存储键位自定义类型时,必须在自定义类型中重写hash和equals方法

    需求:
        创建一个Map,学生作为键, 家庭住址作为值。
        HashMap<Student,String>
    public class TestDemo {
        public static void main(String[] args) {
            //创建一个Map,学生作为键, 家庭住址作为值。
            //1.创建集合
            HashMap<Student,String> map = new HashMap<Student, String>();
            //2.添加数据
            map.put(new Student("jack",12),"北京中关村");
            map.put(new Student("rose",16),"南京中关村");
            map.put(new Student("marry",20),"天津中关村");
            map.put(new Student("tom",12),"东京中关村");
            //3.打印
            //{Student{name=jack,age=12}="北京中关村",键=值,键=值,键=值}
            System.out.println(map);
            //4.我要修改rose的地址
            map.put(new Student("rose",16),"广东东莞");
            System.out.println(map);
        }
    }
    结论:
        如果键是自定义类型,为了保证键的唯一性,必须重写hashCode和equals方法     
    

    LinkedHashMap介绍

    HashMap底层采用哈希表结构,是无序的.
    LinkedHashMap底层采用链表+哈希表结构,是有序的

    public class LinkedHashMapDemo {
        public static void main(String[] args) {
            LinkedHashMap<String, String> map = new LinkedHashMap<String, String>();
            map.put("邓超", "孙俪");
            map.put("李晨", "范冰冰");
            map.put("刘德华", "朱丽倩");
            Set<Entry<String, String>> entrySet = map.entrySet();
            for (Entry<String, String> entry : entrySet) {
                System.out.println(entry.getKey() + "  " + entry.getValue());
            }
        }
    }
    

    TreeMap集合

    TreeMap底层采用红黑树结构
    TreeMap也是无序的, 会按照键的自然顺序默认升序
    如果存储的键为自定义类型,则必须使用比较器进行排序,否则TreeMap的自然顺序会不知道按照对象的什么来排序.

    public static void main(String[] args) {
        TreeMap<Integer, String> map = new TreeMap<Integer, String>();
        map.put(1,"张三");
        map.put(4,"赵六");
        map.put(3,"王五");
        map.put(6,"酒八");
        map.put(5,"老七");
        map.put(2,"李四");
        System.out.println(map);
    }
     
    控制台的输出结果为:
    {1=张三, 2=李四, 3=王五, 4=赵六, 5=老七, 6=酒八}
    

    自然排序

    扩展:
    Arrays.sort | Collections.sort
    | TreeSet | TreeMap 按照如下进行
    如果键是数值类型,按照键值大小升序排序,如果是字符串类型, 先按照首字母码值,再按次字母码值

    如果想要采用从大到小等自定义规则排序, 则使用比较器Comparator 排序就可以

    在TreeMap中可以使用如下代码,使用其构造方法

    public class Student {
        private int age;
        private String name;
        //省略get/set..
        public Student() {}
        public Student(int age, String name) {
            this.age = age;
            this.name = name;
        }
        @Override
        public String toString() {
            return "Student{" +
                    "age=" + age +
                    ", name='" + name + '\'' +
                    '}';
        }
        @Override
        public boolean equals(Object o) {
            if (this == o) return true;
            if (o == null || getClass() != o.getClass()) return false;
            Student student = (Student) o;
            return age == student.age &&
                    Objects.equals(name, student.name);
        }
        @Override
        public int hashCode() {
            return Objects.hash(age, name);
        }
    }
    public static void main(String[] args) {
        TreeMap<Student, String> map = new TreeMap<Student, String>(new Comparator<Student>
    () {
            @Override
            public int compare(Student o1, Student o2) {
                //先按照年龄升序
                int result = o1.getAge() - o2.getAge();
                if (result == 0) {
                    //年龄相同,则按照名字的首字母升序
                    return o1.getName().charAt(0) - o2.getName().charAt(0);
                } else {
                    //年龄不同,直接返回结果
                    return result;
                }
            }
        });
        map.put(new Student(30, "jack"), "深圳");
        map.put(new Student(10, "rose"), "北京");
        map.put(new Student(20, "tom"), "上海");
        map.put(new Student(10, "marry"), "南京");
        map.put(new Student(30, "lucy"), "广州");
        System.out.println(map);
    }
    控制台的输出结果为:
    {
      Student{age=10, name='marry'}=南京, 
      Student{age=10, name='rose'}=北京, 
      Student{age=20, name='tom'}=上海, 
      Student{age=30, name='jack'}=深圳, 
      Student{age=30, name='lucy'}=广州
    }
    

    Map集合练习[重点]

    需求: 输入一个字符串中每个字符出现次数。

    public class MapTest {
    public static void main(String[] args) {
            //友情提示
            System.out.println("请录入一个字符串:");
            String line = new Scanner(System.in).nextLine();
            // 定义 每个字符出现次数的方法
            findChar(line);
        }
        private static void findChar(String line) {
            //1:创建一个集合 存储  字符 以及其出现的次数
            HashMap<Character, Integer> map = new HashMap<Character, Integer>();
            //2:遍历字符串
            for (int i = 0; i < line.length(); i++) {
                char c = line.charAt(i);
                //判断 该字符 是否在键集中
                if (!map.containsKey(c)) {//说明这个字符没有出现过
                    //那就是第一次
                    map.put(c, 1);
                } else {
                    //先获取之前的次数
                    Integer count = map.get(c);
                    //count++;
                    //再次存入  更新
                    map.put(c, ++count);
                }
            }
            System.out.println(map);
        }
    }
    

    集合嵌套[非常重要]

    总述:任何集合内部都可以存储其它任何集合

    List嵌套List

    public class Test{
        public static void main(String[] args){
            /*
                假如有两个班的学生姓名,它们分别存储在两个集合中:
            */
            //第一个班
            ArrayList<String> list1 = new ArrayList<>();
            list1.add("迪丽热巴");
            list1.add("古力娜扎");
            list1.add("柳岩");
            list1.add("杨幂");
            
            //第二个班
            ArrayList<String> list2 = new ArrayList<>();
            list2.add("蔡徐坤");
            list2.add("杨坤");
            list2.add("陈伟霆");
            list2.add("李易峰");
            
            //将两个集合存储到一个集合中
            ArrayList<ArrayList<String>> allList = new ArrayList<>();
            allList.add(list1);
            allList.add(list2);
            
            System.out.println(allList);
            //遍历allList,取出每个ArrayList
            for(ArrayList<String> list : allList){
                //遍历每个班的ArrayList
                for(String s : list){
                    System.out.println(s);
                }
            }
        }
        
    }
     
    
    

    List嵌套Map

    public class Test{
        public static void main(String[] args){
            /*
                有两个班的学员,分别存储在两个Map中
            */
            //第一个班:
            Map<String,String> map1 = new HashMap<>();
            map1.put("it001","迪丽热巴");
            map1.put("it002","古力娜扎");
            
            //第二个班:
            Map<String,String> map2 = new HashMap<>();
            map2.put("heima001","蔡徐坤");
            map2.put("heima002","李易峰");
            
            //将两个班的map存储到一个ArrayList中
            ArrayList<Map<String,String>> allList = new ArrayList<>();
            allList.add(map1);
            allList.add(map2);
            
            //遍历allList,取出每个Map
            for(Map<String,String> map : allList){
                //遍历map
                Set<String> keys = map.keySet();
                for(String key : keys){
                    System.out.println(key + " - " + map.get(key));
                }
            }
        }
    

    Map嵌套Map

    public class Test{
        public static void main(String[] args){
            /*
            有两个班,班号分别为:"黑马188期"和"黑马189期",两个班学员的姓名分别存储在两个Map中
            */
            //"黑马188期":
            Map<String,String> map1 = new HashMap<>();
            map1.put("it001","迪丽热巴");
            map1.put("it002","古力娜扎");
            
            //"黑马189期":
            Map<String,String> map2 = new HashMap<>();
            map2.put("heima001","蔡徐坤");
            map2.put("heima002","李易峰");
            
            //将两个班的Map连同对应的"班号"一同存储在一个Map中
            Map<String,Map<String,String>> allMap = new HashMap<>();
            allMap.put("黑马188期",map1);
            allMap.put("黑马189期",map2);
            
            //遍历allMap
            Set<String> keys = allMap.keySet();
            for(String k : keys){
                System.out.println(k + ":");
                //取出对应的map
                Map<String,String> map = allMap.get(k);
                //遍历map
                Set<String> keys2 = map.keySet();
                for(String k2 : keys2){
                    System.out.println(k2 + " = " + map.get(k2));
                }
            }
        }
    }
    

    模拟斗地主洗牌发牌[重点]

    案例介绍

    需求: 模拟斗地主发牌,看牌(但是不打牌)

    图解斗地主洗牌

    分析

    步骤分析:
    1.准备 编号和牌 组成的Map集合
    2.准备一副牌(54个编号)
    3.洗牌(打乱集合)
    4.发牌(遍历集合)
    5.排序(sort方法)
    6.转牌(以键找值)
    7.打印给用户看

    斗地主洗牌代码实现

    public class TestDouDiZhu {
        public static void main(String[] args) {
            //1.准备 编号和牌 组成的Map集合
            LinkedHashMap<Integer, String> map = new LinkedHashMap<Integer, String>();
            //a.花色 4种
            String[] colors = {"♠", "♥", "♣", "♦"};
            //b.数值 13种
            String[] nums = {"3", "4", "5", "6", "7", "8", "9", "10", "J", "Q", "K", "A", "2"};
            //c.编号变量
            int id = 1;
            //d.组合牌
            for (String num : nums) {
                for (String color : colors) {
                    String card = color + num;
                    //保存到map集合中
                    map.put(id, card);
                    id++;
                }
            }
            //e.单独添加大小王
            map.put(53, "小S");
            map.put(54, "大S");
    
            //2.准备一副牌(54个编号)
            ArrayList<Integer> cards = new ArrayList<Integer>();
            for (int i = 1; i < 55; i++) {
                cards.add(i);
            }
            //3.洗牌(打乱集合)
            Collections.shuffle(cards);
            //4.发牌(遍历集合)
            ArrayList<Integer> player1 = new ArrayList<Integer>();
            ArrayList<Integer> player2 = new ArrayList<Integer>();
            ArrayList<Integer> player3 = new ArrayList<Integer>();
            ArrayList<Integer> diPai = new ArrayList<Integer>();
            //遍历集合
            //此处不能使用增强for
            for (int i = 0; i < cards.size() - 3; i++) {
                //取出每一张牌
                Integer card = cards.get(i);
                //给谁呢?????????????????????????????????
                //i = 0 3 6 p1
                //i = 1 4 7 p2
                //i = 2 5 8 p3
                if (i % 3 == 0) {
                    player1.add(card);
                } else if (i % 3 == 1) {
                    player2.add(card);
                }else{
                    player3.add(card);
                }
            }
    
            //最后张三留给底牌
            diPai.add(cards.get(53));
            diPai.add(cards.get(52));
            diPai.add(cards.get(51));
            //5.排序(sort方法)
            Collections.sort(player1);
            Collections.sort(player2);
            Collections.sort(player3);
            Collections.sort(diPai);
    
            //6.看牌
            lookCards(player1,map);
            lookCards(player2,map);
            lookCards(player3,map);
            lookCards(diPai,map);
    
        }
        //看牌方法
        public static void lookCards(ArrayList<Integer> idCards, LinkedHashMap<Integer, String> map) {
            //遍历
            for (Integer idCard : idCards) {
                String card = map.get(idCard);
                System.out.print(card+" ");
            }
            System.out.println();
        }
    }
    

    冒泡排序算法(工具类已经写好了)

    介绍

    • 依次比较相连的两个元素,大的放后边
    • 如果有n个数据进行排序,总共需要比较n-1轮(每一轮是指, 如 数组中5个数, 0和1,1和2,2和3,3和4 才算一轮)
    • 每一轮比较完毕,下一轮的比较就会少一个数据参与

    n个数据一共执行 n-1轮, 每一轮, 需要执行 n-1次

    过程图解


    冒泡排序动态图.gif

    代码实现

    /*
        冒泡排序:
            一种排序的方式,对要进行排序的数据中相邻的数据进行两两比较,将较大的数据放在后面,
            依次对所有的数据进行操作,直至所有数据按要求完成排序
     */
    public class ArrayDemo {
        public static void main(String[] args) {
            //定义一个数组
            int[] arr = {7, 6, 5, 4, 3};
            System.out.println("排序前:" + Arrays.toString(arr));
     
            // 这里减1,是控制每轮比较的次数
            for (int x = 0; x < arr.length - 1; x++) {
                // -1是为了避免索引越界,-x是为了调高比较效率
                for (int i = 0; i < arr.length - 1 - x; i++) {
                      //如果前>后   
                      if (arr[i] > arr[i + 1]) {
                        int temp = arr[i];
                        arr[i] = arr[i + 1];
                        arr[i + 1] = temp;
                    }
                }
            }
            System.out.println("排序后:" + Arrays.toString(arr));
        }
    }
    

    数结构特点小结

    数组特点:查询快,增删慢

    单向链表特点:查询慢,增删快

    栈特点:先进后出

    队列特点:先进先出

    哈希表特点:查询速度快

    今日小结

    1.Map接口定义的共性方法【必须掌握】
            put(键,值);
            remove(键);
            put(重复的键,值);
            get(键)
                
            containsKey(键);
            containsValue(值);
    2.Map各种实现类的遍历方式(a.以键找值 b.键值对方式)【必须掌握】
            a.以键找值
                Set<K> keys = map.keySet(); //获取所有键的集合
                for(K key : keys){ //遍历所有的键
                    V value = map.get(key)//以键找值
                    //打印
                    sout(key,value);    
                }
            b.键值对方式
                Set<Map.Entry<K,V>> entrys = map.entrySet();//获取所有的键值对的集合
                for(Map.Entry<K,V> entry : entrys){//遍历这个键值对集合
                    K key = entry.getKey();//获取键值对中的键和值  
                    V value = entry.getValue();//获取键值对中的键和值  
                    //打印
                    sout(key,value);   
                }
        
    3.集合嵌套【难点,开发中见的不多】
        a。List套List:
            ArrayList<ArrayList<String>> arr;
        b。List套Map
            ArrayList<HashMap<String,Integer>> map
        c。Map套Map
            HashMap<String,HashMap<String,Integer>> map
    4.斗地主牌【必须掌握】
        至少3遍!!!    
        
    5.冒泡排序【理解】
          a。理解冒泡过程
          b。算法背下来
                for(int i = 0;i<arr.length-1;i++){
                    for(int j = 0;j<arr.length-1-i;j++){
                        if(arr[j]>arr[j+1]){
                            int temp = arr[j];
                            arr[j] = arr[j+1];
                            arr[j+1] = temp;
                        }
                    }  
                }
        ```    
    
    
    
    
    
    

    相关文章

      网友评论

          本文标题:3/12day09_Map集合_集合的嵌套_斗地主发牌案例_冒泡

          本文链接:https://www.haomeiwen.com/subject/srnejhtx.html