day09【Map、斗地主排序、冒泡排序】
反馈和复习
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 比较器); 自定义排序规则(升序 前-后)
今日内容
1.Map集合(和Collection没有直接的联系)
2.集合的嵌套(集合的元素还是集合)
3.斗地主发牌案例(必须3遍以上)
4.冒泡排序算法(a.算法过程 b.算法的代码实现)
第一章 Map集合【重点】
1.1 Map的概述以及其特点
什么是Map集合:
Collection集合称为单列集合,Map集合称为双列集合
Map集合的特点:
a.Collection每个元素单独存在(单列),Map每个元素成对存在(双列)
b.Map集合键必须是唯一的,值是可以重复的
c.Collection<E>中泛型只有一个,Map<K,V>中泛型有两个(其中K代表键的类型,V代表值的类)
1.2 Map的3个常用实现类以及其特点
Map接口有三个常见的实现类:
HashMap: 底层采用哈希表结构, 无序
LinkedHashMap:底层采用链表+哈希表结构,有序
TreeMap: 底层采用红黑树结构,无序(但是键有自然顺序)
重点: Map中为了保证键的唯一性,如果键是自定义类型,必须重写键的hashCode和equals方法
1.3 Map接口定义的通用方法【重点】
增: V put(K 键,V 值); 添加一个键值对,返回null
删: V remove(K 键);根据键去删除键值对,返回被删除的键值对的值
改: V put(K 键,V 值); 添加一个重复的键时,该方法变成修改,返回修改前的值
查: V get(K 键); 根据键获取对应的值
其他:
public boolean containsKey(Object 键); 判断Map中是否包含该键
public boolean containsValue(Object 值); 判断Map中是否包含该值
使用Map中通用方法:
public class TestMap {
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.打印
//{李四=28, 张三=18, 前妻=8, 王五=38, 赵六=48, 王八=88}
System.out.println(map);
//4.删除
Integer v1 = map.remove("王五");
System.out.println(v1);
System.out.println(map);
//5.获取
Integer v2 = map.get("张三");
System.out.println(v2);
System.out.println(map);
//6.修改,也是调用put
Integer v3 = map.put("前妻", 9);
System.out.println(v3);
System.out.println(map);
//7.判断
boolean b1 = map.containsKey("赵七");
System.out.println(b1);
boolean b2 = map.containsValue(18);
System.out.println(b2);
}
}
1.4 Map的遍历【非常重点】
-
遍历方式一
第一种方式称为:以键找值 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); } } }
-
遍历方式二
第二种方式称为:键值对方式 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); } } }
1.5 HashMap存储自定义类型的键
需求:
创建一个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方法
1.6 LinkedHashMap介绍
HashMap底层采用哈希表结构,是无序的
LinkedHashMap底层采用链表+哈希表结构,是有序的
public class TestLinkedHashMap {
public static void main(String[] args) {
//1.创建一个LinkedHashMap
LinkedHashMap<String, Integer> map = new LinkedHashMap<String, Integer>();
//2.添加几个
map.put("rose",20);
map.put("jack",10);
map.put("marry",40);
map.put("tom",30);
//3.打印
System.out.println(map);
}
}
1.7 TreeMap集合
a.TreeMap底层采用红黑树结构
TreeMap也是无序的,会按照键的自然顺序默认升序
public class TestTreeMap {
public static void main(String[] args) {
//1.创建一个TreeMap集合
TreeMap<Integer, String> treeMap = new TreeMap<Integer, String>();
//2.添加
treeMap.put(20,"李四");
treeMap.put(30,"王五");
treeMap.put(40,"赵六");
treeMap.put(10,"张三");
//3.打印
System.out.println(treeMap);
}
}
扩展:
如果键是数值类型,那么按照键值的大小升序
如果键是字符类型,那么按照键的码值的大小升序
如果键是字符串类型,那么按照键的首字母大小升序,如果首字母相同按照次字母,依次类推...
这四种的结论是一样: Arrays.sort Collections.sort TreeSet TreeMap
b.我们也可以使用比较器排序
使用TreeMap的另外一个构造即可
public TreeMap(Comparator 比较器);
public class TestTreeMap {
public static void main(String[] args) {
//1.创建一个TreeMap集合
// TreeMap<Integer, String> treeMap = new TreeMap<Integer, String>();
TreeMap<Integer, String> treeMap = new TreeMap<Integer, String>(new Comparator<Integer>() {
@Override
public int compare(Integer o1, Integer o2) {
//口诀: 升序 前-后
return o2-o1;
}
});
//2.添加
treeMap.put(20,"李四");
treeMap.put(30,"王五");
treeMap.put(40,"赵六");
treeMap.put(10,"张三");
//3.打印
System.out.println(treeMap);
//4.创建TreeMap集合,键是自定义类型
TreeMap<Student, String> map = new TreeMap<Student,String>(new Comparator<Student>() {
@Override
public int compare(Student o1, Student o2) {
//按照年龄降序
// return o2.age-o1.age;
//按照姓名的长度升序
return o1.name.length()-o2.name.length();
}
});
//5.添加数据
map.put(new Student("jack",20),"北京");
map.put(new Student("ady",10),"南京");
map.put(new Student("marry",8),"东京");
map.put(new Student("hanmeimei",15),"西京");
//6.打印
System.out.println(map);
}
}
1.8 Map集合练习【重点】
面试题:
输入一个字符串中每个字符出现次数。
public class TestDemo {
public static void main(String[] args) {
//输入一个字符串中每个字符出现次数。
//分析:
//最后的结果是什么样?? a=3 b=2 c=10 d=5
//1.定义一个map
LinkedHashMap<Character,Integer> map = new LinkedHashMap<Character, Integer>();
//2.输入一个字符串
System.out.println("请输入一个字符串:");
String str = new Scanner(System.in).nextLine();
//abcdabcdac
//3.遍历字符串
for (int i = 0; i < str.length(); i++) {
//4.取出字符串中的某个字符
char ch = str.charAt(i);
//5.这个字符ch以前出现过
if (map.containsKey(ch)){
Integer oldCount = map.get(ch);
map.put(ch,oldCount+1);
}else{
//5.这个字符ch以前没出现过
map.put(ch,1);
}
}
//4.打印结果 map
System.out.println(map);
}
}
第二章 集合的嵌套【难点&重点】
什么是集合的嵌套
集合中的元素还是一个集合
2.1 List嵌套List
a.使用List集合保证两个班的学生名字
public class TestListList {
public static void main(String[] args) {
//a.使用List集合保证两个班的学生名字
//1.创建集合保存一个班级学生
ArrayList<String> ban1 = new ArrayList<String>();
ban1.add("jack");
ban1.add("rose");
ban1.add("tom");
//2.创建集合保存一个班级学生
ArrayList<String> ban2 = new ArrayList<String>();
ban2.add("小花");
ban2.add("小草");
ban2.add("小狗");
//3.将ban1和ban2两个集合,保存到一个大集合中
ArrayList<ArrayList<String>> bans = new ArrayList<>();
bans.add(ban1);
bans.add(ban2);
//4.自己遍历
for (ArrayList<String> ban : bans) {
for (String name : ban) {
System.out.println(name);
}
}
//5.直接打印
// System.out.println(bans);//[[],[]]
}
}
2.2 List嵌套Map
a.保存两个班学生的名字以及对应的年龄
public class TestListMap {
public static void main(String[] args) {
//a.保存两个班学生的名字以及对应的年龄
//1.保存第一个班级学生的姓名和年龄
HashMap<String, Integer> map1 = new HashMap<String, Integer>();
map1.put("jack",12);
map1.put("rose",11);
map1.put("tom",10);
//2.保存第二个班级学生的姓名和年龄
HashMap<String, Integer> map2 = new HashMap<String, Integer>();
map2.put("张鹏",18);
map2.put("徐睿",19);
map2.put("张亭",17);
//3.创建一个大集合 保存两个map
ArrayList<HashMap<String, Integer>> maps = new ArrayList<HashMap<String, Integer>>();
maps.add(map1);
maps.add(map2);
//4.直接打印
System.out.println(maps); //[{},{}]
//5.自己遍历
for (HashMap<String, Integer> map : maps) {
Set<String> keys = map.keySet();
for (String key : keys) {
Integer value = map.get(key);
System.out.println(key+".."+value);
}
}
}
}
2.3 Map嵌套Map
a.保证两个班的名字和班里同学的姓名以及对应的年龄
public class TestMapMap {
public static void main(String[] args) {
//a.保证两个班的名字和班里同学的姓名以及对应的年龄
//1.保存第一个班级同学的姓名和年龄
HashMap<String, Integer> map1 = new HashMap<String, Integer>();
map1.put("jack",12);
map1.put("rose",11);
map1.put("tom",10);
//2.保存第二个班级同学的姓名和年龄
HashMap<String, Integer> map2 = new HashMap<String, Integer>();
map2.put("张鹏",18);
map2.put("徐睿",19);
map2.put("张亭",17);
//3.将两个班级的map集合,保存到另外一个集合中,要求有该班级的名字
HashMap<String,HashMap<String, Integer>> all = new HashMap<String, HashMap<String, Integer>>();
all.put("一班",map1);
all.put("二班",map2);
//4.直接打印
System.out.println(all);// {"一班"={jack=12,rose=11,tom=10},键=值}
//5.手动遍历
//1.获取所有的键
Set<String> names = all.keySet();
//2.遍历所有的键
for (String name : names) {
//3.以键找值
HashMap<String, Integer> map = all.get(name);
//4.获取该map所有的键
Set<String> ns = map.keySet();
//5.遍历ns
for (String n : ns) {
//6.以键找值
Integer value = map.get(n);
System.out.println(n+"..."+value);
}
}
}
}
第三章 模拟斗地主洗牌发牌【重点,至少3遍】
3.1 案例介绍
需求: 模拟斗地主发牌,看牌(但是不打牌)
3.2 案例分析
步骤分析:
1.准备 编号和牌 组成的Map集合
2.准备一副牌(54个编号)
3.洗牌(打乱集合)
4.发牌(遍历集合)
5.排序(sort方法)
6.转牌(以键找值)
7.打印给用户看
3.3 代码实现
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();
}
}
第四章 冒泡排序算法【理解】
4.1 冒泡排序的介绍
所有冒泡排序的思想是这样的:
依次比较数组中相连的两元素,然后将较大元素放在后面,最后按照从小到大顺序排列出来
规律:
n个数比较,一共需要比较n-1轮
第1轮,需要比较n-1次,以后每轮比较的次数会递减
4.2 过程图解(见图解)
4.3 代码实现
冒泡排序算法:
public class TestBubbleSort {
public static void main(String[] args) {
//准备一个数组
int[] arr = {4, 6, 1, 3, 8, 2, 9, 7, 5};
//排序
//一共需要几轮??? arr.length - 1轮
//外层循环,控制轮数
for(int i = 0;i < arr.length - 1;i++) {
// i = 0 1 2
//内存循环,控制比较的次数
for(int j = 0;j < arr.length - 1 - i;j++){
//比较的两个元素:
if (arr[j] > arr[j+1]){ //前100 > 后10
int temp = arr[j];
arr[j] = arr[j+1];
arr[j+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;
}
}
}