一、回顾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类
- HashSet类
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:表示相同元素 ( 不存)
- 当结果为正数:表示大(降序)
- 当结果为负数:表示小(升序)
- 当存储的元素是自定义对象时:
- 存储的元素需要实现Comparable接口,并重写compareto方法
-
比较器排序
-
假设场景: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()
-
请描述使用键找值方式遍历的步骤
-
先通过keySet获取所有的键
-
遍历所有的键,通过键找到值
-
Set<Map.Entry> entrySet()
-
请描述使用键值对对象方式遍历的步骤
-
调用map集合的entrySet方法获取所有的键值对对象
-
遍历每一个键值对对象(Entry对象)
-
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、冒泡排序
请简要描述,什么是冒泡排序?
比较相邻两个元素大小,如果反序,则交换
代码实现冒泡排序时有什么规律?
有n个元素,那么就要比较n-1趟。
每一趟中都会选出一个最值元素,较前一趟少比较一次。
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、选择排序
请描述选择排序的工作原理?
每一次从待排序的数据元素中选出最小(或最大)的一个元素,存放在序列的起始位置,然后,再从剩余未
排序元素中继续寻找最小(大)元素,然后放到已排序序列的末尾。以此类推,直到全部待排序的数据元素排完。
代码实现选择排序时有什么规律?
有n个元素,那么就要比较n-1趟。
每一趟中都会选出一个最值元素,较前一趟少比较一次。
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 。
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;
}
}