06-JavaSE【回顾Set / List / Collection、Map集合、集合的嵌套、排序查找与算法】

一、回顾Set集合

  • 特点:存取无序、没有索引、不可以存储重复元素

  • 子类: (所有方法都来自Collection集合)

    • HashSet类

      • 特点:底层使用哈希表(数组、链表、红黑树)结构
    • LinkedHashSet类

      • 特点:底层使用链表+哈希表结构 (作用:存取元素有序)
    • TreeSet类

      • 特点:底层使用红黑树

      • 存储在TreeSet集合中的元素,会按照给定的规则进行排序

      • 排序规则

        • 自然排序: 元素自身要实现java.util.Comparable接口(重写compareTo方法)

        • 比较器排序:元素自身不需要实现特定的某个接口

          • 需要在创建TreeSet集合时,指定比较器对象

            • 在比较器对象中,实现排序
          • TreeSet set = new TreeSet(new Comparator(){
                          
                          
                //重写
                public int  compare(Object o1 , Object  o2){
                          
                          
                    
                   return  0   or   正数   or  负数
                }
            })
            

1、Set集合

  • 特点:
    • 存储无序
    • 不能存储重复元素
    • 没有索引
  • 子类:
    • HashSet类
      • 特点:
        • 底层使用哈希表结构
    • LinkedHashSet类

2、HashSet集合

  • 底层使用哈希表结构
  • 特点:
    • 存取元素无序
    • 没有索引
    • 不能存储重复元素(存储自定义对象时,如要保证对象不重复要重写:equals、hashCode)

3、LinkedHashSet集合

  • 底层使用哈希表+链表(保证存取顺序一致)
  • 特点:
    • 没有索引
    • 不能存储重复元素
    • 存取元素的顺序一致

4、TreeSet集合

java.util.TreeSet类,实现Set接口

  • 特点:

    • 去重

    • 没有索引

    • 存储的元素会自动排序

      • 排序方式有两种:

        • 1、自然排序

        • 2、比较器排序 : 使用Comparator对象

        • 注明:到底使用哪一种排序规则,取决于TreeSet集合实例化时的构造方法

          • 示例:

            • TreeSet set = new TreeSet();//使用自然排序
              
              TreeSet set = new TreeSet( Comparator对象 ) //使用比较器排序
              

    TreeSet集合的排序:

    • 自然排序

      • 存储的元素需要实现Comparable接口,并重写compareto方法
        • 当存储的元素是自定义对象时:
          • 1、自定义类必须实现comparable接口,并重写compareto方法
          • 2、在重写的compareto方法中制定排序规则
            • 当结果为0:表示相同元素 ( 不存)
            • 当结果为正数:表示大(降序)
            • 当结果为负数:表示小(升序)
    • 比较器排序

      • 假设场景:TreeSet集合中存储String类型,要求降序排序

        • String类是一个final,不能继承该类并重写compareTo方法
        • 解决方案:比较器排序
      • 比较器需要使用:java.uti.Comparator接口

        • 存在一个方法:compare方法 //相当于compareTo
      • 比较器的使用:

        • //在创建TreeSet集合对象时,指定比较器对象
          TreeSet<String> set = new TreeSet<>( Comparator对象 );
          

结论:当TreeSet集合中存储的自定义对象有自然排序功能,且在创建TreeSet时也指定比较器,此时:优先使用比较器对象中的排序规则

二、回顾List集合

  • 特点:存取有序、有索引、可以存储重复元素

1、ArrayList工具类

  • 特点:底层使用数组结构。 查询快、增删慢
  • 方法:
    • 添加: add(int index , Object obj)
    • 删除: remove(int index)
    • 修改: set(int index , Object obj)
    • 查询: get(int index)

2、LinkedList类

  • 特点:底层使用双向链表结构。 查询慢、增删快
  • 方法:
    • 添加:addFirst(Object ojb) 、 addLast(Object obj)
    • 删除:removeFirst()、removeLast()
    • 修改:set(int index , Object ojb) //实现了List集合 (List继承了Collection接口)
    • 查询:getFirst() 、getLast()

三、回顾Collections工具类:

  • 为集合提供了相关的功能。例:排序、乱序、添加所有元素、…
  • 常用方法:
    • shuffle(List list) //把集合中的元素顺序随机打乱
    • sort(List list) //把List集合中的元素进行自然排序(元素自身需要实现Comparable接口)
    • sort(List list , Comparator c) //对List集合中的元素进行排序(排序规则以比较器为准)
    • addAll(Collection c , Object… args )//把args元素添加到c集合中 (args可以有0或多个)

四、Map集合

特点:

  • 一次存储"键值对"两个元素
  • 键元素不能重复,值元素可以重复
  • 一个键元素只能关联一个值元素(一 一 对应)

常用方法:

  • 添加元素:

    • public V put(Object key , Object value)
         //在存储元素之前,会先拿key元素,在Map集合中检索是否已有相同的key存在
          //存在: 拿value元素 覆盖原有的value
          //不存在: 直接存储key、value
      //返回值:
          当返回值为:null,表示是新的key和value添加成功
          返回值为: 非null, 表示是把原有的value覆盖了。  返回还有的value元素值
      
  • 删除元素:

    • public V remove(Object key)
          //根据给定的key元素, 把Map集合中的对应的key以及关联的value,一起删除,并且返回被删除的value值
      
  • 修改元素: put(Object key , Object value)

  • 获取元素:

    • public V get(Object key)
          //根据给定的key元素,获取对应的value元素
      
  • 其它方法:

    • boolean containsKey(Object key) //判断key是否存在
      int  size()  //集合大小
      

1、Map集合概述

java.util.Map<K,V> 集合,里面保存的数据是成对存在的,称之为双列集合。存储的数据,我们称为键值对。 之前所学的Collection集合中元素单个单个存在的,称为单列集合。

查看Map接口描述,发现Map接口下的集合与Collection接口下的集合,它们存储数据的形式不同,如下图。

在这里插入图片描述

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

2、 Map的继承体系(常用实现类

在这里插入图片描述

  • HashMap<K,V>:存储数据采用的哈希表结构,元素的存取顺序不能保证一致。由于要保证键的唯一、不重复,需要重写键的hashCode()方法、equals()方法。
  • LinkedHashMap<K,V>:HashMap下有个子类LinkedHashMap,存储数据采用的哈希表结构+链表结构。通过链表结构可以保证元素的存取顺序一致;通过哈希表结构可以保证的键的唯一、不重复,需要重写键的hashCode()方法、equals()方法。
  • TreeMap<K,V>:TreeMap集合和Map相比没有特有的功能,底层的数据结构是红黑树;可以对元素的**进行排序,排序方式有两种:自然排序比较器排序
  • Hashtable被HashMap集合取代了
  • ConcurrentHashMap属于多线程安全,效率低

tips:Map接口中的集合都有两个泛型变量<K,V>,在使用时,要为两个泛型变量赋予数据类型。两个泛型变量<K,V>的数据类型可以相同,也可以不同。

总结:

HashMap:

HashSet底层实现是HashMap完成的,HashSet保存的元素其实就是HashMap集合中保存的键,底层结构是哈希表结构,具有去重,无序,特点。

LinkedHashMap:

底层结构是有链表和哈希表结构,去重,有序

TreeMap:

底层是有红黑树,去重,无序,排序

3 、Map的常用方法

Map接口中定义了很多方法,常用的如下:

  • public V put(K key, V value): 把指定的键与指定的值添加到Map集合中。
  • public V remove(Object key): 把指定的键 所对应的键值对元素 在Map集合中删除,返回被删除元素的值。
  • public V get(Object key) 根据指定的键,在Map集合中获取对应的值。
  • public Set<K> keySet(): 获取Map集合中所有的键,存储到Set集合中。
  • public Set<Map.Entry<K,V>> entrySet(): 获取到Map集合中所有的键值对对象的集合(Set集合)。
  • public boolean containKey(Object key):判断该集合中是否有此键。

4、Map集合的遍历

Set keySet()

  • 请描述使用键找值方式遍历的步骤

    1. 先通过keySet获取所有的键

    2. 遍历所有的键,通过键找到值

Set<Map.Entry> entrySet()

  • 请描述使用键值对对象方式遍历的步骤

    1. 调用map集合的entrySet方法获取所有的键值对对象

    2. 遍历每一个键值对对象(Entry对象)

    3. getKey获取键,getValue获取值

遍历图解:
在这里插入图片描述

5、Map常用子类

01、HashMap类(必须掌握)

1.HashMap类底层是一个哈希表数据结构,控制键

2.要求HashMap键位置的对象所属类必须重写hashCode和equals方法

3.HashMap集合是jdk1.2开始有的:

1)线程不安全
2) 效率高
3)键和值可以是null
4) 存取无序

小结:向HashMap中的键位置存储的对象所属类必须重写hashCode和equals方法

02、Hashtable类

1.jdk1.0

2.效率低

3.线程安全

4.键和值不能是null

03、LinkedHashMap(了解)

1.他的父类是HashMap

2.底层有两个数据结构:

​ 1)哈希表:保证键唯一 存储键的

​ 2)双重链表:保证存取顺序

04、 TreeMap集合

TreeMap集合和Map相比没有特有的功能,

底层的数据结构是红黑树;可以对元素的进行排序。

排序方式有两种:自然排序比较器排序

到时使用的是哪种排序,取决于我们在创建对象的时候所使用的构造方法;

public TreeMap()									使用自然排序
public TreeMap(Comparator<? super K> comparator) 	比较器排

五、集合的嵌套

1、List嵌套List

**使用场景举例:**一年级有多个班级,每个班级有多名学生。要求保存每个班级的学生姓名,

保存个年级所有的班级信息。

思路:

1.可以使用List集合保存一个班级的学生

2.可以使用List集合保存所有班级

因此我们可以定义集合如下:

班级:List

年级:List<List>

2、 List嵌套Map

**使用场景举例:**一年级有多个班级,每个班级有多名学生。要求保存每个班级的学生姓名,姓名有与之对应的学号,保存一年级所有的班级信息。

思路:

1.可以使用Map集合保存一个班级的学生(键是学号,值是名字)

2.可以使用List集合保存所有班级

因此我们可以定义集合如下:

班级:Map<String,String> 键是学号,值是姓名

年级:List<Map<String,String>>保存每个班级的信息

3、Map嵌套Map

**使用场景举例:**一个年级有多个班级,每个班级有多名学生。要求保存每个班级的学生姓名,姓名

有与之对应的学号,保存一年级所有的班级信息,班级有与之对应的班级名称。

思路:

1.可以使用Map集合保存一个班级的学生(键是学号,值是名字)

2.可以使用Map集合保存所有班级(键是班级名称,值是班级集合信息)

因此我们可以定义集合如下:

班级: Map<String,String> 键:学号,值:姓名

年级: Map<String,Map<String,String>> 键:班级名称,值:具体班级信息

六、排序查找与算法

1、冒泡排序

请简要描述,什么是冒泡排序?

比较相邻两个元素大小,如果反序,则交换

代码实现冒泡排序时有什么规律?

  1. 有n个元素,那么就要比较n-1趟。

  2. 每一趟中都会选出一个最值元素,较前一趟少比较一次。

在这里插入图片描述

    public static void bubblingSort(int[] arr) {
    
    
        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;
                }
            }
        }
        System.out.println(Arrays.toString(arr));
    }

2、选择排序

请描述选择排序的工作原理?

每一次从待排序的数据元素中选出最小(或最大)的一个元素,存放在序列的起始位置,然后,再从剩余未

排序元素中继续寻找最小(大)元素,然后放到已排序序列的末尾。以此类推,直到全部待排序的数据元素排完。

代码实现选择排序时有什么规律?

  1. 有n个元素,那么就要比较n-1趟。

  2. 每一趟中都会选出一个最值元素,较前一趟少比较一次。

在这里插入图片描述

   public static void selectSort(int[] arr) {
    
    
        for (int i = 0; i < arr.length; i++) {
    
    
            for (int j = i + 1; j < arr.length; j++) {
    
    
                if (arr[i] > arr[j]) {
    
    
                    int temp = arr[i];
                    arr[i] = arr[j];
                    arr[j] = temp;
                }
            }
        }

        System.out.println(Arrays.toString(arr));
    }

3、二分查找

数组/集合要实现二分查找有什么前提条件?

数组、集合必须是有排序的。

请描述二分查找的实现原理?

二分查找的原理,每次查找最中间的元素,对比中间元素的值与被查找元素的值大小。

  1. 刚好相同,找到了结束

  2. 如果要找的元素比中间元素小了。将查找的范围缩小到中间的左边一般。继续二分查找

  3. 如果要找的元素比中间元素大了。将查找的范围缩小到中间的右边一般。继续二分查找

直到找到位置,如果最没有找到返回-1 。

在这里插入图片描述

import java.util.Arrays;
import java.util.Collections;

public class Demo3 {
    
    
    public static void main(String[] args) {
    
    
        int[] nums = {
    
    20, 18, 21, 24, 16, 19, 22};

        //数组排序
        Arrays.sort(nums);
        System.out.println("排序后的数组:" + Arrays.toString(nums));
        //[16, 18, 19, 20, 21, 22, 24]

        int index = searchNum(nums, 17);

        System.out.println(index);
    }

    public static int searchNum(int[] array, int key) {
    
    
        int start = 0;//头部索引
        int end = array.length - 1;//尾部索引


        for (int i = 0; start <= end; i++)
        {
    
    
            int mid = (start + end) / 2; //计算出中间索引

            //拿中间索引的元素值 和 要查找的元素值 比较
            if (array[mid] > key) {
    
    
                end = mid - 1;
            } else if (array[mid] < key) {
    
    
                start = mid + 1;
            }else{
    
    
                return mid;
            }
        }
        return -1;
    }
}

猜你喜欢

转载自blog.csdn.net/mmmmmCJP/article/details/115189190