@tcxu 你好,想跟你請教個問題:
package jiu;
/**
*@ClassName HashSetDemo
*
* @Description 測驗HashMapSet集合類
*
* @date 2014-3-3 上午8:45:26
*
*/
import java.util.HashSet;
public class HashSetDemo {
public static void main(String args[]) {
// 創建HashSet物件
HashSet<String> hs = new HashSet<String>();
// 加入元素到HastSet中
hs.add("B");
hs.add("A");
hs.add("D");
hs.add("E");
hs.add("C");
hs.add("F");
System.out.println(hs);
}
}

不是說HashSet是無序的嗎?怎么輸出結果卻有序了?
uj5u.com熱心網友回復:
可以把所有字母全部加入,然后在看看還是不是有序的
uj5u.com熱心網友回復:
HashSet的原理是:計算物件的hash值,并映射到陣列的下標。再看一下String的hashCode()方法的原始碼
哈希值是通過char對應的int值計算出來的,即:char對應的int值越大,hash值就越大。
而在拉丁字母A、B、C、D的char字符對應的int值恰巧是遞增的,所以他們的hash值也恰巧是遞增的,所以最終映射到HashSet內的陣列的位置也是順序的。


uj5u.com熱心網友回復:
是的,HashSet 元素的存盤(地址)是無序的。一般來講,通過進行迭代的迭代器也是依次將各個元素(字串),無序地輸出。
樓主所示的"有序結果",其實是一種極其特殊案例:每個元素都僅是一(單)個字符,或都是數字字符,或都是小寫英文字符,或都是大寫英文字符。
元素的存盤地址,視這個元素的哈希值而定。由于元素僅有一個字符,其哈希值的計算結果,就會是這個給定字符的 ascii 碼(參見: 哈希演算法)的值。結果, 列印出的 HashSet 串列,就會是貌似經過排序后的結果。但要注意構成這種案例的條件:元素必須 都是單個數字字符、或都是單個英文小寫字符、或都是單個英文大寫字符。
下列代碼顯示每個元素的哈希值,以及最終呼叫 toString() 輸出 HashSet hs 的結果。輸出結果顯示,單個字符元素的哈希值,就是它的 ASCII值。
import java.util.HashSet;
public class HashSetDemo {
static void showHashSet(String[] s){
HashSet<String> hs = new HashSet<String>();
for (int i=0;i<s.length;i++){
hs.add(s[i]);
System.out.println(s[i] + "的哈希值:" +s[i].hashCode()+ " ");
}
System.out.println("toString的結果:" + hs);
}
public static void main(String args[]) {
String data[][]=new String[5][6];
String dat[]={
"B","A","D","E","C","F", // 可以列印出貌似排序的結果
"6","4","3","1","2","5", // 可以列印出貌似排序的結果
"BB","AA","DD","EE","CC","FF",
"42","41","45","46","44","43",
"Base","Alberta","Done","End","Coding","Factory"};
for (int i=0;i<dat.length;i++)
data[i/6][i%6]=dat[i];
for (int i=0;i<data.length;i++)
showHashSet(data[i]);
}
}
輸出:
B的哈希值:66
A的哈希值:65
D的哈希值:68
E的哈希值:69
C的哈希值:67
F的哈希值:70
toString的結果:[A, B, C, D, E, F]
6的哈希值:54
4的哈希值:52
3的哈希值:51
1的哈希值:49
2的哈希值:50
5的哈希值:53
toString的結果:[1, 2, 3, 4, 5, 6]
BB的哈希值:2112
AA的哈希值:2080
DD的哈希值:2176
EE的哈希值:2208
CC的哈希值:2144
FF的哈希值:2240
toString的結果:[BB, AA, DD, EE, CC, FF]
42的哈希值:1662
41的哈希值:1661
45的哈希值:1665
46的哈希值:1666
44的哈希值:1664
43的哈希值:1663
toString的結果:[44, 45, 46, 41, 42, 43]
Base的哈希值:2063089
Alberta的哈希值:743772625
Done的哈希值:2135970
End的哈希值:69819
Coding的哈希值:2023747466
Factory的哈希值:572770538
toString的結果:[Done, Alberta, Coding, Factory, End, Base]
uj5u.com熱心網友回復:
hash 是無須的,或者說是不保證有序的。 但多次重新運行下列代碼,亦可看出:每個 Integer 元素的哈希值,就是它的整形數的值。而且 hashset 的輸出結果都是進行排序了的,那hashset 是怎么做到對結果的有順序輸出的呢?
import java.util.HashSet;
import java.lang.Integer;
import java.util.Random;
public class SetOfInteger {
public static void main(String[] args) {
Random random=new Random(47);
HashSet<Integer> intset=new HashSet<Integer>();
for(int i=0;i<1000;i++){
int n = random.nextInt(50);
System.out.print( n + " hashCode: " + new Integer(n).hashCode() + ", ");
intset.add(n);
}
System.out.println("\n" + intset);
}
}
輸出:
回答是: 雖然 hash 有它自己的順序, 但這個順序是hash的順序.不一樣的哈希演算法,順序也是不一樣的。而且有序輸出跟有序存盤是兩碼事。 看來 正如 HashSet能對結果進行排序嗎 的討論指出的那樣, "你需要百度下:資料結構、存盤結構、還有hash鍵值對。總的來說你缺的太多,別一下直接想這么深的問題,先從資料結構開始學" 。
uj5u.com熱心網友回復:
參考來自“wy65”的評論
可以把所有字母全部加入,然后在看看還是不是有序的
試了一下:將所有的單個大寫、部分小寫(a-g)、和部分數字字符(1-6), 作為長度為1的字串,加起來。結果是"大寫字符、小寫字符、和 數字字符,分別升序排列輸出"。只是數字的字串最后出現。
import java.util.HashSet;
public class HashSetDemo_1 {
public static void main(String args[]) {
// 創建HashSet物件
HashSet<String> hs = new HashSet<String>();
// 加入元素到HastSet中
hs.add("3");
hs.add("6");
hs.add("5");
hs.add("4");
hs.add("2");
hs.add("1");
hs.add("b");
hs.add("g");
hs.add("d");
hs.add("e");
hs.add("c");
hs.add("f");
hs.add("B");
hs.add("A");
hs.add("D");
hs.add("E");
hs.add("C");
hs.add("F");
hs.add("X");
hs.add("Y");
hs.add("S");
hs.add("Z");
hs.add("T");
hs.add("V");
hs.add("U");
hs.add("J");
hs.add("I");
hs.add("K");
hs.add("I");
hs.add("M");
hs.add("L");
hs.add("A");
hs.add("Q");
hs.add("P");
hs.add("O");
hs.add("N");
hs.add("R");
hs.add("N");
hs.add("R");
hs.add("a");
hs.add("G");
hs.add("H");
System.out.println(hs);
}
}

uj5u.com熱心網友回復:
試試下面的代碼段:
HashSet<String> hs = new HashSet<String>();
for (int i = 0; i < 26; i++) {
hs.clear();
hs.add(String.valueOf((char)('A' + i)));
hs.add(String.valueOf((char)('A' + 25 - i)));
System.out.println(hs.toString());
}
輸出:
[A, Z]
[B, Y]
[C, X]
[D, W]
[E, V]
[U, F]
[T, G]
[S, H]
[R, I]
[Q, J]
[P, K]
[L, O]
[M, N]
[M, N]
[L, O]
[P, K]
[Q, J]
[R, I]
[S, H]
[T, G]
[U, F]
[E, V]
[D, W]
[C, X]
[B, Y]
[A, Z]
[A, Z]
uj5u.com熱心網友回復:
你對無序這個概念有誤差啊
uj5u.com熱心網友回復:
hashSet的無序是指不能以寫入的順序或倒序輸出
uj5u.com熱心網友回復:
我記得現在jdk8 版本的hashSet底層是呼叫HaseMap 的K來實作無序的,無序的概念并不是說你輸入什么都會打亂順序,他會按照HashCode進行插入到Hash 中,最后會用hash表存的順序輸出!
uj5u.com熱心網友回復:
這里的有序是指,你輸出的和輸入的位置一樣吧。無序就是輸入的和輸出的位置不相同轉載請註明出處,本文鏈接:https://www.uj5u.com/qita/268088.html
標籤:其他技術討論專區
