Java中Set集合、增強(qiáng)for草描、HashSet類(lèi)览绿、LinkedHashSet類(lèi)、TreeSet類(lèi)穗慕、二叉樹(shù)饿敲、Comparator 排序

Set
- 元素是無(wú)序(存儲(chǔ)順序和取出順序不一致),元素是唯一的,不可重復(fù)的
我們來(lái)看一下API


這里寫(xiě)圖片描述

我們寫(xiě)一個(gè)簡(jiǎn)單的Demo看看它的元素是不是無(wú)序和唯一的

public class SetDemo { 
       public static void main(String[] args) {
           // 創(chuàng)建集合對(duì)象 
         Set<String> set = new HashSet<String>();
          // 創(chuàng)建并添加元素
         set.add("hello");
         set.add("java");
         set.add("world");
         set.add("java"); 
         set.add("world"); 
         // 增強(qiáng)for遍歷 
         for (String s : set) {
               System.out.println(s); 
         } 
        //迭代器遍歷 
        Iterator it = set.iterator(); 
        while(it.hasNext()){ 
                System.out.println(it.next()); 
        }
    }
}

我們先來(lái)看結(jié)果:

這里寫(xiě)圖片描述

在這里想給大家說(shuō)一個(gè)要注意的地方雖然Set集合的元素?zé)o序逛绵,但是怀各,作為集合來(lái)說(shuō),它肯定有它自己的存儲(chǔ)順序术浪,而你的順序恰好和它的存儲(chǔ)順序一致瓢对,這代表不了有序,你可以多存儲(chǔ)一些數(shù)據(jù)胰苏,就能看到效果硕蛹。

  • 增強(qiáng)for
    增強(qiáng)for:是for循環(huán)的一種。
  格式: 
           for(元素?cái)?shù)據(jù)類(lèi)型 變量 : 數(shù)組或者Collection集合) { 
                   使用變量即可硕并,該變量就是元素 
           }

好處:簡(jiǎn)化了數(shù)組和集合的遍歷法焰。弊端: 增強(qiáng)for的目標(biāo)不能為null。如何解決呢?對(duì)增強(qiáng)for的目標(biāo)先進(jìn)行不為null的判斷倔毙,然后在使用壶栋。


HashSet類(lèi)

什么是HashSet?我們先來(lái)了解他的概述

  • HashSet類(lèi)概述

    • 不保證 set 的迭代順序
    • 特別是它不保證該順序恒久不變普监。
  • HashSet如何保證元素唯一性

    • 底層數(shù)據(jù)結(jié)構(gòu)是哈希表(元素是鏈表的數(shù)組)
    • 哈希表依賴(lài)于哈希值存儲(chǔ)
    • 添加功能底層依賴(lài)兩個(gè)方法:
      • int hashCode()
      • boolean equals(Object obj)
public class HashSetDemo { 
      public static void main(String[] args) { 
          // 創(chuàng)建集合對(duì)象 
          HashSet<String> hs = new HashSet<String>(); 
         // 創(chuàng)建并添加元素 
          hs.add("hello");
          hs.add("world"); 
          hs.add("java"); 
          hs.add("world"); 
         // 遍歷集合(這里可以用增強(qiáng)for也可以用迭代器贵试,但是增強(qiáng)for比較簡(jiǎn)單點(diǎn)) 
          for (String s : hs) { 
               System.out.println(s); 
         } 
   }
}

輸出結(jié)果:
這里寫(xiě)圖片描述

為什么存儲(chǔ)字符串的時(shí)候,字符串內(nèi)容相同的只存儲(chǔ)了一個(gè)呢?

我們可以查看add方法的源碼凯正,就可以知道這個(gè)方法底層依賴(lài) 兩個(gè)方法:hashCode()和equals()毙玻。

    步驟:
        首先比較哈希值
        如果相同,繼續(xù)走廊散,比較地址值或者走equals()
        如果不同,就直接添加到集合中 
    按照方法的步驟來(lái)說(shuō):
        先看hashCode()值是否相同
        相同:繼續(xù)走equals()方法
        返回true: 說(shuō)明元素重復(fù)桑滩,就不添加
        返回false:說(shuō)明元素不重復(fù),就添加到集合
        不同:就直接把元素添加到集合
    如果類(lèi)沒(méi)有重寫(xiě)這兩個(gè)方法允睹,默認(rèn)使用的Object()运准。一般來(lái)說(shuō)不同相同幌氮。
    而String類(lèi)重寫(xiě)了hashCode()和equals()方法,所以胁澳,它就可以把內(nèi)容相同的字符串去掉该互。只留下一個(gè)。

存儲(chǔ)自定義對(duì)象

我們存儲(chǔ)自定義對(duì)象韭畸,并保證元素的唯一性宇智,
要求:如果兩個(gè)對(duì)象的成員變量值都相同,則為同一個(gè)元素胰丁。

public class HashSetDemo { 
          public static void main(String[] args) { 
                 // 創(chuàng)建集合對(duì)象 HashSet<Student> 
                hs = new HashSet<Student>(); 
                 // 創(chuàng)建學(xué)生對(duì)象 
               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());
              }
    }
}
/** * 存儲(chǔ)對(duì)象 */
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;
   }
}

輸出結(jié)果:
這里寫(xiě)圖片描述

我們看輸出結(jié)果随橘,很明顯不符合我的要求。因?yàn)槲覀冎繦ashSet底層依賴(lài)的是hashCode()和equals()方法锦庸。而這兩個(gè)方法我們?cè)趯W(xué)生類(lèi)中沒(méi)有重寫(xiě)机蔗,所以,默認(rèn)使用的是Object類(lèi)甘萧。這個(gè)時(shí)候蜒车,他們的哈希值是不會(huì)一樣的,根本就不會(huì)繼續(xù)判斷幔嗦,執(zhí)行了添加操作酿愧。

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

@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類(lèi)

  • 概述
    • 底層數(shù)據(jù)結(jié)構(gòu)由哈希表和鏈表組成
    • 由鏈表保證元素有序(存儲(chǔ)和取出是一致)
    • 由哈希表保證元素唯一性
public class LinkedHashSetDemo { 
        public static void main(String[] args) {
                // 創(chuàng)建集合對(duì)象
               LinkedHashSet<String> hs = new LinkedHashSet<String>();
               // 創(chuàng)建并添加元素
              hs.add("hello");
              hs.add("world");
              hs.add("java");
              hs.add("world");
              hs.add("java"); 
              // 遍歷
              for (String s : hs) { 
                    System.out.println(s);
              }
     }
}

TreeSet類(lèi)

  • 概述
    • 使用元素的自然順序?qū)υ剡M(jìn)行排序
    • 或者根據(jù)創(chuàng)建 set 時(shí)提供的 Comparator 進(jìn)行排序
      • 所以排序有兩種方式
        • 自然排序
        • 比較器排序
    • 具體取決于使用的構(gòu)造方法邀泉。
public class TreeSetDemo { 
      public static void main(String[] args) { 
        // 創(chuàng)建集合對(duì)象 
       // 自然順序進(jìn)行排序 
       TreeSet<Integer> ts = new TreeSet<Integer>(); 
      // 創(chuàng)建元素并添加
     // 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是如何保證元素的排序和唯一性的
    • 底層數(shù)據(jù)結(jié)構(gòu)是紅黑樹(shù)(紅黑樹(shù)是一種自平衡的二叉樹(shù))

二叉樹(shù)

那么二叉樹(shù)是怎么把元素存進(jìn)去嬉挡,又是怎么取出來(lái)的呢?
如果你弄懂了這個(gè)問(wèn)題汇恤,那么你就明白了二叉樹(shù)了

我們先來(lái)了解元素是如何存儲(chǔ)進(jìn)去的庞钢?

第一個(gè)元素存儲(chǔ)的時(shí)候,直接作為根節(jié)點(diǎn)存儲(chǔ)因谎。從第二個(gè)元素開(kāi)始基括,每個(gè)元素從根節(jié)點(diǎn)開(kāi)始比較比根節(jié)點(diǎn)元素,就放在右邊比根節(jié)點(diǎn)元素财岔,就放在左邊相等的話就忽略风皿。

我們以上面的存儲(chǔ)的元素20,18,23,22,17,24,19,18,24來(lái)畫(huà)一個(gè)圖幫助大家理解

這里寫(xiě)圖片描述

元素是如何取出來(lái)的呢?

從根節(jié)點(diǎn)開(kāi)始匠璧,按照左桐款、中、右的原則依次取出元素即可夷恍。

Comparator 排序

/* * 需求:請(qǐng)按照姓名的長(zhǎng)度排序 */
public class TreeSetDemo { 
public static void main(String[] args) { 
// 創(chuàng)建集合對(duì)象
 TreeSet<Student> ts = new TreeSet<Student>();
 // 創(chuàng)建元素 
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()); 
       } 
    }
}
/* * 如果一個(gè)類(lèi)的元素要想能夠進(jìn)行自然排序魔眨,就必須實(shí)現(xiàn)自然排序接口 */
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) { 
// 主要條件 姓名的長(zhǎng)度 
int num = this.name.length() - s.name.length(); 
// 姓名的長(zhǎng)度相同,不代表姓名的內(nèi)容相同 
int num2 = num == 0 ? this.name.compareTo(s.name) : num;
 // 姓名的長(zhǎng)度和內(nèi)容相同,不代表年齡相同遏暴,所以還得繼續(xù)判斷年齡 
int num3 = num2 == 0 ? this.age - s.age : num2; 
return num3; 
}
}
  • TreeSet集合保證元素排序和唯一性的原理
  • 唯一性:是根據(jù)比較的返回是否是0來(lái)決定侄刽。
  • 排序:
    • A:自然排序(元素具備比較性)
      • 讓元素所屬的類(lèi)實(shí)現(xiàn)自然排序接口 Comparable
    • B:比較器排序(集合具備比較性)
      • 讓集合的構(gòu)造方法接收一個(gè)比較器接口的子類(lèi)對(duì)象 Comparator
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市朋凉,隨后出現(xiàn)的幾起案子州丹,更是在濱河造成了極大的恐慌,老刑警劉巖侥啤,帶你破解...
    沈念sama閱讀 217,185評(píng)論 6 503
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件当叭,死亡現(xiàn)場(chǎng)離奇詭異盖灸,居然都是意外死亡,警方通過(guò)查閱死者的電腦和手機(jī)赁炎,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,652評(píng)論 3 393
  • 文/潘曉璐 我一進(jìn)店門(mén),熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)钾腺,“玉大人徙垫,你說(shuō)我怎么就攤上這事放棒∫霰ǎ” “怎么了间螟?”我有些...
    開(kāi)封第一講書(shū)人閱讀 163,524評(píng)論 0 353
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)厢破。 經(jīng)常有香客問(wèn)我荣瑟,道長(zhǎng),這世上最難降的妖魔是什么摩泪? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 58,339評(píng)論 1 293
  • 正文 為了忘掉前任笆焰,我火速辦了婚禮,結(jié)果婚禮上见坑,老公的妹妹穿的比我還像新娘嚷掠。我一直安慰自己,他們只是感情好荞驴,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,387評(píng)論 6 391
  • 文/花漫 我一把揭開(kāi)白布叠国。 她就那樣靜靜地躺著,像睡著了一般戴尸。 火紅的嫁衣襯著肌膚如雪粟焊。 梳的紋絲不亂的頭發(fā)上,一...
    開(kāi)封第一講書(shū)人閱讀 51,287評(píng)論 1 301
  • 那天,我揣著相機(jī)與錄音项棠,去河邊找鬼悲雳。 笑死,一個(gè)胖子當(dāng)著我的面吹牛香追,可吹牛的內(nèi)容都是我干的合瓢。 我是一名探鬼主播,決...
    沈念sama閱讀 40,130評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼透典,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼晴楔!你這毒婦竟也來(lái)了?” 一聲冷哼從身側(cè)響起峭咒,我...
    開(kāi)封第一講書(shū)人閱讀 38,985評(píng)論 0 275
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤税弃,失蹤者是張志新(化名)和其女友劉穎,沒(méi)想到半個(gè)月后凑队,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體则果,經(jīng)...
    沈念sama閱讀 45,420評(píng)論 1 313
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,617評(píng)論 3 334
  • 正文 我和宋清朗相戀三年漩氨,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了西壮。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 39,779評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡叫惊,死狀恐怖款青,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情霍狰,我是刑警寧澤抡草,帶...
    沈念sama閱讀 35,477評(píng)論 5 345
  • 正文 年R本政府宣布,位于F島的核電站蚓耽,受9級(jí)特大地震影響渠牲,放射性物質(zhì)發(fā)生泄漏签杈。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,088評(píng)論 3 328
  • 文/蒙蒙 一答姥、第九天 我趴在偏房一處隱蔽的房頂上張望谚咬。 院中可真熱鬧,春花似錦择卦、人聲如沸郎嫁。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 31,716評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)盔腔。三九已至月褥,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間宁赤,已是汗流浹背。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 32,857評(píng)論 1 269
  • 我被黑心中介騙來(lái)泰國(guó)打工盐杂, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留哆窿,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 47,876評(píng)論 2 370
  • 正文 我出身青樓挚躯,卻偏偏與公主長(zhǎng)得像擦秽,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子感挥,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,700評(píng)論 2 354

推薦閱讀更多精彩內(nèi)容

  • 1. Java基礎(chǔ)部分 基礎(chǔ)部分的順序:基本語(yǔ)法触幼,類(lèi)相關(guān)的語(yǔ)法,內(nèi)部類(lèi)的語(yǔ)法置谦,繼承相關(guān)的語(yǔ)法,異常的語(yǔ)法瘟栖,線程的語(yǔ)...
    子非魚(yú)_t_閱讀 31,625評(píng)論 18 399
  • 1.import static是Java 5增加的功能,就是將Import類(lèi)中的靜態(tài)方法谅阿,可以作為本類(lèi)的靜態(tài)方法來(lái)...
    XLsn0w閱讀 1,222評(píng)論 0 2
  • 一. Java基礎(chǔ)部分.................................................
    wy_sure閱讀 3,810評(píng)論 0 11
  • 上一篇文章介紹了Set集合的通用知識(shí)。Set集合中包含了三個(gè)比較重要的實(shí)現(xiàn)類(lèi):HashSet寓涨、TreeSet和En...
    Ruheng閱讀 15,640評(píng)論 3 57
  • 01 昨天我為自己寫(xiě)了一篇日記,名叫《大四這年奏司,我21歲樟插,后悔沒(méi)早點(diǎn)開(kāi)始努力》。寫(xiě)這篇文的目的很純粹黄锤,記錄下自己寫(xiě)...
    洋芋絲絲閱讀 1,062評(píng)論 56 54