集合:set接口及其實現類(HashSet、TreeSet底層結構)


1、set接口

(1)特點

  • 元素不能重復(equals判斷)
  • 無序
    @Test
    public void test1() {
        Set set=new HashSet();
        set.add("zhai");
        set.add("123");
        set.add("null");
        set.add("123");
        set.add("90");
        System.out.println(set);
    }
[123, null, 90, zhai]

注意:Treeset不允許添加null元素

(2)特有方法

沒有特有方法,主要是從collection接口繼承來的

(3)遍歷方式

和collection接口的遍歷方式相同:迭代器、增強for

 

2、HashSet底層結構

(1)底層結構

  • 哈希表
public HashSet() {
        map = new HashMap<>();
    }

因為HashSet維護的是一個HashMap對象,而HashMap維護的是一個哈希表,兩者都是基於hash結構的。二者在Java里有着相同的實現,前者僅僅是對后者做了一層包裝,也就是說HashSet里面有一個HashMap(適配器模式)

  • 無序:根據哈希值確定元素在哈希表中的位置

(2)去除重復原理

 原理:

先獲取元素的哈希值,通過一些運算獲取一個整數索引index(要存放在數組的位置)

如果索引處沒有元素,則直接添加

如果索引處有其他元素,則需要進行equals判斷,如果不相等,則以鏈表的形式追加到已有元素的后面並返回true,如果相等則直接覆蓋並返回false

如果不是哈希表的結構,需要進行大量的equals判斷,哈希表的使用大大減少了equals的使用

 

重寫equals與hashCode方法(https://www.cnblogs.com/zhai1997/p/11354885.html

存儲已經存在的數據類型的數據,不用重寫equals和hashcode方法,即可去除重復元素

存儲自定義類型的數據需要重寫equals和hashcode方法

 

3、TreeSet底層結構

(1)底層結構

基於map對象(TreeMap),treeMap的底層是紅黑樹的結構,可以實現對元素的排序。TreeSet是對TreeMap的簡單包裝,對TreeSet的函數調用都會轉換成合適的TreeMap方法

(2)特點

  • 不允許重復
  • 可以實現對里面的元素進行排序(自然排序、定制排序)

  •  紅黑樹存儲的時候是左邊的存較小的元素,右邊存儲較大的元素,取出的時候可以按順序取出,先取出20,然后25... ...
  • 紅黑樹與二叉樹的不同是,紅黑樹給二叉樹標記了顏色,例如:左邊紅色右邊黑色,當左邊的紅色元素過多右邊黑色元素過少的時候,紅黑樹就失去了平衡,此時就要重新打亂順序重新選出根元素,使得兩邊保持平衡
  • 紅黑樹是二叉樹的一種

(3)TreeSet的使用

 @Test
    public void test1() {
        Set set=new TreeSet();
        set.add(new Student("zhai",12));
        set.add(new Student("zz",13));
        set.add(new Student("zhang",14));
        set.add(new Student("liu",19));
        set.add(new Student("zhang",14));
        for (Object s: set){
            System.out.println(s);
        }
    }
java.lang.ClassCastException: com.zhb.domain.Student cannot be cast to java.lang.Comparable

報錯的類型是類型轉換異常,原因是添加元素的時候在確定元素在二叉樹中的位置的時候,需要當前元素與結點元素進行比較,小的左,大的右,相等的話不添加,但是對象不具有比較性,因此報錯

要讓其具有比較性有兩種方法:

自然排序:

public class Student implements Comparable{
    public String sname;
    public int age;

    @Override
    public String toString() {
        return "Student{" +
                "sname='" + sname + '\'' +
                ", age=" + age +
                '}';
    }

    public Student(String sname, int age) {
        this.sname = sname;
        this.age = age;
    }

    public String getSname() {
        return sname;
    }

    public void setSname(String sname) {
        this.sname = sname;
    }

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }


    @Override
    public int compareTo(Object o) {
        Student s=(Student)o;
        return Integer.compare(this.age,s.age);
    }
}
Student{sname='zhai', age=12}
Student{sname='zz', age=13}
Student{sname='zhang', age=14}
Student{sname='liu', age=19}

此方法需要實現接口重寫方法

定制排序:

 @Test
    public void test1() {
        Set set=new TreeSet(new Comparator() {
            @Override
            public int compare(Object o1, Object o2) {
                Student s1=(Student)o1;
                Student s2=(Student)o2;
                return Integer.compare(s1.getAge(),s2.getAge());
            }
        });
        set.add(new Student("zhai",12));
        set.add(new Student("zz",13));
        set.add(new Student("zhang",14));
        set.add(new Student("liu",19));
        set.add(new Student("zhang",14));
        for (Object s: set){
            System.out.println(s);
        }
    }
Student{sname='zhai', age=12}
Student{sname='zz', age=13}
Student{sname='zhang', age=14}
Student{sname='liu', age=19}

在定義TreeSet的同時定義比較器

(4)添加方法原理

底層是treemap的添加:

 進行元素的比較:

 調用的比較器:

(5)如何實現去重

  通過比較方法(compareTo方法)的返回值是否為0來判斷元素是否重復。一般Set會比較equals和hashCode。而TreeSet還會比較compareTo,先調用compareTo並通過二分法將元素排列以后,再調用equals和hashCode來判斷和當前排列位置的元素是否一致

 

4、LinkedHashSet

  LinkedHashSetLinkedHashMap在Java里也有着相同的實現,前者僅僅是對后者做了一層包裝,也就是說LinkedHashSet里面有一個LinkedHashMap(適配器模式)

結構:哈希表,鏈表部分是雙向鏈表

好處:保證迭代順序跟插入順序相同、迭代時間就只跟entry的個數相關,而跟table的大小無關

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM