红黑树、HashSet、LinkedHashSet底层原理

1. 数据结构(红黑树)

  • 红黑树是一种自平衡的二叉查找树,是计算机科学中用到的一种数据结构。
  • 1972年出现,当时被称之为平衡二叉B树。后来,1978年被修改为如今的”红黑树"。
  • 它是一种特殊的二叉查找树,红黑树的每一个节点上都有存储位表示节点的颜色。
  • 每一个节点可以是红或者黑;红黑树不是高度平衡的,它的平衡是通过“红黑规则”进行实现的。

平衡二叉树: 

        高度平衡。

        当左右子树高度差超过1时,通过旋转保持平衡。

红黑树:

        是一个二叉查找树:
                但是不是高度平衡的。
                条件:特有的红黑规则。

1.1 数据结构(红黑树)红黑规则

        每一个节点或是红色的,或者是黑色的。

        根节点必须是黑色。

        如果一个节点没有子节点或者父节点,则该节点相应的指针属性值为Nil,这些Nil视为叶节点,每个叶节点(Nil)是黑色的。

如果某一个节点是红色,那么它的子节点必须是黑色(不能出现两个红色节点相连的情况)。

        对每一个节点,从该节点到其所有后代叶节点的简单路径上,均包含相同数目的黑色节点。

1.2 数据结构(红黑树)添加节点的规则

默认颜色:添加节点默认是红色的(效率高)

 1.3 数据结构(红黑树)添加节点的规则

        红黑树在添加节点的时候,添加的节点默认是红色的。

2. HashSet

2.1 存储字符串并遍历

利用Set系列的集合,添加字符串,并使用多种方式遍历。

        迭代器

        增强for

        Lambda表达式

import java.util.HashSet;
import java.util.Set;

public class A01_SetDemo1 {
    public static void main(String[] args) {
       /*
           利用Set系列的集合,添加字符串,并使用多种方式遍历。
            迭代器
            增强for
            Lambda表达式

        */


        //1.创建一个Set集合的对象
        Set<String> s = new HashSet<>();

        //2,添加元素
        //如果当前元素是第一次添加,那么可以添加成功,返回true
        //如果当前元素是第二次添加,那么添加失败,返回false
        s.add("张三");
        s.add("张三");
        s.add("李四");
        s.add("王五");

        //3.打印集合
        //无序
        //System.out.println(s);//[李四, 张三, 王五]

        //迭代器遍历
       /* Iterator<String> it = s.iterator();
        while (it.hasNext()){
            String str = it.next();
            System.out.println(str);
        }
*/

        //增强for
       /* for (String str : s) {
            System.out.println(str);
        }*/

        // Lambda表达式
        s.forEach( str->System.out.println(str));


    }
}

2.2 HashSet底层原理

  •  HashSet集合底层采取哈希表存储数据
  •  哈希表是一种对于增删改查数据性能都较好的结构

2.3 哈希表组成

  • JDK8之前:数组+链表
  • JDK8开始:数组+链表+红黑树

2.4 哈希值

哈希值:对象的整数表现形式

  •  根据hashCode方法算出来的int类型的整数
  • 该方法定义在Object类中,所有对象都可以调用,默认使用地址值进行计算
  • 一般情况下,会重写hashCode方法,利用对象内部的属性值计算哈希值

2.5 对象的哈希值特点

  • 如果没有重写hashCode方法,不同对象计算出的哈希值是不同的
  • 如果已经重写hashcode方法,不同的对象只要属性值相同,计算出的哈希值就是一样的
  • 在小部分情况下,不同的属性值或者不同的地址值计算出来的哈希值也有可能一样。(哈希碰撞)
public class A02_HashSetDemo1 {
    public static void main(String[] args) {
        /*
            哈希值:
                对象的整数表现形式
                1. 如果没有重写hashCode方法,不同对象计算出的哈希值是不同的
                2. 如果已经重写hashcode方法,不同的对象只要属性值相同,计算出的哈希值就是一样的
                3. 但是在小部分情况下,不同的属性值或者不同的地址值计算出来的哈希值也有可能一样。(哈希碰撞)

         */

        //1.创建对象
        Student s1 = new Student("zhangsan",23);
        Student s2 = new Student("zhangsan",23);

        //2.如果没有重写hashCode方法,不同对象计算出的哈希值是不同的
        //  如果已经重写hashcode方法,不同的对象只要属性值相同,计算出的哈希值就是一样的
        System.out.println(s1.hashCode());//-1461067292
        System.out.println(s2.hashCode());//-1461067292


        //在小部分情况下,不同的属性值或者不同的地址值计算出来的哈希值也有可能一样。
        //哈希碰撞
        System.out.println("abc".hashCode());//96354
        System.out.println("acD".hashCode());//96354

    }
}

2.6 HashSetJDK8以前底层原理

        创建一个默认长度16,默认加载因为0.75的数组,数组名table

        根据元素的哈希值跟数组的长度计算出应存入的位置

        判断当前位置是否为null,如果是null直接存入

        如果位置不为null,表示有元素,则调用equals方法比较属性值

        一样:不存           不一样:存入数组,形成链表

                JDK8以前:新元素存入数组,老元素挂在新元素下面

                JDK8以后:新元素直接挂在老元素下面

        int index=(数组长度-1)& 哈希值

2.7 HashSet底层原理

        JDK8以后,当链表长度超过8,而且数组长度大于等于64时,自动转换为红黑树

        如果集合中存储的是自定义对象,必须要重hashCode和equals方法

利用HashSet集合去除重复元素

        需求:创建一个存储学生对象的集合,存储多个学生对象。

        使用程序实现在控制台遍历该集合。

        要求:学生对象的成员变量值相同,我们就认为是同一个对象。

import java.util.HashSet;
public class A03_HashSetDemo2 {
    public static void main(String[] args) {
        /* 需求:创建一个存储学生对象的集合,存储多个学生对象。
            使用程序实现在控制台遍历该集合。
            要求:学生对象的成员变量值相同,我们就认为是同一个对象


        String   Integer
*/
        //1.创建三个学生对象
        Student s1 = new Student("zhangsan",23);
        Student s2 = new Student("lisi",24);
        Student s3 = new Student("wangwu",25);
        Student s4 = new Student("zhangsan",23);


        //2.创建集合用来添加学生
        HashSet<Student> hs = new HashSet<>();

        //3.添加元素
        System.out.println(hs.add(s1));
        System.out.println(hs.add(s2));
        System.out.println(hs.add(s3));
        System.out.println(hs.add(s4));

        //4.打印集合
        System.out.println(hs);
    }
}
import java.util.HashSet;
public class A03_HashSetDemo2 {
    public static void main(String[] args) {
        /* 需求:创建一个存储学生对象的集合,存储多个学生对象。
            使用程序实现在控制台遍历该集合。
            要求:学生对象的成员变量值相同,我们就认为是同一个对象


        String   Integer
*/
        //1.创建三个学生对象
        Student s1 = new Student("zhangsan",23);
        Student s2 = new Student("lisi",24);
        Student s3 = new Student("wangwu",25);
        Student s4 = new Student("zhangsan",23);


        //2.创建集合用来添加学生
        HashSet<Student> hs = new HashSet<>();

        //3.添加元素
        System.out.println(hs.add(s1));
        System.out.println(hs.add(s2));
        System.out.println(hs.add(s3));
        System.out.println(hs.add(s4));

        //4.打印集合
        System.out.println(hs);
    }
}

3. LinkedHashSet底层原理

        有序、不重复、无索引。

        这里的有序指的是保证存储和取出的元素顺序一致。

        原理:底层数据结构是依然哈希表,只是每个元素又额外的多了一个双链表的机制记录存储的顺序。

 

import java.util.LinkedHashSet;
public class A04_LinkedHashSetDemo {
    public static void main(String[] args) {
        //1.创建4个学生对象
        Student s1 = new Student("zhangsan",23);
        Student s2 = new Student("lisi",24);
        Student s3 = new Student("wangwu",25);
        Student s4 = new Student("zhangsan",23);


        //2.创建集合的对象
        LinkedHashSet<Student> lhs = new LinkedHashSet<>();


        //3.添加元素
        System.out.println(lhs.add(s3));
        System.out.println(lhs.add(s2));
        System.out.println(lhs.add(s1));
        System.out.println(lhs.add(s4));

        //4.打印集合
        System.out.println(lhs);
    }
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值