Java中Set集合、增強for、HashSet類、LinkedHashSet類、TreeSet類、二叉樹、Comparator 排序

Set
- 元素是無序(存儲順序和取出順序不一致),元素是唯一的,不可重復的
我們來看一下API


這里寫圖片描述

我們寫一個簡單的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()); 
        }
    }
}

我們先來看結果:

這里寫圖片描述

在這里想給大家說一個要注意的地方雖然Set集合的元素無序,但是,作為集合來說,它肯定有它自己的存儲順序,而你的順序恰好和它的存儲順序一致,這代表不了有序,你可以多存儲一些數據,就能看到效果。

  • 增強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); 
         } 
   }
}

輸出結果:
這里寫圖片描述

為什么存儲字符串的時候,字符串內容相同的只存儲了一個呢?

我們可以查看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("朱婷", 22); 
               Student s2 = new Student("惠若琪", 22); 
               Student s3 = new Student("徐云麗", 21); 
               Student s4 = new Student("朱婷", 22); 
               Student s5 = new Student("郎平", 55); 
               Student s6 = new Student("郎平", 57); 
               // 添加元素 
               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;
   }
}

輸出結果:
這里寫圖片描述

我們看輸出結果,很明顯不符合我的要求。因為我們知道HashSet底層依賴的是hashCode()和equals()方法。而這兩個方法我們在學生類中沒有重寫,所以,默認使用的是Object類。這個時候,他們的哈希值是不會一樣的,根本就不會繼續判斷,執行了添加操作。

所以我們要在Student類中重寫hashCode()和equals()這兩個方法
這兩個方法都是重寫的,不用自己去寫

@Override 
public int hashCode() { 
        final int prime = 31; 
        int result = 1;
         result = prime * result + age;
        result = prime * result + ((name == null) ? 0 : 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;
 }

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);
              }
     }
}

TreeSet類

  • 概述
    • 使用元素的自然順序對元素進行排序
    • 或者根據創建 set 時提供的 Comparator 進行排序
      • 所以排序有兩種方式
        • 自然排序
        • 比較器排序
    • 具體取決于使用的構造方法。
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(20); ts.add(18); ts.add(23); ts.add(22); ts.add(17); ts.add(24);    
   ts.add(19); ts.add(18); ts.add(24);
    // 遍歷 
    for (Integer i : ts) { 
      System.out.println(i);
    }
  }
}
  • TreeSet是如何保證元素的排序和唯一性的
    • 底層數據結構是紅黑樹(紅黑樹是一種自平衡的二叉樹)

二叉樹

那么二叉樹是怎么把元素存進去,又是怎么取出來的呢?
如果你弄懂了這個問題,那么你就明白了二叉樹了

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

第一個元素存儲的時候,直接作為根節點存儲。從第二個元素開始,每個元素從根節點開始比較比根節點元素,就放在右邊比根節點元素,就放在左邊相等的話就忽略。

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

這里寫圖片描述

元素是如何取出來的呢?

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

Comparator 排序

/* * 需求:請按照姓名的長度排序 */
public class TreeSetDemo { 
public static void main(String[] args) { 
// 創建集合對象
 TreeSet<Student> ts = new TreeSet<Student>();
 // 創建元素 
Student s1 = new Student("朱婷", 22); 
Student s2 = new Student("惠若琪", 22); 
Student s3 = new Student("徐云麗", 21); 
Student s4 = new Student("朱婷婷", 22);
 Student s5 = new Student("郎平", 55); 
Student s6 = new Student("林丹", 34); 
Student s7 = new Student("李宗偉", 33); 
Student s8 = new Student("阿杜", 23); 
// 添加元素 
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 == 0 ? this.name.compareTo(s.name) : num;
 // 姓名的長度和內容相同,不代表年齡相同,所以還得繼續判斷年齡 
int num3 = num2 == 0 ? this.age - s.age : num2; 
return num3; 
}
}
  • TreeSet集合保證元素排序和唯一性的原理
  • 唯一性:是根據比較的返回是否是0來決定。
  • 排序:
    • A:自然排序(元素具備比較性)
      • 讓元素所屬的類實現自然排序接口 Comparable
    • B:比較器排序(集合具備比較性)
      • 讓集合的構造方法接收一個比較器接口的子類對象 Comparator
最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市,隨后出現的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 228,119評論 6 531
  • 序言:濱河連續發生了三起死亡事件,死亡現場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機,發現死者居然都...
    沈念sama閱讀 98,382評論 3 415
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事。” “怎么了?”我有些...
    開封第一講書人閱讀 176,038評論 0 373
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 62,853評論 1 309
  • 正文 為了忘掉前任,我火速辦了婚禮,結果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當我...
    茶點故事閱讀 71,616評論 6 408
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發上,一...
    開封第一講書人閱讀 55,112評論 1 323
  • 那天,我揣著相機與錄音,去河邊找鬼。 笑死,一個胖子當著我的面吹牛,可吹牛的內容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 43,192評論 3 441
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 42,355評論 0 288
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后,有當地人在樹林里發現了一具尸體,經...
    沈念sama閱讀 48,869評論 1 334
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 40,727評論 3 354
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發現自己被綠了。 大學時的朋友給我發了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 42,928評論 1 369
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 38,467評論 5 358
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響,放射性物質發生泄漏。R本人自食惡果不足惜,卻給世界環境...
    茶點故事閱讀 44,165評論 3 347
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 34,570評論 0 26
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 35,813評論 1 282
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個月前我還...
    沈念sama閱讀 51,585評論 3 390
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 47,892評論 2 372

推薦閱讀更多精彩內容

  • 1. Java基礎部分 基礎部分的順序:基本語法,類相關的語法,內部類的語法,繼承相關的語法,異常的語法,線程的語...
    子非魚_t_閱讀 31,711評論 18 399
  • 1.import static是Java 5增加的功能,就是將Import類中的靜態方法,可以作為本類的靜態方法來...
    XLsn0w閱讀 1,252評論 0 2
  • 一. Java基礎部分.................................................
    wy_sure閱讀 3,826評論 0 11
  • 上一篇文章介紹了Set集合的通用知識。Set集合中包含了三個比較重要的實現類:HashSet、TreeSet和En...
    Ruheng閱讀 15,667評論 3 57
  • 01 昨天我為自己寫了一篇日記,名叫《大四這年,我21歲,后悔沒早點開始努力》。寫這篇文的目的很純粹,記錄下自己寫...
    洋芋絲絲閱讀 1,070評論 56 54