天天看點

59 java集合和泛型_9 _Set實作類 _HashSet

文章目錄

  • ​​Set實作類​​
  • ​​存儲結構:哈希表(散清單)​​
  • ​​HashSet的使用​​
  • ​​HashSet的存儲過程​​
  • ​​HashSet補充​​

Set實作類

  1. HashSet 【重點】 :
  • 基于HashCode計算元素存放位置,實作元素不重複。(存儲結構是一個哈希表)
  • 當存入元素的哈希碼相同時,會調用equals進行确認, 如結果為true, 則拒絕後者存入。
  1. TreeSet:
  • 基于排列順序實作元素不重複。
  • 實作了SortedSet接口,對集合元素自動排序。
  • 元素對象的類型必須實作Comparable接口,指定排序規則。
  • 通過CompareTo方法确定是否為重複元素。

存儲結構:哈希表(散清單)

  1. (Hash table,也叫哈希表),是根據關鍵碼值(Key value)而直接進行通路的​​資料結構​​。也就是說,它通過把關鍵碼值映射到表中一個位置來通路記錄,以加快查找的速度。這個映射函數叫做​​散列函數​​,存放記錄的​​數組​​叫做​​散清單​​。
  2. 給定表M,存在函數f(key),對任意給定的關鍵字值key,代入函數後若能得到包含該關鍵字的記錄在表中的位址,則稱表M為哈希(Hash)表,函數f(key)為哈希(Hash) 函數。
  3. 基本概念:
  • 若關鍵字為k,則其值存放在f(k)的存儲位置上。由此,不需比較便可直接取得所查記錄。稱這個對應關系f為散列函數,按這個思想建立的表為散清單。
  • 對不同的關鍵字可能得到同一散列位址,即k1≠k2,而 f(k1)=f(k2),這種現象稱為沖突(英語:Collision)。具有相同函數值的關鍵字對該散列函數來說稱做同義詞。綜上所述,根據散列函數**f(k)**和處理沖突的方法将一組關鍵字映射到一個有限的連續的位址集(區間)上,并以關鍵字在位址集中的“像”作為記錄在表中的存儲位置,這種表便稱為散清單,這一映射過程稱為散列造表或散列,所得的存儲位置稱散列位址。
  • 若對于關鍵字集合中的任一個關鍵字,經散列函數映象到位址集合中任何一個位址的機率是相等的,則稱此類散列函數為均勻散列函數(Uniform Hash function),這就是使關鍵字經過散列函數得到一個“随機的位址”,進而減少沖突。
  • 59 java集合和泛型_9 _Set實作類 _HashSet

HashSet的使用

代碼1:

package com.wlw.collection.set;

import java.util.HashSet;
import java.util.Iterator;

/**
 * HashSet 的使用
 * 存儲結構:哈希表(數組+連結清單+紅黑樹(jdk1.8之後))
 */
public class HashSet_Demo01 {
    public static void main(String[] args) {

        //建立集合
        HashSet<String> hashSet = new HashSet<>();

        //1.添加
        hashSet.add("阿斯頓");
        hashSet.add("劉德華");
        hashSet.add("護發素");
        hashSet.add("阿薩啊");
        //hashSet.add("劉德華"); //不會再添加
        System.out.println("元素個數:"+hashSet.size());
        System.out.println(hashSet.toString());

        //2.删除
        /*
        hashSet.remove("護發素");
        System.out.println("删除之後,元素個數:"+hashSet.size());
        */

        //3.周遊
        //3.1 增強for
        System.out.println("----------3.1 增強for---------");
        for (String s : hashSet) {
            System.out.println(s);
        }

        //3.2疊代器
        System.out.println("----------3.2疊代器---------");
        Iterator<String> iterator = hashSet.iterator();
        while (iterator.hasNext()){
            String s = iterator.next();
            System.out.println(s);
        }
        
        //4.判斷
        System.out.println(hashSet.contains("hhhhh")); //false
        System.out.println(hashSet.isEmpty()); //false
    }
}
/*
元素個數:4
[阿薩啊, 阿斯頓, 劉德華, 護發素]
----------3.1 增強for---------
阿薩啊
阿斯頓
劉德華
護發素
----------3.2疊代器---------
阿薩啊
阿斯頓
劉德華
護發素
false
false
*/      

代碼2:

package com.wlw.collection.set;

import java.util.HashSet;
import java.util.Iterator;

/**
 * HashSet 的使用
 * 存儲結構:哈希表(數組+連結清單+紅黑樹(jdk1.8之後))
 * 存儲過程(判斷重複依據):
 * (1)根據hashcode計算儲存的位址(數組),如果此位置為空,則直接儲存,如果不為空,執行第二步
 * (2)再執行euqals方法,如果equals方法傳回true,則認為重複,不儲存,否則形成連結清單
 */
public class HashSet_Demo02 {
    public static void main(String[] args) {

        //建立集合
        HashSet<Person> hashSet = new HashSet<>();
        Person p1 = new Person("劉德華",10);
        Person p2 = new Person("林畫圖",20);
        Person p3 = new Person("劉思達",30);

        //1.添加
        hashSet.add(p1);
        hashSet.add(p2);
        hashSet.add(p3);
        //hashSet.add(p3); //重複,不會再添加

        hashSet.add(new Person("劉思達",30));
        /*
            假如,執行這一條語句,我想讓他不加進去(認為和之前p3相同),
            就需要在該類型中重寫hashCode方法與equals方法,
            隻重寫hashCode方法是不行的
         */

        System.out.println("元素個數:"+hashSet.size());
        System.out.println(hashSet.toString());

        //2.删除
        /*
        //hashSet.remove(p1);
        hashSet.remove(new Person("劉德華",10));
        //因為重寫了hashCode方法與equals方法,是以是能删除掉上面的p1的

        System.out.println("删除之後,元素個數:"+hashSet.size());
        */

        //3.周遊
        //3.1 增強for
        System.out.println("----------3.1 增強for---------");
        for (Person person : hashSet) {
            System.out.println(person.toString());
        }

        //3.2疊代器
        System.out.println("----------3.2疊代器---------");
        Iterator<Person> iterator = hashSet.iterator();
        while (iterator.hasNext()){
            Person person = iterator.next();
            System.out.println(person.toString());
        }
        //4.判斷
        System.out.println(hashSet.contains(p1)); //true
        System.out.println(hashSet.isEmpty()); //false
    }
}

/*
元素個數:3
[Person{name='林畫圖', age=20}, Person{name='劉思達', age=30}, Person{name='劉德華', age=10}]
----------3.1 增強for---------
Person{name='林畫圖', age=20}
Person{name='劉思達', age=30}
Person{name='劉德華', age=10}
----------3.2疊代器---------
Person{name='林畫圖', age=20}
Person{name='劉思達', age=30}
Person{name='劉德華', age=10}
true
false
*/      
/*
重寫了hashCode方法與equals方法
*/
package com.wlw.collection.set;

import java.util.Objects;

public class Person {
    private String name;
    private int age;

    //無參構造
    public Person() {
    }

    //有參構造
    public Person(String name, int age) {
        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 +
                '}';
    }

    //自動生成的
    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (o == null || getClass() != o.getClass()) return false;
        Person person = (Person) o;
        return age == person.age &&
                Objects.equals(name, person.name);
    }

    //自動生成的
    @Override
    public int hashCode() {
        return Objects.hash(name, age);
    }

    /* 自己寫的
    @Override
    public int hashCode() {
       int i1 = this.name.hashCode();
       int i2 = this.name.hashCode();
       return i1 + i2;
    }

    @Override
    public boolean equals(Object o) {
        //1.判斷是否一樣
        if (this == o){
            return true;
        }
        //2.判斷是否為空
        if (o == null){
            return false;
        }
        //3.判斷是否是Person類型
        if(this.getClass() == o.getClass()){

        }
        if(o instanceof Person){
            //4.類型轉換
            Person p = (Person) o;
            //5.比較資料
            if(this.name.equals(p.getName()) && this.age == p.getAge()){
                return true;
            }
        }
        return false;

    }
*/


}      

HashSet的存儲過程

存儲過程(判斷重複依據):

(1)根據hashcode計算儲存的位址(數組),如果此位置為空,則直接儲存,如果不為空,執行第二步

HashSet補充

@Override
public int hashCode() {
        return Objects.hash(name, age);
    }

public static int hash(Object... values) {
        return Arrays.hashCode(values);
    }

public static int hashCode(Object a[]) {
        if (a == null)
            return 0;

        int result = 1;

        for (Object element : a)
            result = 31 * result + (element == null ? 0 : element.hashCode());

        return result;
    }

/*
31  這個數
(1)31是一個質數,可以減少散列沖突
(2)31可以提高執行效率, 31*i = (i << 5)-i