==学习目标==
1、能够了解红黑树
2、能够掌握HashSet集合的特点以及使用(特点以及使用,哈希表数据结构)
3、能够掌握Map集合的特点以及使用(特点,常见方法,Map集合的遍历)
4、能够掌握HashMap集合的特点以及使用
5、能够掌握TreeMap集合的特点以及使用
==知识点==
红黑树
HashSet
Map
HashMap
TreeMap
==知识点梳理==
==超详细讲义==
1.红黑树
1.1红黑树-概述【了解】
1.什么是红黑树
平衡二叉B树,每一个节点可以是红或者黑,红黑树不是 高度平衡 的,它的平衡是通过"自己的红黑规则"进行实现的。
1.2 红黑树-红黑规则 (了解)
红黑树的红黑规则有哪些每一个节点或是红色的,或者是黑色的根节点必须是黑色所有叶子节点(空的节点被称作叶子节点)都是黑色的不能出现两个红色节点相连 的情况对每一个节点,从该节点到其所有后代叶节点的简单路径上,均包含相同数目的黑色节点
1.3 红黑树-添加节点的默认颜色(了解)
添加节点时,默认为红色,效率高
1.4 红黑树-添加节点后,如何保证红黑规则1 【难点】
1.5 红黑树-添加节点后,如何保证红黑规则2 【难点】
(旋转之后,根据规则验证是否是红黑树,总结红黑树添加节点的规则)
1.6 红黑树练习-成绩排序案例【重点】
(共3点)
1.案例需求
用TreeSet集合存储多个学生信息(姓名,语文成绩,数学成绩,英语成绩),并遍历该集合
要求: 按照总分从低到高排序
代码实现
学生类
public class Student implements Comparable<Student> {
private String name;
private int chinese;
private int math;
private int english;
public Student() {
}
public Student(String name, int chinese, int math, int english) {
this.name = name;
this.chinese = chinese;
this.math = math;
this.english = english;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getChinese() {
return chinese;
}
public void setChinese(int chinese) {
this.chinese = chinese;
}
public int getMath() {
return math;
}
public void setMath(int math) {
this.math = math;
}
public int getEnglish() {
return english;
}
public void setEnglish(int english) {
this.english = english;
}
public int getSum() {
return this.chinese + this.math + this.english;
}
@Override
public int compareTo(Student o) {
// 主要条件: 按照总分进行排序
int result = o.getSum() - this.getSum();
// 次要条件: 如果总分一样,就按照语文成绩排序
result = result == 0 ? o.getChinese() - this.getChinese() : result;
// 如果语文成绩也一样,就按照数学成绩排序
result = result == 0 ? o.getMath() - this.getMath() : result;
// 如果总分一样,各科成绩也都一样,就按照姓名排序
result = result == 0 ? o.getName().compareTo(this.getName()) : result;
return result;
}
}
测试类
public class TreeSetDemo {
public static void main(String[] args) {
//创建TreeSet集合对象,通过比较器排序进行排序
TreeSet<Student> ts = new TreeSet<Student>();
//创建学生对象
Student s1 = new Student("jack", 98, 100, 95);
Student s2 = new Student("rose", 95, 95, 95);
Student s3 = new Student("sam", 100, 93, 98);
//把学生对象添加到集合
ts.add(s1);
ts.add(s2);
ts.add(s3);
//遍历集合
for (Student s : ts) {
System.out.println(s.getName() + "," + s.getChinese() + "," + s.getMath() + "," + s.getEnglish() + "," + s.getSum());
}
}
}
2.TreeSet原理
2.HashSet集合
2.1HashSet-基本使用【重点】
1.什么是HashSet(HashSet的特点)
底层数据结构是哈希表
存取无序
不可以存储重复元素
没有索引,不能使用普通for循环遍历(get方法)
2.HashSet使用-存储字符串并遍历
package com.itheima.myhashset;
import java.util.HashSet;
import java.util.Iterator;
/**
* 添加字符串并进行遍历
*/
public class HashSetDemo1 {
public static void main(String[] args) {
HashSet<String> hs = new HashSet<>();
hs.add("hello");
hs.add("world");
hs.add("java");
hs.add("java");
hs.add("java");
hs.add("java");
hs.add("java");
hs.add("java");
Iterator<String> it = hs.iterator();
while(it.hasNext()){
String s = it.next();
System.out.println(s);
}
System.out.println("=============================");
for (String s : hs) {
System.out.println(s);
}
}
}
2.2哈希值【了解】
1.什么是哈希值
2.如何获取对象中的Hash值
3.哈希值的特点
没有重写HashCode的情况:
1.同种一对象多次调用hashCode方法返回值是一样的
2.不同对象hashCode方法返回值不一样
Object子类重写hashCode方法的情况:
重写的目的是计算对象哈希值时,按属性值来计算,因此只要属性值相同,不同对象的hashCode方法返回值是一样的
package com.itheima.myhashset;
/**
* 计算哈希值
*/
public class HashSetDemo2 {
public static void main(String[] args) {
Student s1 = new Student("xiaozhi",23);
Student s2 = new Student("xiaomei",22);
//因为在Object类中,是根据对象的地址值计算出来的哈希值。
System.out.println(s1.hashCode());//1060830840
System.out.println(s1.hashCode());//1060830840
System.out.println(s2.hashCode());//2137211482
}
}
Student类
package com.itheima.myhashset;
public class Student {
private String name;
private int age;
public Student() {
}
public Student(String name, int age) {
this.name = name;
this.age = age;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
//我们可以对Object类中的hashCode方法进行重写
//在重写之后,就一般是根据对象的属性值来计算哈希值的。
//此时跟对象的地址值就没有任何关系了。
@Override
public int hashCode() {
int result = name != null ? name.hashCode() : 0;
result = 31 * result + age;
return result;
}
@Override
public String toString() {
return "Student{" +
"name='" + name + '\'' +
", age=" + age +
'}';
}
}
2.4HashSet-JDK7底层原理【难点】
哈希表=数组 + 链表
2.5HashSet-JDK8底层优化【难点】
(共两点)
1.HashSet 在JDK1.8之后的原理
节点个数少于等于8个数组 + 链表
节点个数多于8个数组 + 红黑树
2.HashSet 在JDK1.8版本的存储流程
2.6HashSet集合存储学生对象并遍历【重点】
案例需求创建一个存储学生对象的集合,存储多个学生对象,使用程序实现在控制台遍历该集合
要求:学生对象的成员变量值相同,我们就认为是同一个对象
代码实现
测试类
public class HashSetDemo2 {
public static void main(String[] args) {
//HashSet集合存储自定义类型元素,要想实现元素的唯一,要求必须重写hashCode方法和equals方法
HashSet<Student> hashSet = new HashSet<>();
Student s1 = new Student("xiaohei",23);
Student s2 = new Student("xiaohei",23);
Student s3 = new Student("xiaomei",22);
hashSet.add(s1);
hashSet.add(s2);
hashSet.add(s3);
for (Student student : hashSet) {
System.out.println(student);
}
}
}
学生类
package com.itheima.myhashset;
public class Student {
private String name;
private int age;
public Student() {
}
public Student(String name, int age) {
this.name = name;
this.age = age;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
@Override
public boolean equals(Object o) {
if (this == o) {
return true;
}
if (o == null || getClass() != o.getClass()) {
return false;
}
Student student = (Student) o;
if (age != student.age) {
return false;
}
return name != null ? name.equals(student.name) : student.name == null;
}
//我们可以对Object类中的hashCode方法进行重写
//在重写之后,就一般是根据对象的属性值来计算哈希值的。
//此时跟对象的地址值就没有任何关系了。
@Override
public int hashCode() {
int result = name != null ? name.hashCode() : 0;
result = 31 * result + age;
return result;
}
@Override
public String toString() {
return "Student{" +
"name='" + name + '\'' +
", age=" + age +
'}';
}
}
3.Map集合
3.1Map-基本使用【重点、难点】
(共3点)
1.什么是Map集合【记忆】
Map集合又称为双列集合,双列集合中元素的内容是成对的
2.Map集合的特点 【记忆】
键不能重复,值可以重复
键与值之间是一一对应的关系
(键+值)这个整体我们称之为"键值对"或"键值对对象",在Java中又叫"Entry对象"
3.如何使用Map集合
1.Map集合格式
interface Map<K,V> K:键的类型;V:值的类型
2.如何创建Map集合对象
Map<String,String> map = new HashMap<String,String>();//使用具体实现类,采用多态形式创建
4.使用Map集合存储学生学号和姓名
package com.itheima.mapdemo1;
import java.util.HashMap;
import java.util.Map;
/**
* Map的基本使用
*/
public class MyMap1 {
public static void main(String[] args) {
Map<String,String> map = new HashMap<>();
//map.add();
map.put("itheima001","小智");
map.put("itheima002","小美");
map.put("itheima003","大胖");
System.out.println(map);
}
}
3.2Map常用方法【重点】
方法介绍
示例代码
package com.itheima.mapdemo1;
import java.util.HashMap;
import java.util.Map;
/**
* Map的基本方法
*/
public class MyMap2 {
public static void main(String[] args) {
Map<String,String> map = new HashMap<>();
map.put("itheima001","小智");
map.put("itheima002","小美");
map.put("itheima003","大胖");
map.put("itheima004","小黑");
map.put("itheima005","大师");
//method1(map);
//method2(map);
//method3(map);
//method4(map);
//method5(map);
//method6(map);
//method7(map);
}
private static void method7(Map<String, String> map) {
// int size() 集合的长度,也就是集合中键值对的个数
int size = map.size();
System.out.println(size);
}
private static void method6(Map<String, String> map) {
// boolean isEmpty() 判断集合是否为空
boolean empty1 = map.isEmpty();
System.out.println(empty1);//false
map.clear();
boolean empty2 = map.isEmpty();
System.out.println(empty2);//true
}
private static void method5(Map<String, String> map) {
// boolean containsValue(Object value) 判断集合是否包含指定的值
boolean result1 = map.containsValue("aaa");
boolean result2 = map.containsValue("小智");
System.out.println(result1);
System.out.println(result2);
}
private static void method4(Map<String, String> map) {
// boolean containsKey(Object key) 判断集合是否包含指定的键
boolean result1 = map.containsKey("itheima001");
boolean result2 = map.containsKey("itheima006");
System.out.println(result1);
System.out.println(result2);
}
private static void method3(Map<String, String> map) {
// void clear() 移除所有的键值对元素
map.clear();
System.out.println(map);
}
private static void method2(Map<String, String> map) {
// V remove(Object key) 根据键删除键值对元素
String s = map.remove("itheima001");
System.out.println(s);
System.out.println(map);
}
private static void method1(Map<String, String> map) {
// V put(K key,V value) 添加元素
//如果要添加的键不存在,那么会把键值对都添加到集合中
//如果要添加的键是存在的,那么会覆盖原先的值,把原先值当做返回值进行返回。
String s = map.put("itheima001", "aaa");
System.out.println(s);
System.out.println(map);
}
}
3.3Map-第一种遍历方式【重点】
方法介绍
示例代码
package com.itheima.mapdemo1;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;
/**
* Map的第一种遍历方式
*/
public class MyMap3 {
public static void main(String[] args) {
//创建集合并添加元素
Map<String,String> map = new HashMap<>();
map.put("1号丈夫","1号妻子");
map.put("2号丈夫","2号妻子");
map.put("3号丈夫","3号妻子");
map.put("4号丈夫","4号妻子");
map.put("5号丈夫","5号妻子");
//获取到所有的键
Set<String> keys = map.keySet();
//遍历Set集合得到每一个键
for (String key : keys) {
//通过每一个键key,来获取到对应的值
String value = map.get(key);
System.out.println(key + "---" + value);
}
}
}
3.4Map-第二种遍历方式【重点】
方法介绍
示例代码
package com.itheima.mapdemo1;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;
/**
* Map的第二种遍历方式
*/
public class MyMap4 {
public static void main(String[] args) {
//创建集合并添加元素
Map<String,String> map = new HashMap<>();
map.put("1号丈夫","1号妻子");
map.put("2号丈夫","2号妻子");
map.put("3号丈夫","3号妻子");
map.put("4号丈夫","4号妻子");
map.put("5号丈夫","5号妻子");
//首先要获取到所有的键值对对象。
//Set集合中装的是键值对对象(Entry对象)
//而Entry里面装的是键和值
Set<Map.Entry<String, String>> entries = map.entrySet();
for (Map.Entry<String, String> entry : entries) {
//得到每一个键值对对象
String key = entry.getKey();
String value = entry.getValue();
System.out.println(key + "---" + value);
}
}
}
4.HashMap集合
4.1HashMap-原理解析【难点】
1.HashMap小结
HashMap底层是哈希表结构
依赖hashCode方法和equals方法保证键的唯一
如果键要存储自定义对象,需要重写hashCode和equals方法
4.2 HashMap集合-练习【重点】
(共4点,第4点是对forEache的解析)
1.案例需求
创建一个HashMap集合,键是学生对象(Student),值是籍贯 (String)。存储三个元素,并遍历。
要求保证键的唯一性:如果学生对象的成员变量值相同,我们就认为是同一个对象
2.实现思路
定义学生类
创建HashMap集合对象
添加学生对象
为了保证key的一致性,重写学生类的hashCode和equals方法
3.代码实现
学生类
package com.itheima.mapdemo1;
public class Student{
private String name;
private int age;
public Student() {
}
public Student(String name, int age) {
this.name = name;
this.age = age;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
Student student = (Student) o;
if (age != student.age) return false;
return name != null ? name.equals(student.name) : student.name == null;
}
@Override
public int hashCode() {
int result = name != null ? name.hashCode() : 0;
result = 31 * result + age;
return result;
}
@Override
public String toString() {
return "Student{" +
"name='" + name + '\'' +
", age=" + age +
'}';
}
}
测试类
package com.itheima.mapdemo1;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;
/**
* Map的练习
*/
public class MyMap5 {
public static void main(String[] args) {
HashMap<Student,String> hm = new HashMap<>();
Student s1 = new Student("xiaohei",23);
Student s2 = new Student("dapang",22);
Student s3 = new Student("xiaomei",22);
hm.put(s1,"江苏");
hm.put(s2,"北京");
hm.put(s3,"天津");
//第一种:先获取到所有的键,再通过每一个键来找对应的值
Set<Student> keys = hm.keySet();
for (Student key : keys) {
String value = hm.get(key);
System.out.println(key + "----" + value);
}
System.out.println("===================================");
//第二种:先获取到所有的键值对对象。再获取到里面的每一个键和每一个值
Set<Map.Entry<Student, String>> entries = hm.entrySet();
for (Map.Entry<Student, String> entry : entries) {
Student key = entry.getKey();
String value = entry.getValue();
System.out.println(key + "----" + value);
}
System.out.println("===================================");
//第三种:
hm.forEach(
(Student key, String value)->{
System.out.println(key + "----" + value);
}
);
}
}
4.forEach方法解析
5.TreeMap集合
5.1TreeMap-原理解析【了解】
1.TreeMap-小结
TreeMap底层是红黑树结构
依赖自然排序或者比较器排序,对键进行排序
如果 键存储 的是自定义对象,需要实现Comparable接口或者在创建TreeMap对象时候给出比较器排序规则
5.2TreeMap集合应用案例【重点】
案例需求创建一个TreeMap集合,键是学生对象(Student),值是籍贯(String),学生属性姓名和年龄,按照年龄进行排序并遍历
要求按照学生的年龄进行排序,如果年龄相同则按照姓名进行排序
实现思路
1.创建学生类
2.创建TreeMap集合对象
3.创建学生对象
4.添加学生对象
5.遍历输出
代码实现
学生类
package com.itheima.maptest;
public class Student/* implements Comparable<Student>*/{
private String name;
private int age;
public Student() {
}
public Student(String name, int age) {
this.name = name;
this.age = age;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
@Override
public String toString() {
return "Student{" +
"name='" + name + '\'' +
", age=" + age +
'}';
}
/* @Override
public int compareTo(Student o) {
//按照年龄进行排序
int result = o.getAge() - this.getAge();
//次要条件,按照姓名排序。
result = result == 0 ? o.getName().compareTo(this.getName()) : result;
return result;
}*/
}
测试类
package com.itheima.maptest;
import java.util.Comparator;
import java.util.TreeMap;
/**
* 需求:创建一个TreeMap集合,键是学生对象(Student),值是籍贯(String)。
* 学生属性姓名和年龄,按照年龄进行排序并遍历。
*/
public class Test1 {
public static void main(String[] args) {
TreeMap<Student,String> tm = new TreeMap<>(new Comparator<Student>() {
@Override
public int compare(Student o1, Student o2) {
int result = o1.getAge() - o2.getAge();
result = result== 0 ? o1.getName().compareTo(o2.getName()) : result;
return result;
}
});
Student s1 = new Student("xiaohei",23);
Student s2 = new Student("dapang",22);
Student s3 = new Student("xiaomei",22);
tm.put(s1,"江苏");
tm.put(s2,"北京");
tm.put(s3,"天津");
tm.forEach(
(Student key, String value)->{
System.out.println(key + "---" + value);
}
);
}
}