人生苦短我學Java-13-泛型/Set集合/二叉樹
一、泛型
1、什麼是泛型?
引數化型別,就是指在定義泛型的時候,像在定義形參一樣,在使用泛型的時候,需要傳遞資料型別。
泛型不能寫基本資料型別,如int、布林、byte,char等
泛型在編譯後會擦除掉泛型的型別,實際上就可以理解編譯後就沒有了泛型。
寫法:一般用第一種,這樣就不會在idea中有警告了。
ArrayList<String> arr = new ArrayList<String>();
ArrayList<String>arr = new ArrayList<>();
ArrayList<String> arr= new ArrayList();
2、泛型的作用?
避免了強制型別轉換
限制了集合中元素的資料型別
3、自定義泛型類
package com.ppl.object; /* com.ppl.object:學習專案 @user:廣深-小龍 @date:2022/1/22 21:26 */ import java.util.ArrayList; public class Obj_fx { public static void main(String[] args) { // 泛型的使用,下面只能新增string型別 ArrayList<String> arr = new ArrayList(); arr.add("ppl"); arr.add("123"); for (Object o : arr) { System.out.print(o + " "); } // 自定義泛型類 Fx<String> f = new Fx<>(); f.test("只能是string"); // 自定義泛型類+自定義泛型方法 Fx<Integer> f1 = new Fx<>(); f.test(123);// 自定義介面 f.print("asd"); new Fx().print("asd"); new Fx().print(123); new Fx().print(true); } } // 自定義介面 interface If<E> { public abstract void print(E e); } // 自定義泛型類 class Fx<E> implements If<E> { // 自定義泛型方法 public <E> void test(E e) { System.out.println(e); } // 自定義介面, 重寫抽象方法 public void print(E e) { System.out.println(e); } }
4、萬用字元
①List<?> arr2 = new ArrayList<>();
②泛型萬用字元 上限
<? extends 引用型別>
如Number型別,那麼上限可以是數字相關:Integer、Float等子類包含自身,不能是父類如Objcet,或其它型別。
③泛型萬用字元 下限,和上限相反
<? super引用型別>
如Number型別,那麼上限可以是數字相關:父類如Objcet及包含自身,不能是Integer、Float等子類,或其它型別。
二、Set集合
和Collection、List中成員方法一樣,Set集合特點:
- 無序的(存入與取出不一定一致順序)
- 無索引的
- 元素唯一
1、HashSet上程式碼:
package com.ppl.object; /* com.ppl.object:學習專案 @user:廣深-小龍 @date:2022/1/24 21:27 */ import java.util.HashSet; import java.util.Iterator; import java.util.Set; public class Obj_Set { public static void main(String[] args) { Set set = new HashSet(); set.add(123); set.add("123456"); set.add(true); System.out.println(set); // 遍歷,迭代器 Iterator it = set.iterator(); while (it.hasNext()) { System.out.println("迭代器" + it.next()); } // 遍歷,轉陣列 Object[] obj = set.toArray(); for (int i = 0; i < obj.length; i++) { System.out.println("轉陣列" + obj[i]); } // 遍歷,增強for for (Object o : set) { System.out.println("增強for" + o); } } }
2、TreeSet
樹形結構中的:紅黑樹
特點:遍歷和HashSet一致的
- 無序的(存入與取出不一定一致順序)
- 無索引的
- 元素唯一
- 有排序(從小到到)
class MyTreeSet { public void test() { // TreeSet 會按照字典排序,有小到大排序。 TreeSet t = new TreeSet(); t.add("b"); t.add("a"); t.add("c"); // t.add(123); 執行異常。因為字串和integer不能混合排序 TreeSet t1 = new TreeSet(); t1.add(1); t1.add(3); t1.add(2); System.out.println(t); System.out.println(t1); } }
自定義類,如果我們想要使用TreeSet來儲存自定義物件的話,要滿足兩個條件之一才可以正常執行
- 條件一:自然排序Comparable
- 條件二:比較器Comparator
/* add自定義類 如果我們想要使用TreeSet來儲存自定義物件的話,要滿足兩個條件之一才可以正常執行 條件一:自然排序Comparable 如何實現自然排序? 1.自定義類,實現Comparable介面 2.重寫抽象方法compareTo() 3.在compareTo()方法中寫比較規 返回值為0:集合中的元素只有一個 返回值為正數:集合中的元素是正序 返回值為負數:集合中的元素是倒數 條件二:比較器Comparator 如何實現比較器? 1.自定義類 2.建立TreeSet集合物件,在構造方法中傳遞Comparator的物件 3.重寫compare()方法 4.在compare()中寫比較規則 返回值為0:集合中的元素只有一個 返回值為正數:集合中的元素是正序 返回值為負數:集合中的元素是倒數 */ class Person implements Comparable<Person> { // 1.自定義類,實現Comparable介面 private String name; public Person() { } public Person(String name) { super(); this.name = name; return; } // 2.重寫抽象方法compareTo() @Override public int compareTo(Person o) { // return 0; // 只返回一個 // return 1; // 正數 正序 return -1; // 負數 倒序 // 3.在compareTo()方法中寫比較規 } @Override public String toString() { return "Person{" + "name='" + name + '\'' + '}'; } } // 條件二:自定義類 class Person1 { private String name; public Person1() { } public Person1(String name) { super(); this.name = name; } public String getName() { return name; } public void setName(String name) { this.name = name; } @Override public String toString() { return "Person1{" + "name='" + name + '\'' + '}'; } }
三、資料結構:樹形
1、普通二叉樹
- 由根節點組成,只有一個根節點
- 每個節點下最大隻能有2個子節點
- 查詢速度慢,因為要全部遍歷一遍
2、二叉查詢樹
升級版的普通二叉樹
- 由根節點組成,只有一個根節點
- 每個節點下最大隻能有2個子節點
- 比當前值小排列左邊,反之排列右邊
- 查詢速度相對比普通二叉樹快
缺點:如果 元素為:1 2 3 4 5 6 7 8 9
一直排列在右邊是不是也是很長?查詢元素是不是也要遍歷一遍?
肯定是的,只能說非此種情況下,查詢元素相比普通二叉樹速度要快。
3、平衡二叉樹
在二叉查詢樹基礎上,多了:層級高度差不超過1
如出現超出,那麼會發生,左旋或右旋
4、紅黑樹
- 紅黑樹的節點要麼是黑色,要麼是紅色,根節點一定是黑色
- 如果節點為紅色,那麼2個子節點都為黑色,不能連續兩個紅色的節點,如果沒有子節點了,預設指向nil節點(葉子位元組),葉子節點一定是黑色的
- 任何一個節點到其葉子節點的這條件簡單路徑上黑色節點的個數是一樣多的
- 預設新增節點的顏色為紅色
預設節點為紅色,只需要改變一個節點的顏色:
注意:
如果出現兩個紅色節點,需要判斷:
父節點為紅色,看父同級節點(叔叔節點)是紅色還是黑色
a:如果叔叔節點是紅色:父節點由紅變黑,叔叔節點由紅變黑,爺爺由黑變紅,如果爺爺節點是根節點,再由紅變黑。
b:如果叔叔節點是黑色:父節點由紅變黑,爺爺由黑變紅,然後進行左旋或右旋,如果爺爺節點是根節點,再由紅變黑。
由大到小排序:
class SetTest implements Comparable<SetTest> { private int age; public SetTest() { } public SetTest(int age) { super(); this.age = age; } @Override public String toString() { return "SetTest{" + "age=" + age + '}'; } @Override public int compareTo(SetTest o) { int i = o.age - this.age; /* i: 0 去重 i: ≥1 右邊排序 i: ≤1 左邊排序 */ return i; } }
輸出:[SetTest{age=5}, SetTest{age=3}, SetTest{age=1}]
歡迎來大家QQ交流群一起學習:482713805,博主微信+:gogsxl