文章目錄
- Set實作類
- 存儲結構:哈希表(散清單)
- HashSet的使用
- HashSet的存儲過程
- HashSet補充
Set實作類
- HashSet 【重點】 :
- 基于HashCode計算元素存放位置,實作元素不重複。(存儲結構是一個哈希表)
- 當存入元素的哈希碼相同時,會調用equals進行确認, 如結果為true, 則拒絕後者存入。
- TreeSet:
- 基于排列順序實作元素不重複。
- 實作了SortedSet接口,對集合元素自動排序。
- 元素對象的類型必須實作Comparable接口,指定排序規則。
- 通過CompareTo方法确定是否為重複元素。
存儲結構:哈希表(散清單)
- (Hash table,也叫哈希表),是根據關鍵碼值(Key value)而直接進行通路的資料結構。也就是說,它通過把關鍵碼值映射到表中一個位置來通路記錄,以加快查找的速度。這個映射函數叫做散列函數,存放記錄的數組叫做散清單。
- 給定表M,存在函數f(key),對任意給定的關鍵字值key,代入函數後若能得到包含該關鍵字的記錄在表中的位址,則稱表M為哈希(Hash)表,函數f(key)為哈希(Hash) 函數。
- 基本概念:
- 若關鍵字為k,則其值存放在f(k)的存儲位置上。由此,不需比較便可直接取得所查記錄。稱這個對應關系f為散列函數,按這個思想建立的表為散清單。
- 對不同的關鍵字可能得到同一散列位址,即k1≠k2,而 f(k1)=f(k2),這種現象稱為沖突(英語:Collision)。具有相同函數值的關鍵字對該散列函數來說稱做同義詞。綜上所述,根據散列函數**f(k)**和處理沖突的方法将一組關鍵字映射到一個有限的連續的位址集(區間)上,并以關鍵字在位址集中的“像”作為記錄在表中的存儲位置,這種表便稱為散清單,這一映射過程稱為散列造表或散列,所得的存儲位置稱散列位址。
- 若對于關鍵字集合中的任一個關鍵字,經散列函數映象到位址集合中任何一個位址的機率是相等的,則稱此類散列函數為均勻散列函數(Uniform Hash function),這就是使關鍵字經過散列函數得到一個“随機的位址”,進而減少沖突。
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