[英]HashSet vs. ArrayList
所以我有一個自定義類Class,它將擁有一組另一個自定義類Student。 所以它看起來像這樣:
public class Class {
private Set<Student> students;
// other methods
}
現在我將向學生們添加和刪除許多學生,我也將改變已經在學生集中的學生的許多私人領域。
問題:我應該使用哪種數據結構來實現這一目標? 由於我將更改set student中的Student對象的屬性(從而更改哈希碼),我應該使用ArrayList嗎?
當它涉及ArrayList
和HashSet
的行為時,它們是完全不同的類。
ArrayList
不驗證重復項。 get()
是O(1)
contains()
是O(n)
但您可以完全控制條目的順序。
get add contains next remove(0) iterator.remove ArrayList O(1) O(1) O(n) O(1) O(1) O(1)
不是線程安全的並且為了使線程安全,你必須使用Collections.synchronizedList(...)
HashSet
確保沒有重復項。 給你一個O(1)
contains()
方法,但不保留順序。
add contains next notes HashSet O(1) O(1) O(h/n) h is the table
Collections.synchronizedSet(...)
我應該使用什么數據結構來實現這一目標? 由於我將更改set student中的Student對象的屬性(從而更改哈希碼),我應該使用ArrayList嗎?
如果set元素的哈希碼容易改變,那么你不應該使用HashSet
。 (如果這樣做,數據結構將會中斷,並且集合中的元素可能會丟失。)
但是我懷疑你應該使用ArrayList
,因為如果hashcode()
對對象的更改敏感,那么equals(Object)
很可能也是如此。 這意味着contains(...)
和類似的方法將無法找到對象。
我認為您應該使用Map
類型,並使用“學生標識符”作為鍵。
(你也可以覆蓋hashcode
和equals
這樣相等意味着兩個對象具有相同的id。但這使得equals(Object)
無法用於其他目的。)
如果您的代碼中有重復數據,那么您應該使用ArrayList,否則您可以使用hashset,如下所示。因此,如果您的代碼不需要重復值,則使用Set而不是list,因為該集合將提供更好的性能(O( n)對於列表的O(n ^ 2),這是正常的,因為避免重復是集合的目的。
public static void main(String [] args){
ArrayList arr =new ArrayList();
arr.add("Hello");
arr.add("is");
arr.add("Hello");
System.out.println(arr); //As we are using Arraylist therefore
//the duplicate elements are allowed therefore
//"Hello" is not removed in the output
}
public static void main(String [] args){
HashSet arr =new HashSet();
arr.add("Hello");
arr.add("is");
arr.add("Hello");
System.out.println(arr); //As we are using Hashset therefore
//the duplicate elements removed therefore
//"Hello" is removed in the output
}
這取決於。 當你在談論學生時,必須有像id或rollno這樣獨特的東西。 如果是,則覆蓋哈希碼方法並根據其ID實現哈希碼。 然后通過更改學生的任何其他屬性對哈希碼沒有影響。
選擇Set或List完全取決於您的要求。 閱讀此鏈接,它將闡明Set和list之間的區別
Set和List有什么區別?
如果您正在使用Set中的對象,那么您可以嘗試覆蓋hashcode和equals方法,以便控制唯一性在您手中。
根據您的要求,我認為最好的結構應該是Map。 設置實際底層使用內部的Map結構,並且您還需要注意equals方法覆蓋以獲得更好的查找。 並且set和arraylist發現目標對象需要采用一些查找算法,因此效率不如預期(特別是在非常大的收集情況下)。 即使map會浪費一些空間,但如果你的ID是某種原始類型,你可以考慮Trove庫中原始類型的map實現。
問題:我應該使用哪種數據結構來實現這一目標? 由於我將更改set student中的Student對象的屬性(從而更改哈希碼),我應該使用ArrayList嗎?
當然,如果您要更改hashCode或equals使用的值,則無法使用HashMap或HashSet。
您說要刪除並添加很多內容。 問題是你是想要順序地還是隨機地(基於索引)。 如果你添加,順序刪除,那么肯定最好的選擇是LinkedList。 如果隨機訪問對象,則ArrayList效率更高。
對於散列集合(如HashSet
,密鑰應該是immutable
。 Hashset在內部使用散列來決定存儲對象的存儲桶。 而且在檢索對象時,它將使用哈希來查找對象桶。 如果在存儲后更改對象,則可能會更改對象的哈希碼,而Set可能無法檢索正確的對象。 如果您需要在將對象添加到集合后更改對象,則使用散列集合不是一個好的選擇。 而是選擇Arraylist
,但請注意,使用ArrayList
您將失去快速檢索所需學生的優勢,就像使用Set一樣。
當對象的equals
方法的結果發生變化時,不應使用Set
。 如果您通過穩定的唯一ID號識別學生,並且equals
只檢查該ID,那么使用Set
就可以了。
請注意, HashSet
將使用hashCode
進行索引和比較,而hashCode
應該恰好包含用於確定equals
字段。
Set的javadoc說
注意:如果將可變對象用作set元素,則必須非常小心。 如果在對象是集合中的元素的同時以影響等於比較的方式更改對象的值,則不指定集合的行為。 這種禁令的一個特例是,不允許集合將自身作為一個要素包含在內。
因此,如果您打算使用HashSet
如果您使用inmutable字段創建hashCode()
和equals()
,那么您將不會遇到此問題。 例如,為每個實例使用唯一的studentID。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.