Java編程基礎18——集合(Set集合)

1_HashSet存儲字符串並遍歷

  • A:Set集合概述及特色java

    • 經過API查看便可
  • B:案例演示算法

    • HashSet存儲字符串並遍歷
import java.util.HashSet;
public class Demo1_HashSet {
    public static void main(String[] args) {
        //Set集合,無索引,不能夠重複,無序(存取不一致)
        HashSet<String> hs = new HashSet<>();    //建立HashSet對象
        boolean b1 = hs.add("a");
        boolean b2 = hs.add("a");                //當向Set集合中儲存重複元素的時候返回爲false
        hs.add("b");
        hs.add("c");
        hs.add("d");
        
        System.out.println(hs);                    //HashSet的繼承體現中有重寫toString方法
        System.out.println(b1);
        System.out.println(b2);
        
        for (String string : hs) {                //只要能用迭代器迭代的,就可使用加強for循環遍歷
            System.out.println(string);
        }
    }
}

2_HashSet存儲自定義對象保證元素惟一性

  • A:案例演示數組

    • 存儲自定義對象,並保證元素惟一性。
    • 重寫hashCode()和equals()方法
  • B:畫圖演示dom

    • 畫圖說明比較過程
  • C:代碼優化ide

    • 爲了減小比較,優化hashCode()代碼寫法。
    • 最終版就是自動生成便可。函數

      • 代碼寫的複雜,目的就是爲了少調用equals方法,提升咱們程序運行的效率
  • D:原理優化

    • 1.HashSet原理ui

      • 咱們使用Set集合都是須要去掉重複元素的, 若是在存儲的時候逐個equals()比較, 效率較低;哈希算法提升了去重複的效率, 下降了使用equals()方法的次數
      • 當HashSet調用add()方法存儲對象的時候, 先調用對象的hashCode()方法獲得一個哈希值(如同上火車先有票), 而後在集合中查找是否有哈希值相同的對象this

        • 若是沒有哈希值相同的對象就直接存入集合
        • 若是有哈希值相同的對象, 就和哈希值相同的對象逐個進行equals()比較,比較結果爲false就存入, true則不存
    • 2.將自定義類的對象存入HashSet去重複idea

      • 類中必須重寫hashCode()和equals()方法
      • hashCode(): 屬性相同的對象返回值必須相同, 屬性不一樣的返回值儘可能不一樣(提升效率)
      • equals(): 屬性相同返回true, 屬性不一樣返回false,返回false的時候存儲
import java.util.HashSet;
import net.allidea.bean.Person;
public class Demo1_HashSet {
    public static void main(String[] args) {
        HashSet<Person> hs = new HashSet<>();
        hs.add(new Person("張三",23));
        hs.add(new Person("張三",23));
        hs.add(new Person("李四",24));
        hs.add(new Person("李四",24));
        hs.add(new Person("李四",24));
        
//        System.out.println(hs.size());
        System.out.println(hs);
    }
}
//Person文件
public class Person {
    private String name;
    private int age;
    public Person() {
        super();
    }
    public Person(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 String toString() {
        return "Person [name=" + name + ", age=" + age + "]";
    }
    
    //爲何是31? 1.是質數。2.既不大也不小。3.是2的五次方-1,2向左移動五位
    @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)                        //傳入的對象爲NULL
            return false;
        if (getClass() != obj.getClass())        //判斷兩個對象對應的字節碼文件是不是同一個字節碼
            return false;
        Person other = (Person) obj;            //向下轉型
        if (age != other.age)                    //調用對象的年齡不等於傳入對象的年齡
            return false;
        if (name == null) {                        //調用對象的姓名爲null
            if (other.name != null)
                return false;
        } else if (!name.equals(other.name))    //調用對象的姓名不等於傳入對象的姓名
            return false;
        return true;
    }    
    
/*    @Override
    public boolean equals(Object obj) {
        System.out.println("執行了嗎");
        Person p = (Person)obj;
        return this.name.equals(p.name) && this.age == p.age;
    }
    @Override
    public int hashCode() {
        //return 10;
        //return age;
        final int NUM = 38;
        return name.hashCode() * NUM + age;
    }*/
}

3_LinkedHashSet的概述和使用

  • A:LinkedHashSet的特色(Linked表明的是鏈表實現的,HashSet表明的是屬於HashSet派系的)
  • B:LinkedHashSet的特色

    • 能夠保證怎麼存就怎麼取
    • 1.底層是鏈表實現的,是Set集合中惟一一個能保證怎麼存就怎麼取的集合對象

      • 2.由於是HashSet的子類,因此也保證了元素是惟一的,與HashSet的原理同樣
import java.util.LinkedHashSet;
public class Demo2_LinkedHashSet {
    public static void main(String[] args) {
        LinkedHashSet<String> lhs = new LinkedHashSet<>();
        lhs.add("a");
        lhs.add("a");
        lhs.add("a");
        lhs.add("b");
        lhs.add("c");
        lhs.add("d");
        
        System.out.println(lhs);
    }
}

4_產生10個1-20之間的隨機數要求隨機數不能重複

  • A:案例演示

    • 需求:編寫一個程序,獲取10個1至20的隨機數,要求隨機數不能重複。並把最終的隨機數輸出到控制檯。
import java.util.HashSet;
import java.util.Random;

public class Demo3_test {
    public static void main(String[] args) {
        Random r = new Random();                //1.建立Random隨機數對象
        
        HashSet<Integer> hs = new HashSet<>();    //2.須要存儲10個隨機數,不能重複,用HashSet集合
        
        while(hs.size() < 10) {            //3.若是HashSet的size<10就能夠不斷的存儲,若是>=10就中止存儲
            hs.add(r.nextInt(20) + 1);    //4.經過Random類中的nextInt(n)方法,獲取1-20之間的隨機數,   
        }                                    //並將這些隨機數存儲在HashSet集合中
        for (Integer integer : hs) {            //5.遍歷HashSet
            System.out.println(integer);
        }
    }
}

5_練習

  • 使用Scanner從鍵盤讀取一行輸入,去掉其中重複字符, 打印出不一樣的那些字符
import java.util.HashSet;
import java.util.Scanner;

public class Demo2 {
    public static void main(String[] args) {
        Scanner sc = new Scanner(System.in);        //1.建立Scanner對象
        System.out.println("請輸入一行字符串:");
        HashSet<Character> hs = new HashSet<>();     //2.建立HashSet對象,將字符存儲去掉重複
        String line = sc.nextLine();
        char[] arr = line.toCharArray();            //3.將字符串轉換爲字符數組,獲取每個字符存儲在HashSet集合中,自動去除重複
        
        for (char c : arr) {                        //4.遍歷字符數組
            hs.add(c);
        }
        
        for(Character ch : hs) {                    //5.自動拆箱,遍歷HashSet,打印每個字符
            System.out.println(ch);
        }
    }
}

6_練習

  • 需求: 將集合中的重複元素去掉
import java.util.List;
import java.util.ArrayList;
import java.util.LinkedHashSet;

public class Demo3 {
    public static void main(String[] args) {
        ArrayList<String> list = new ArrayList<>();//1.建立List集合存儲若干個重複元素
        list.add("a");
        list.add("a");
        list.add("b");
        list.add("b");
        list.add("b");
        list.add("c");
        
        getSingle(list);            //2.單獨定義方法去除重複    
        System.out.println(list);    //3.打印List集合
    }
    public static void getSingle(List<String> list) {
        LinkedHashSet<String> lhs = new LinkedHashSet<>();        //1.建立一個LinkedHashSet集合
        lhs.addAll(list);            //2.將List集合中全部的元素添加到LinkedHashSet集合中,去重
        list.clear();                //3.將List集合中的元素清空。
        list.addAll(lhs);            //4.將LinkedHashSet集合中的元素添加回List集合中
    }
}

7_TreeSet存儲Integer類型的元素並遍歷

  • A:案例演示

    • TreeSet存儲Integer類型的元素並遍歷

      • TreeSet是用來對元素進行排序的,一樣也能夠保證元素的惟一
import java.util.TreeSet;
public class Demo3_TreeSet {
    public static void main(String[] args) {
        TreeSet<Integer> ts = new TreeSet<>();
        ts.add(1);
        ts.add(1);
        ts.add(3);
        ts.add(3);
        ts.add(2);
        
        System.out.println(ts);
    }
}

8_TreeSet存儲自定義對象以及保證元素惟一和天然排序的原理

  • A:案例演示

    • 存儲自定義Person對象

      • TreeSet集合是用來對象元素進行排序的,一樣也能夠保證元素的惟一
      • 當compareTo方法返回0的時候,集合中只有一個元素
      • 當compareTo方法返回正數的時候,集合會正序存儲(怎麼存,就怎麼取)
      • 當compareTo方法返回負數的時候,集合會倒序存儲
  • B:TreeSet保證元素惟一和天然排序的原理和圖解

    • 原理

      • 二叉樹——小的存儲在左邊(負數),大的存儲在右邊(正數),相等就不存(返回0)。
      • compareTo方法,在TreeSet集合中如何存儲元素取決於CopareTo方法的返回值
      • 1.返回0,集合中只有一個元素。經過比較不存儲。
      • 2.返回-1,存儲在根元素左邊。集合倒序
      • 3.返回+1,集合怎麼存就怎麼取*/
import java.util.TreeSet;
import net.allidea.bean.Person;
public class Demo3_TreeSet {
    public static void main(String[] args) {
        TreeSet<Person> ts = new TreeSet<>();
        ts.add(new Person("張三",23));
        ts.add(new Person("李四",24));
        ts.add(new Person("李二",24));
        ts.add(new Person("王五",25));
        ts.add(new Person("趙六",46));
        ts.add(new Person("田七",17));
        
        System.out.println(ts);
    }

    private static void demo1() {
        TreeSet<Integer> ts = new TreeSet<>();
        ts.add(1);
        ts.add(1);
        ts.add(3);
        ts.add(3);
        ts.add(2);
        
        System.out.println(ts);
    }
}
//重寫Person文件中的compareTo
    @Override
    public int compareTo(Person o) {
        int num = this.age - o.age;                //年齡是比較的主要條件,姓名是次要條件
        return num == 0 ? this.name.compareTo(o.name) : num;
    }

12_TreeSet存儲自定義對象並遍歷練習1

  • A:案例演示

    • TreeSet存儲自定義對象並遍歷練習1(按照姓名排序)
@Override
    //按照姓名排序
    public int compareTo(Person o) {
        int num = this.name.compareTo(o.name);    
        return num == 0 ? this.age - o.age : num;
    }

13_TreeSet存儲自定義對象並遍歷練習2

  • A:案例演示

    • TreeSet存儲自定義對象並遍歷練習2(按照姓名的長度排序)
@Override
    //按照姓名長度排序
    public int compareTo(Person o) {
        int length = this.name.length() - o.name.length();                //比較長度爲主要條件
        int num = length == 0 ? this.name.compareTo(o.name) : length;    //比較內容爲次要條件
        return num == 0 ? this.age - o.age : num;                        //比較年齡爲次要條件
    }

14_TreeSet保證元素惟一和比較器排序的原理及代碼實現

  • A:案例演示

    • TreeSet保證元素惟一和比較器排序的原理及代碼實現
public static void main(String[] args) {
        //將字符串按照長度排序
        //Comparator c = new CompareBylen();父類指向子類
        TreeSet<String> ts = new TreeSet<>(new CompareByLen());   
        ts.add("aaaaa");
        ts.add("z");
        ts.add("wc");
        ts.add("nab");
        ts.add("cba");
        
        System.out.println(ts);
    }
//比較器
class CompareByLen /*extends Object*/ implements Comparator<String> {
    @Override
    public int compare(String s1, String s2) {    //按照字符串長度比較
        int num = s1.length() - s2.length();    //長度爲主要條件    
        return num == 0 ? s1.compareTo(s2) : num;//內容爲次要條件
    }
}

15_TreeSet原理

  • 1.特色

    • TreeSet是用來排序的, 能夠指定一個順序, 對象存入以後會按照指定的順序排列
  • 2.使用方式

    • a.天然順序(Comparable)

      • TreeSet類的add()方法中會把存入的對象提高爲Comparable類型
      • 調用對象的compareTo()方法和集合中的對象比較
      • 根據compareTo()方法返回的結果進行存儲
    • b.比較器順序(Comparator)

      • 建立TreeSet的時候能夠制定 一個Comparator
      • 若是傳入了Comparator的子類對象, 那麼TreeSet就會按照比較器中的順序排序
      • add()方法內部會自動調用Comparator接口中compare()方法排序
      • 調用的對象是compare方法的第一個參數,集合中的對象是compare方法的第二個參數
    • c.兩種方式的區別

      • TreeSet構造函數什麼都不傳, 默認按照類中Comparable的順序(沒有就報錯ClassCastException)
      • TreeSet若是傳入Comparator, 就優先按照Comparator進行排序

16_練習:集合中有無序且重複的字符串,定義方法,讓其有序(字典順序)且不去重排列。

  • A:匿名內部類

    • 就是內部類的簡化寫法。
  • B:前提:存在一個類或者接口

    • 這裏的類能夠是具體類也能夠是抽象類。
  • C:格式:

    new 接口名(){重寫方法;}
  • D:本質是什麼呢?

    • 是一個繼承了該類或者實現了該接口的子類匿名對象。
import java.util.List;
import java.util.TreeSet;
import java.util.ArrayList;
import java.util.Comparator;

public class Demo4 {
    public static void main(String[] args) {
        //1.定義一個List集合,並存儲重複的無序的字符串
        ArrayList<String> list = new ArrayList<>();
        list.add("aaaa");
        list.add("g");
        list.add("bb");
        list.add("all");
        list.add("ccc");
        list.add("idea");
        list.add("bb");
        list.add("aaaa");
        
        sort(list);                    //2.定義方法對其排序保留重複
        System.out.println(list);    //3.打印List集合
    }

    private static void sort(List<String> list) {
        //1.建立TreeSet集合對象,由於String自己就具有比較功能,可是重複不會保留,因此咱們用比較器
        TreeSet<String> ts = new TreeSet<>(new Comparator<String>() {    //匿名內部類的方法

            @Override
            public int compare(String s1, String s2) {
                int num = s1.compareTo(s2);                            //比較內容
                return num == 0 ? 1 : num;
            }});
        //2.將List集合中全部的元素添加到TreeSet集合中,對其排序,保留重複
        ts.addAll(list);
        //3.清空list集合
        list.clear();
        //4.將TreeSet集合中排好序的元素添加到list中
        list.addAll(ts);
    }
}

17_練習

  • 從鍵盤接收一個字符串, 程序對其中全部字符進行排序,例如鍵盤輸入: helloworld程序打印:dehllloorw
import java.util.Comparator;
import java.util.Scanner;
import java.util.TreeSet;

public class Demo5 {
    public static void main(String[] args) {
        Scanner sc = new Scanner(System.in);
        System.out.println("請輸入一個字符串:");
        String line = sc.nextLine();
        
        //2.將字符串轉換爲字符數組
        char[] arr = line.toCharArray();
        
        //3.定義TreeSet集合,傳入比較器對字符排序,並保留重複
        TreeSet<Character> ts = new TreeSet<>(new Comparator<Character>() {

            @Override
            public int compare(Character c1, Character c2) {
//                int num = c1 - c2;                //自動拆箱
                int num = c1.compareTo(c2);
                return num == 0 ? 1 : num;
            }});
        //4.遍歷字符數組,將每個字符存儲在TreeSet集合中
        for (char c : arr) {
            ts.add(c);                            //自動裝箱
        }
        //5.遍歷TreeSet打印每個字符
        for(Character c : ts) {
            System.out.print(c);
        }
    }
}

18_練習

  • 程序啓動後, 能夠從鍵盤輸入接收多個整數, 直到輸入quit時結束輸入. 把全部輸入的整數倒序排列打印.
import java.util.Comparator;
import java.util.Scanner;
import java.util.TreeSet;
public class Demo6 {
    public static void main(String[] args) {
        Scanner sc = new Scanner(System.in);        //1.建立Scanner對象,鍵盤錄入。
        //2.建立TreeSet集合對象,TreeSet傳入比較器。
        TreeSet<Integer> ts = new TreeSet<>(new Comparator<Integer>() {        //將比較器傳給TreeSet的構造方法

            @Override
            public int compare(Integer i1, Integer i2) {
                int num = i2 - i1;                            //自動拆箱
//                int num = i2.csompareTo(i1);
                return num == 0 ? 1 : num;
            }});
        System.out.println("請輸入一個整數:");
        //3.無限循環接收整數,遇到Quit退出,用字符串的形式接收。
        while(true) {
            String line = sc.nextLine();//將鍵盤錄入的字符串存儲在line中
            if("quit".equals(line)) {//若是字符串常量和變量比較,常量放前面,這樣不會出現空指針異常,變量裏面可能存儲null
                break;
            }
            //4.判斷quit就退出,不是就將其轉換爲Integer,並添加到集合中
            Integer i =  Integer.parseInt(line);//將數字字符串轉換成數字
            ts.add(i);
        }
        //5.遍歷TreeSet集合並打印每個元素。
        for (Integer integer : ts) {
            System.out.print(integer);
        }
    }
}

19_練習

  • 需求:鍵盤錄入5個學生信息(姓名,語文成績,數學成績,英語成績),按照總分從高到低輸出到控制檯。
//1.定義一個學生類
//a.成員變量:姓名,語文成績,數學成績,英語成績,總成績
//b.成員方法:空參有參構造,toString方法,在遍歷集合中的Student對象,打印對象引用的時候會顯示屬性值
public class Student {
    private String name;
    private int chinese;
    private int math;
    private int english;
    private int sum;
    public Student() {
        super();
        
    }
    public Student(String name, int chinese, int math, int english) {
        super();
        this.name = name;
        this.chinese = chinese;
        this.math = math;
        this.english = english;
        this.sum = this.chinese + this.math + this.english;
    }
    public int getSum() {
        return sum;
    }
    
    public String toString() {
        return name + "," + chinese + "," + math + "," + english + "," + sum;
    }
}
import java.util.Comparator;
import java.util.Scanner;
import java.util.TreeSet;

public class Demo7 {
    public static void main(String[] args) {
        //2.鍵盤錄入須要Scanner,建立鍵盤錄入對象
        Scanner sc = new Scanner(System.in);
        System.out.println("請輸入一個學生成績:姓名,語文成績,數學成績,英語成績");
        // 3.建立TreeSet集合對象,在TreeSet的構造函數中傳入比較器,按照總分比較
        TreeSet<Student> ts = new TreeSet<>(new Comparator<Student>() {

            @Override
            public int compare(Student s1, Student s2) {
                int num = s2.getSum() - s1.getSum();
                return num == 0 ? 1 : num;
            }});
        //4.錄入五個學生,以集合中的學生個數爲判斷條件,若是size是小於5就進行存儲
        while(ts.size() < 5) {
            // 5.將錄入的字符串切割,用逗號切割,會返回一個字符串數組,將字符串數組中從第二個元素開始轉換成int數
            String line = sc.nextLine();
            String[] arr = line.split(",");
            
            int chinese = Integer.parseInt(arr[1]);
            int math = Integer.parseInt(arr[2]);
            int english = Integer.parseInt(arr[3]);            
            //6.將轉換後的結果封裝成Student對象,將Student添加到TreeSet集合中
            ts.add(new Student(arr[0], chinese, math, english));
        }
         //7.遍歷TreeSet集合打印每個Student對象
        System.out.println("排序後的學生信息:");
        for (Student s : ts) {
            System.out.println(s);
        }
    }
}

20_總結

  • 1.List

    • a.普通for循環, 使用get(int index)逐個獲取 (Set沒有,由於沒有索引)
    • b.調用iterator()方法獲得Iterator, 使用hasNext()和next()方法
    • c.加強for循環, 只要可使用Iterator的類均可以用
    • d.Vector集合可使用Enumeration的hasMoreElements()和nextElement()方法
  • 2.Set

    • a.調用iterator()方法獲得Iterator, 使用hasNext()和next()方法
    • b.加強for循環, 只要可使用Iterator的類均可以用
  • 3.普通for循環,迭代器,加強for循環不能在遍歷的過程當中刪除
相關文章
相關標籤/搜索