c++ map底层实现原理_红黑树TreeSet原理HashSet底层原理Map集合遍历
发布日期:2021-06-24 14:01:17 浏览次数:2 分类:技术文章

本文共 16183 字,大约阅读时间需要 53 分钟。

==学习目标==

1、能够了解红黑树

2、能够掌握HashSet集合的特点以及使用(特点以及使用,哈希表数据结构)

3、能够掌握Map集合的特点以及使用(特点,常见方法,Map集合的遍历)

4、能够掌握HashMap集合的特点以及使用

5、能够掌握TreeMap集合的特点以及使用

==知识点==

  1. 红黑树
  2. HashSet
  3. Map
  4. HashMap
  5. TreeMap

==知识点梳理==

ebc17c41dc9624c23b1c0432662a4a25.png

==超详细讲义==

1.红黑树

1.1红黑树-概述【了解】

1.什么是红黑树

平衡二叉B树,每一个节点可以是红或者黑,红黑树不是 高度平衡 的,它的平衡是通过"自己的红黑规则"进行实现的。

25cf99628ecb90bebc75238cf305f287.png

1.2 红黑树-红黑规则 (了解)

  • 红黑树的红黑规则有哪些每一个节点或是红色的,或者是黑色的根节点必须是黑色所有叶子节点(空的节点被称作叶子节点)都是黑色的不能出现两个红色节点相连 的情况对每一个节点,从该节点到其所有后代叶节点的简单路径上,均包含相同数目的黑色节点

1.3 红黑树-添加节点的默认颜色(了解)

添加节点时,默认为红色,效率高

1.4 红黑树-添加节点后,如何保证红黑规则1 【难点】

dfe54f6ee648ce8b1e3f02bab86d99b7.png
a97b2b8c22d25702885d8aee3a9d4124.png

1.5 红黑树-添加节点后,如何保证红黑规则2 【难点】

(旋转之后,根据规则验证是否是红黑树,总结红黑树添加节点的规则)

09fc45ae99556f49e19e01066c78e4b7.png
418ce934f9fddb4f9f475283ce2c9395.png

1.6 红黑树练习-成绩排序案例【重点】

(共3点)

1.案例需求

  • 用TreeSet集合存储多个学生信息(姓名,语文成绩,数学成绩,英语成绩),并遍历该集合
  • 要求: 按照总分从低到高排序

代码实现

学生类

public class Student implements Comparable {    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 ts = new TreeSet();        //创建学生对象        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原理

ea394a603eabfe43aacd4e048fb2ea22.png
93f2e17d734d10f115a016dc747bbc4b.png

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 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 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.什么是哈希值

是JDK根据对象的地址或者属性值,算出来的int类型的整数

2.如何获取对象中的Hash值

Object类中有一个方法: public int hashCode():根据对象的地址值计算出来的哈希值

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底层原理【难点】

哈希表=数组 + 链表

f61cc97de04c1e3d65c1067f66050231.png

2.5HashSet-JDK8底层优化【难点】

(共两点)

1.HashSet 在JDK1.8之后的原理

  • 节点个数少于等于8个数组 + 链表
  • 节点个数多于8个数组 + 红黑树
15af53485491c2d3b05525e0c8a037cc.png

2.HashSet 在JDK1.8版本的存储流程

400a31836a8da91d6fc634111b72083d.png

2.6HashSet集合存储学生对象并遍历【重点】

  • 案例需求创建一个存储学生对象的集合,存储多个学生对象,使用程序实现在控制台遍历该集合
  • 要求:学生对象的成员变量值相同,我们就认为是同一个对象

代码实现

测试类

public class HashSetDemo2 {    public static void main(String[] args) {        //HashSet集合存储自定义类型元素,要想实现元素的唯一,要求必须重写hashCode方法和equals方法        HashSet 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对象"

7a7d7e80a6cea80585471a333b0d161d.png

3.如何使用Map集合

1.Map集合格式

interface Map  K:键的类型;V:值的类型

2.如何创建Map集合对象

Map map = new HashMap();//使用具体实现类,采用多态形式创建

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 map = new HashMap<>();​        //map.add();        map.put("itheima001","小智");        map.put("itheima002","小美");        map.put("itheima003","大胖");​        System.out.println(map);    }}

3.2Map常用方法【重点】

方法介绍

d06d3943f339718e72848eb552ef4456.png

示例代码

package com.itheima.mapdemo1;​import java.util.HashMap;import java.util.Map;/** * Map的基本方法 */public class MyMap2 {    public static void main(String[] args) {      Map 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 map) {        //        int size()              集合的长度,也就是集合中键值对的个数        int size = map.size();        System.out.println(size);    }​    private static void method6(Map 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 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 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 map) {        //        void clear()            移除所有的键值对元素        map.clear();        System.out.println(map);    }​    private static void method2(Map map) {        //        V remove(Object key)    根据键删除键值对元素        String s = map.remove("itheima001");        System.out.println(s);        System.out.println(map);    }​    private static void method1(Map map) {        //        V put(K key,V value)    添加元素        //如果要添加的键不存在,那么会把键值对都添加到集合中        //如果要添加的键是存在的,那么会覆盖原先的值,把原先值当做返回值进行返回。        String s = map.put("itheima001", "aaa");        System.out.println(s);        System.out.println(map);    }}

3.3Map-第一种遍历方式【重点】

方法介绍

2bff6ed4fed6b1182cbfc188ca5bf5a7.png
8dce8a3cbbb9696ebfeb4002d60069e8.png

示例代码

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 map = new HashMap<>();        map.put("1号丈夫","1号妻子");      map.put("2号丈夫","2号妻子");        map.put("3号丈夫","3号妻子");        map.put("4号丈夫","4号妻子");        map.put("5号丈夫","5号妻子");​        //获取到所有的键      Set keys = map.keySet();        //遍历Set集合得到每一个键        for (String key : keys) {            //通过每一个键key,来获取到对应的值            String value = map.get(key);            System.out.println(key + "---" + value);        }    }}

3.4Map-第二种遍历方式【重点】

方法介绍

c99bdec789463c78ac98a261d0af2524.png
a490c6f336a43558bcbd399c8d5d04b8.png
3ce69cc08960e6e727ffa06661c14273.png

示例代码

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 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> entries = map.entrySet();        for (Map.Entry 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方法
fcc454d699e722e8ad5be9275adf2a7b.png

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 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 keys = hm.keySet();        for (Student key : keys) {            String value = hm.get(key);            System.out.println(key + "----" + value);        }​        System.out.println("===================================");​        //第二种:先获取到所有的键值对对象。再获取到里面的每一个键和每一个值        Set> entries = hm.entrySet();        for (Map.Entry 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方法解析

22146012c8d35500997215d2aeb79a76.png

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*/{  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 tm = new TreeMap<>(new Comparator() {            @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);                }        );    }}

转载地址:https://blog.csdn.net/weixin_33305027/article/details/112124688 如侵犯您的版权,请留言回复原文章的地址,我们会给您删除此文章,给您带来不便请您谅解!

上一篇:32位程序如何在64位系统上运行_WOW64!Hooks:深入考察WOW64子系统运行机制及其Hooking技术(上)...
下一篇:go get 代码找不到_Go 语言基于 channel 实现的并发安全的字节池

发表评论

最新留言

留言是一种美德,欢迎回访!
[***.207.175.100]2024年04月22日 07时22分13秒