• 集合框架:Set集合的特点、HashSet集合的底层原理、哈希表、实现去重复


    Set集合的特点

    Set(集合)是一种无序的、不重复的数据结构,它的特点如下:

    1. 集合中的元素是无序的:Set 中的元素没有顺序,无法通过索引来访问。

    2. 集合中的元素是唯一的:Set 中不允许有重复的元素,每个元素在集合中只能出现一次。

    3. 内部实现采用哈希表或树形结构:Set 内部通常是基于哈希表或平衡树等数据结构实现的。

    4. 可以用于去重和快速查找:因为 Set 中的元素是唯一的,所以可以很方便地用来做去重操作。同时,由于内部实现采用哈希表或树形结构,所以查找某个元素的时间复杂度为 O(1) 或 O(log n)。

    5. Set 中的元素必须是可哈希的:由于 Set 中的元素是基于哈希表实现的,所以集合中的元素必须是可哈希的,即元素必须有一个明确的哈希值。如果一个元素没有哈希值,那么它就不能被用作 Set 的元素。

    注意:

    Set要用到的常用方法,基本上就是Collection提供的!自己几乎没有额外新增一些常用方法!

    练习代码

    1. import java.util.Set;
    2. import java.util.TreeSet;
    3. public class Test_set {
    4. public static void main(String[] args) {
    5. //1.创建一个set集合对象
    6. //HashSet:无序,不重复,无索引
    7. //Set set = new HashSet<>(); //创建了一个HashSet的集合对象 一行经典代码
    8. //LinkedHashSet:有序,不重复,无索引
    9. //Set set = new LinkedHashSet<>(); //创建了一个LinkedHashSet的集合对象
    10. //TreeSet:可排序(默认升序),不重复,无索引
    11. Set set = new TreeSet<>(); //创建了一个TreeSet的集合对象
    12. set.add(666);
    13. set.add(555);
    14. set.add(555);
    15. set.add(888);
    16. set.add(888);
    17. set.add(777);
    18. set.add(777);
    19. System.out.println(set);
    20. }
    21. }

    哈希值

    在学习HashSet集合的底层原理之前,我们先来了解一下什么是哈希值↓↓↓

    概念

    哈希值(Hash Value)是指将任意长度的数据映射为固定长度的值,通常用一个整数或固定长度的字节数组表示。哈希值也被称为散列值(Hash Code)或摘要(Digest)。

    特点

    在计算机领域,哈希值经常用于数据的存储、索引和加密等操作。它具有以下特点:

    1. 哈希值是固定长度的:无论输入数据的长度是多少,哈希函数都会生成固定长度的哈希值。例如,常见的哈希算法 MD5 生成的哈希值为 128 位,SHA-1 的哈希值为 160 位。

    2. 输入数据的微小改变会导致哈希值的巨大变化:只需改变输入数据的微小部分,哈希值就会发生巨大的变化。这种特性称为"雪崩效应",使得哈希值在校验数据的完整性时非常有用。

    3. 哈希值一般是不可逆的:通常情况下,根据哈希值无法推导出原始数据的内容。哈希函数设计成使得产生相同哈希值的原始数据非常困难。

    4. 相同的输入数据生成相同的哈希值:哈希函数对于相同的输入数据总是生成相同的哈希值,这方便进行数据的存储和比较。

    5. 哈希值的分布应该均匀:良好的哈希函数应该能够将输入数据均匀地映射到哈希值空间,尽量避免碰撞(多个不同的输入数据生成相同的哈希值)。

    java中Object类提供的public int hashCode()方法可以返回对象的哈希码值。

    HashSet集合的底层原理

    在 HashSet 中,元素被存储在一个 HashMap 的实例中,其中元素的值作为键(key),而键的哈希值(通过调用元素的 hashCode() 方法)则用来确定元素在哈希表中的位置。当要将一个元素加入 HashSet 时,HashSet 会首先计算该元素的哈希值,然后找到对应的存储位置。如果该位置上已经存在了元素,HashSet 会使用 equals() 方法来检查这两个元素是否相等,如果相等则认为是重复元素,不会将其加入集合。

    简单来说,HashSet 的底层原理是基于哈希表实现的,使用哈希值来快速查找元素,并提供了高效的添加、删除和查找操作。

    哈希表

    既然HashSet集合是基于哈希表实现的,那么我们就来学习下哈希表↓↓↓

    哈希表(Hash table,也叫散列表),是根据关键码值(Key value)而直接进行访问的数据结构。也就是说,它通过把关键码值映射到表中一个位置来访问记录,以加快查找的速度。这个映射函数叫做散列函数,存放记录的数组叫做散列表。

    给定表M,存在函数f(key),对任意给定的关键字值key,代入函数后若能得到包含该关键字的记录在表中的地址,则称表M为哈希(Hash)表,函数f(key)为哈希(Hash) 函数。

    实现去重复

    先来看一段代码

    1. import java.util.HashSet;
    2. import java.util.Set;
    3. public class Test {
    4. public static void main(String[] args) {
    5. //深入了解HashSet的去重复机制
    6. Set students = new HashSet<>();
    7. Student st1 = new Student("至尊宝",18,167.5);
    8. Student st2 = new Student("蜘蛛精",22,169.8);
    9. Student st3 = new Student("蜘蛛精",22,169.8);
    10. Student st4 = new Student("牛魔王",19,183.5);
    11. students.add(st1);
    12. students.add(st2);
    13. students.add(st3);
    14. students.add(st4);
    15. System.out.println(students);
    16. }
    17. }

    运行一下

    这里面有两个内容相同的不同对象st1和st2,那么HashSet集合默认是不能去重复的。在实际操作中,我们希望只留下一个对象来表示,该怎么做呢?

    //内容一样的两个对象,HashSet认为他们是不重复的
    
    /*
    如果希望Set集合认为两个内容一样的对象是重复的,必须重写对象的hashcode()和equals()方法
     */

    我们可以去Student类中重写hashcode()和equals()方法

    1. import java.util.Objects;
    2. public class Student {
    3. private String name;
    4. private int age;
    5. private double height;
    6. public Student() {
    7. }
    8. @Override
    9. public boolean equals(Object o) {
    10. if (this == o) return true;
    11. if (o == null || getClass() != o.getClass()) return false;
    12. Student student = (Student) o;
    13. return age == student.age && Double.compare(height, student.height) == 0 && Objects.equals(name, student.name);
    14. }
    15. @Override
    16. public int hashCode() {
    17. return Objects.hash(name, age, height);
    18. }
    19. public Student(String name, int age, double height) {
    20. this.name = name;
    21. this.age = age;
    22. this.height = height;
    23. }
    24. public String getName() {
    25. return name;
    26. }
    27. public void setName(String name) {
    28. this.name = name;
    29. }
    30. public int getAge() {
    31. return age;
    32. }
    33. public void setAge(int age) {
    34. this.age = age;
    35. }
    36. public double getHeight() {
    37. return height;
    38. }
    39. public void setHeight(double height) {
    40. this.height = height;
    41. }
    42. @Override
    43. public String toString() {
    44. return "Student{" +
    45. "name='" + name + '\'' +
    46. ", age=" + age +
    47. ", height=" + height +
    48. '}';
    49. }
    50. }

    这样就只会有一个蜘蛛精留下了↓

    篇幅问题,这篇博客到此结束了,下一篇文章我会详细介绍JDK8前后的两种哈希表,需要的朋友可以留意一下~

  • 相关阅读:
    CentOS 8 通过YUM方式升级最新内核
    c++运算符重载
    Sharding-JDBC实现分库分表
    虚拟机配置完NAT模式之后可以和主机ping通但是ping 百度显示:网络不可达
    web前端期末大作业——HTML+CSS+JavaScript仿王者荣耀游戏网站设计与制作
    Harmony装饰器
    【剑指offer】---数组中的重复数字
    Laravel Macroable
    SQL面试题之区间合并问题
    Linux:gcc编译器
  • 原文地址:https://blog.csdn.net/Pretty_TokaiTeio/article/details/134299078