天天看點

JAVA基礎再回首(十七)——Set集合、增強for、HashSet類、LinkedHashSet類、TreeSet類、二叉樹、Comparator 排序JAVA基礎再回首(十七)——Set集合、增強for、HashSet類、LinkedHashSet類、TreeSet類、二叉樹、Comparator 排序

JAVA基礎再回首(十七)——Set集合、增強for、HashSet類、LinkedHashSet類、TreeSet類、二叉樹、Comparator 排序

版權聲明:轉載必須注明本文轉自程式員杜鵬程的部落格:http://blog.csdn.net/m366917

前面我們學習了集合架構的List集合,根據前面我畫的集合架構的圖,可以看到還有Set集合和Map集合我們沒有學習,這篇我們就來學習Set集合。
  • Set
    • 元素是無序(存儲順序和取出順序不一緻),元素是唯一的,不可重複的

我們來看一下API

JAVA基礎再回首(十七)——Set集合、增強for、HashSet類、LinkedHashSet類、TreeSet類、二叉樹、Comparator 排序JAVA基礎再回首(十七)——Set集合、增強for、HashSet類、LinkedHashSet類、TreeSet類、二叉樹、Comparator 排序
我們寫一個簡單的Demo看看它的元素是不是無序和唯一的
public class SetDemo {
    public static void main(String[] args) {
        // 建立集合對象
        Set<String> set = new HashSet<String>();

        // 建立并添加元素
        set.add("hello");
        set.add("java");
        set.add("world");
        set.add("java");
        set.add("world");

        // 增強for周遊
        for (String s : set) {
            System.out.println(s);
        }
        //疊代器周遊
        Iterator it = set.iterator();
        while(it.hasNext()){
            System.out.println(it.next());
        }
    }
}
           
我們先來看結果:
JAVA基礎再回首(十七)——Set集合、增強for、HashSet類、LinkedHashSet類、TreeSet類、二叉樹、Comparator 排序JAVA基礎再回首(十七)——Set集合、增強for、HashSet類、LinkedHashSet類、TreeSet類、二叉樹、Comparator 排序

在這裡想給大家說一個要注意的地方

雖然Set集合的元素無序,但是,作為集合來說,它肯定有它自己的存儲順序,而你的順序恰好和它的存儲順序一緻,這代表不了有序,你可以多存儲一些資料,就能看到效果。

上面我們使用了兩種周遊的方式,用了增強的for循環和疊代器來周遊,前面我們學List集合的時候,我們還用了普通的for循環,但是在這裡不能用普通的for循環了,疊代器周遊我們前面都學過,那我在下面就簡單的提一下增強的for循環的簡單使用。

增強for

增強for:是for循環的一種。
格式:
    for(元素資料類型 變量 : 數組或者Collection集合) {
        使用變量即可,該變量就是元素
    }
           

好處:簡化了數組和集合的周遊。

弊端: 增強for的目标不能為null。

如何解決呢?對增強for的目标先進行不為null的判斷,然後在使用。

HashSet類

什麼是HashSet?我們先來了解他的概述
  • HashSet類概述
    • 不保證 set 的疊代順序
    • 特别是它不保證該順序恒久不變。
  • HashSet如何保證元素唯一性
    • 底層資料結構是哈希表(元素是連結清單的數組)
    • 哈希表依賴于哈希值存儲
    • 添加功能底層依賴兩個方法:
      • int hashCode()
      • boolean equals(Object obj)
public class HashSetDemo {
    public static void main(String[] args) {
        // 建立集合對象
        HashSet<String> hs = new HashSet<String>();

        // 建立并添加元素
        hs.add("hello");
        hs.add("world");
        hs.add("java");
        hs.add("world");

        // 周遊集合(這裡可以用增強for也可以用疊代器,但是增強for比較簡單點)
        for (String s : hs) {
            System.out.println(s);
        }
    }
}
           
輸出結果:
JAVA基礎再回首(十七)——Set集合、增強for、HashSet類、LinkedHashSet類、TreeSet類、二叉樹、Comparator 排序JAVA基礎再回首(十七)——Set集合、增強for、HashSet類、LinkedHashSet類、TreeSet類、二叉樹、Comparator 排序
為什麼存儲字元串的時候,字元串内容相同的隻存儲了一個呢?

我們可以檢視add方法的源碼,就可以知道這個方法底層依賴 兩個方法:hashCode()和equals()。

  • 步驟:
    • 首先比較哈希值
    • 如果相同,繼續走,比較位址值或者走equals()
    • 如果不同,就直接添加到集合中
  • 按照方法的步驟來說:
    • 先看hashCode()值是否相同
    • 相同:繼續走equals()方法
    • 傳回true: 說明元素重複,就不添加
    • 傳回false:說明元素不重複,就添加到集合
    • 不同:就直接把元素添加到集合
  • 如果類沒有重寫這兩個方法,預設使用的Object()。一般來說不同相同。
  • 而String類重寫了hashCode()和equals()方法,是以,它就可以把内容相同的字元串去掉。隻留下一個。

存儲自定義對象

我們存儲自定義對象,并保證元素的唯一性,

要求:如果兩個對象的成員變量值都相同,則為同一個元素。

public class HashSetDemo {
    public static void main(String[] args) {
        // 建立集合對象
        HashSet<Student> hs = new HashSet<Student>();

        // 建立學生對象
        Student s1 = new Student("朱婷", );
        Student s2 = new Student("惠若琪", );
        Student s3 = new Student("徐雲麗", );
        Student s4 = new Student("朱婷", );
        Student s5 = new Student("郎平", );
        Student s6 = new Student("郎平", );

        // 添加元素
        hs.add(s1);
        hs.add(s2);
        hs.add(s3);
        hs.add(s4);
        hs.add(s5);
        hs.add(s6);

        // 周遊集合
        for (Student s : hs) {
            System.out.println(s.getName() + "---" + s.getAge());
        }
    }
}

/**
 * 存儲對象
 */
public class Student {
    private String name;
    private int age;

    public Student() {
        super();
    }

    public Student(String name, int age) {
        super();
        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;
    }
}
           
輸出結果:
JAVA基礎再回首(十七)——Set集合、增強for、HashSet類、LinkedHashSet類、TreeSet類、二叉樹、Comparator 排序JAVA基礎再回首(十七)——Set集合、增強for、HashSet類、LinkedHashSet類、TreeSet類、二叉樹、Comparator 排序

我們看輸出結果,很明顯不符合我的要求。

因為我們知道HashSet底層依賴的是hashCode()和equals()方法。

而這兩個方法我們在學生類中沒有重寫,是以,預設使用的是Object類。

這個時候,他們的哈希值是不會一樣的,根本就不會繼續判斷,執行了添加操作。

是以我們要在Student類中重寫hashCode()和equals()這兩個方法

這兩個方法都是重寫的,不用自己去寫

@Override
    public int hashCode() {
        final int prime = ;
        int result = ;
        result = prime * result + age;
        result = prime * result + ((name == null) ?  : name.hashCode());
        return result;
    }

    @Override
    public boolean equals(Object obj) {
        if (this == obj)
            return true;
        if (obj == null)
            return false;
        if (getClass() != obj.getClass())
            return false;
        Student other = (Student) obj;
        if (age != other.age)
            return false;
        if (name == null) {
            if (other.name != null)
                return false;
        } else if (!name.equals(other.name))
            return false;
        return true;
    }
           
然後我們運作程式,會出現以下結果,你會發現,符合了我們的要求
JAVA基礎再回首(十七)——Set集合、增強for、HashSet類、LinkedHashSet類、TreeSet類、二叉樹、Comparator 排序JAVA基礎再回首(十七)——Set集合、增強for、HashSet類、LinkedHashSet類、TreeSet類、二叉樹、Comparator 排序

LinkedHashSet類

  • 概述
    • 底層資料結構由哈希表和連結清單組成
    • 由連結清單保證元素有序(存儲和取出是一緻)
    • 由哈希表保證元素唯一性
      我們做個小練習來了解它
public class LinkedHashSetDemo {
    public static void main(String[] args) {
        // 建立集合對象
        LinkedHashSet<String> hs = new LinkedHashSet<String>();

        // 建立并添加元素
        hs.add("hello");
        hs.add("world");
        hs.add("java");
        hs.add("world");
        hs.add("java");

        // 周遊
        for (String s : hs) {
            System.out.println(s);
        }
    }
}
           
輸出結果:
JAVA基礎再回首(十七)——Set集合、增強for、HashSet類、LinkedHashSet類、TreeSet類、二叉樹、Comparator 排序JAVA基礎再回首(十七)——Set集合、增強for、HashSet類、LinkedHashSet類、TreeSet類、二叉樹、Comparator 排序
LinkedHashSet類很好了解,下面我們來繼續學習TreeSet類

TreeSet類

  • 概述
    • 使用元素的自然順序對元素進行排序
    • 或者根據建立 set 時提供的 Comparator 進行排序
      • 是以排序有兩種方式
        • 自然排序
        • 比較器排序
    • 具體取決于使用的構造方法。
我們先建立集合對象,運用自然排序的方式來寫Demo
public class TreeSetDemo {
    public static void main(String[] args) {
        // 建立集合對象
        // 自然順序進行排序
        TreeSet<Integer> ts = new TreeSet<Integer>();

        // 建立元素并添加
        // 20,18,23,22,17,24,19,18,24
        ts.add();
        ts.add();
        ts.add();
        ts.add();
        ts.add();
        ts.add();
        ts.add();
        ts.add();
        ts.add();

        // 周遊
        for (Integer i : ts) {
            System.out.println(i);
        }
    }
}
           
輸出結果:
JAVA基礎再回首(十七)——Set集合、增強for、HashSet類、LinkedHashSet類、TreeSet類、二叉樹、Comparator 排序JAVA基礎再回首(十七)——Set集合、增強for、HashSet類、LinkedHashSet類、TreeSet類、二叉樹、Comparator 排序
我們可以看到它使用元素的自然順序對元素進行了排序
  • TreeSet是如何保證元素的排序和唯一性的
    • 底層資料結構是紅黑樹(紅黑樹是一種自平衡的二叉樹)

下面我們就來學習一下二叉樹

二叉樹

那麼二叉樹是怎麼把元素存進去,又是怎麼取出來的呢?

如果你弄懂了這個問題,那麼你就明白了二叉樹了

我們先來了解元素是如何存儲進去的?

第一個元素存儲的時候,直接作為根節點存儲。

從第二個元素開始,每個元素從根節點開始比較

比根節點元素大,就放在右邊

比根節點元素小,就放在左邊

相等的話就忽略。

我們以上面的存儲的元素20,18,23,22,17,24,19,18,24來畫一個圖幫助大家了解

JAVA基礎再回首(十七)——Set集合、增強for、HashSet類、LinkedHashSet類、TreeSet類、二叉樹、Comparator 排序JAVA基礎再回首(十七)——Set集合、增強for、HashSet類、LinkedHashSet類、TreeSet類、二叉樹、Comparator 排序

元素是如何取出來的呢?

從根節點開始,按照左、中、右的原則依次取出元素即可。

Comparator 排序

上面我們學習了自然排序,接下來我們來學習比較器排序。
/*
 * 需求:請按照姓名的長度排序
 */
public class TreeSetDemo {
    public static void main(String[] args) {
        // 建立集合對象
        TreeSet<Student> ts = new TreeSet<Student>();

        // 建立元素
        Student s1 = new Student("朱婷", );
        Student s2 = new Student("惠若琪", );
        Student s3 = new Student("徐雲麗", );
        Student s4 = new Student("朱婷婷", );
        Student s5 = new Student("郎平", );
        Student s6 = new Student("林丹", );
        Student s7 = new Student("李宗偉", );
        Student s8 = new Student("阿杜", );

        // 添加元素
        ts.add(s1);
        ts.add(s2);
        ts.add(s3);
        ts.add(s4);
        ts.add(s5);
        ts.add(s6);
        ts.add(s7);
        ts.add(s8);

        // 周遊
        for (Student s : ts) {
            System.out.println(s.getName() + "---" + s.getAge());
        }
    }
}
/*
 * 如果一個類的元素要想能夠進行自然排序,就必須實作自然排序接口
 */
public class Student implements Comparable<Student> {
    private String name;
    private int age;

    public Student() {
        super();
    }

    public Student(String name, int age) {
        super();
        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 int compareTo(Student s) {
        // 主要條件 姓名的長度
        int num = this.name.length() - s.name.length();
        // 姓名的長度相同,不代表姓名的内容相同
        int num2 = num ==  ? this.name.compareTo(s.name) : num;
        // 姓名的長度和内容相同,不代表年齡相同,是以還得繼續判斷年齡
        int num3 = num2 ==  ? this.age - s.age : num2;
        return num3;
    }
}
           
輸出結果:
JAVA基礎再回首(十七)——Set集合、增強for、HashSet類、LinkedHashSet類、TreeSet類、二叉樹、Comparator 排序JAVA基礎再回首(十七)——Set集合、增強for、HashSet類、LinkedHashSet類、TreeSet類、二叉樹、Comparator 排序
我們就總結了以下幾點内容
  • TreeSet集合保證元素排序和唯一性的原理
  • 唯一性:是根據比較的傳回是否是0來決定。
  • 排序:
    • A:自然排序(元素具備比較性)
      • 讓元素所屬的類實作自然排序接口 Comparable
    • B:比較器排序(集合具備比較性)
      • 讓集合的構造方法接收一個比較器接口的子類對象 Comparator

最後,我們在做一個聯系題吧

擷取10個1至20的随機數,要求随機數不能重複。

我們先來分析一下:

  • A:建立随機數對象
  • B:建立一個HashSet集合
  • C:判斷集合的長度是不是小于10
    • 是:就建立一個随機數添加
    • 否:不理它
  • D:周遊HashSet集合

知道了思路,那就開始寫吧!

public class HashSetDemo {
    public static void main(String[] args) {
        // 建立随機數對象
        Random r = new Random();

        // 建立一個Set集合
        HashSet<Integer> ts = new HashSet<Integer>();

        // 判斷集合的長度是不是小于10
        while (ts.size() < ) {
            int num = r.nextInt() + ;
            ts.add(num);
        }

        // 周遊Set集合
        for (Integer i : ts) {
            System.out.println(i);
        }
    }
}
           
運作程式,每次都會得到10個1-20以内的随機數

好了,這篇我們講了Set集合和它的子類,沒有掌握的,再好好了解一下,下篇我們學習Map集合。

歡迎有興趣的同學加我朋友的QQ群:點選直接加群555974449 請備注:java基礎再回首我們一起來玩吧。