幾種常見 容器 比較和分析 hashmap, map, vector, list ...hash table


http://www.cnblogs.com/sharpfeng/archive/2012/09/18/2691096.html

幾種常見 容器 比較和分析 hashmap, map, vector, list ...hash table

 

 

list支持快速的插入和刪除,但是查找費時;

vector支持快速的查找,但是插入費時。

map查找的時間復雜度是對數的,這幾乎是最快的,hash也是對數的。 
如果我自己寫,我也會用二叉檢索樹,它在大部分情況下可以保證對數復雜度,最壞情況是常數復雜度,而std::map在任何情況下都可以保證對數復雜度,原因是它保證存諸結構是完全二叉檢索樹,但這會在存諸上犧牲一些時間。

STL   中的   map   內部是平衡二叉樹,所以平衡二叉樹的性質都具備。查找數據的時間也是對數時間。vector,在分配內存上一般要比   new   高效的多。

為什么說   hash_map   是對數級的?在不碰撞的情況下,hash_map是所有數據結構中查找最快的,它是常數級的。 
如果對問題設計了足夠好的hash算法,保證碰撞率很低,hash_map的查找效率無可置疑。 
另外,STL的map,它的查找是對數級的,是除hash_map外最高的了,你可以說“也許還有改進余地”,但對於99.9999%的程序員,設計一個比STL   map好的map,我執悲觀態度。 
STL的map有平衡策略(比如紅黑樹什么的),所以不會退化,不需要考慮數據本身的分布問題。只不過,如果數據本身是排好序的,用vector或heap會明顯的快些,因為它們的訪問比較簡單。

 

我想沒必要懷疑stl::map的查找效率,影響效率最主要的因素是什么?算法,在查找問題上,有什么算法比RB_tree更好嗎?至少現在還沒有。不否 認你可以通過自己寫代碼,設計一個符合你需要的BR—TREE,比stl::map簡捷那么一點,但最多也就每次迭代中少一行指令而已,處理十萬個數據多 執行十萬行指令,這對你重要嗎?如果你不是在設計OS像LINUX,沒人會關注這十萬行指令花的時間。 
rb-tree的時間花在了插入和刪除上,如果你不是對插入和刪除效率要求很高,你沒有理由不選擇基於rb-tree的stl::map。

 

大多數程序員寫不出比std::map更好的map,這是當然的。然而並不是std::map的所有特性都出現在我們的程序中,自己編寫的可以更適合自己的程序,的確會比std::map更快一些。

 

關於hash_map,它與map的實現機制是不一樣的,map內部一般用樹來實現,其查找操作是O(logN)的,這個沒有爭議,我就不多說了。 
hash_map的查找,內部是通過一個從key到value的運算函數來實現的,這個函數“只接受key作為參數”,也就是說,hash_map的查找 算法與數據量無關,所以認為它是O(1)級的。來這里的應該都是達人,可以參看《數據結構》。當然,事實總不這樣完美,再引一段前面我自已說的話,進一步 說明,以免誤會:

----------------------------------------- 
在不碰撞的情況下,hash_map是所有數據結構中查找最快的,它是常數級的。 
------------------------------------------ 
注意我的前提:“在不碰撞的情況下”,其實換句話說,就是要有足夠好的hash函數,它要能使key到value的映射足夠均勻,否則,在最壞的情況下,它的計算量就退化到O(N)級,變成和鏈表一樣。 
如果說   hash_map   是所有容器中最慢的,也只能說:“最拙劣的hash函數”會使hash_map成為查找最慢的容器。但這樣說意義不大,因為,最湊巧的排列能使冒泡排序成為最快的排序算法。

BS: "對於大型容器而言,hash_map能夠提供比map快5至10倍的元素查找速度是很常見的,尤其是在查找速度特別重要的地方.另一方面,如果hash_map選擇了病態的散列函數,他也可能比map慢得多. "

ANSIC++在1998年之后就沒再有重大改變,並且決定不再向C++標准庫中做任何重大的變更,正是這個原因,hash   table(包括hash_map)並沒有被列入標准之中,雖然它理應在C++標准之中占有一席之地。 
雖然,現在的大多數編譯平台支持hash   table,但從可移植性方面考慮,還是不用hash   table的好。

 

hehe俺也來湊湊熱鬧。 
1.有的時候vector可以替代map 
比如key是整數,就可以以key的跨度作為長度來定義vector。 
數據規模很大的時候,差異是驚人的。當然,空間浪費往往也驚人。 
2.hash是很難的東西 
沒有高效低碰撞的算法,hash_xxx沒有意義。 
而對不同的類型,數據集,不可能有優良的神仙算法。必須因場合而宜。 
俺有的解決方法是GP,可不是飯型,是遺傳編程,收效不錯。

 

你的百萬級的數據放到vector不大合適。因為vector需要連續的內存空間,顯然在初始化這個容器的時候會花費很大的容量。 
使用map,你想好了要為其建立一個主鍵嗎?如果沒有這樣的需求,為什么不考慮deque或者list? 
map默認使用的是deque作為容器。其實map不是容器,拿它與容器比較意義不大。因為你可以配置它的底層容器類型。

 

如果內存不是考慮的問題。用vector比map好。map每插入一個數據,都要排序一次。所以速度反不及先安插所有元素,再進行排序。

用 binary_search對已序區間搜索,如果是隨機存取iterator,則是對數復雜度。可見,在不考慮內存問題的情況下,vector比map 好。

 

如果你需要在數據中間進行插入,list 是最好的選擇,vector   的插入效率會讓你痛苦得想死。

 

涉及到查找的話用map比較好,因為map的內部數據結構用rb-tree實現,而用vector你只能用線性查找,效率很低。

stl還提供了 hash容器,理論上查找是飛快~~~。做有序插入的話vector是噩夢,map則保證肯定是按key排序的,list要自己做些事情。

 

HASH類型的查找肯定快,是映射關系嘛,但是插入和刪除卻慢,要做移動操作, LIST類型的使鏈式關系,插入非常快,但是查找卻費時,需要遍歷~~ , 還是用LIST類型的吧,雖然查找慢點,

先快速排序,然后二分查找,效率也不低

 

http://www.cnblogs.com/xiaoQLu/archive/2011/10/13/2210737.html

 

HashSet HashTable HashMap的區別

 

本文轉自:http://wuhenjia.blog.163.com/blog/static/93469449201124114150295/

(1)HashSet是set的一個實現類,hashMap是Map的一個實現類,同時hashMap是hashTable的替代品(為什么后面會講到).

(2)HashSet以對象作為元素,而HashMap以(key-value)的一組對象作為元素,且HashSet拒絕接受重復的對象.HashMap可以看作三個視圖:key的Set,value的Collection,Entry的Set。 這里HashSet就是其實就是HashMap的一個視圖。

HashSet內部就是使用Hashmap實現的,和Hashmap不同的是它不需要Key和Value兩個值。        

往hashset中插入對象其實只不過是內部做了

            public boolean add(Object o) {

                      return map.put(o, PRESENT)==null;
            }

 現在來看hastTable和hashMap的區別:

(1)Hashtable是基於陳舊的Dictionary類的,HashMap是Java 1.2引進的Map接口的一個實現。

(2)這個不同即是最重要的一點:Hashtable中的方法是同步的,而HashMap方法(在缺省情況下)是非同步的。即是說,在多線程應用程序中,不用專門的操作就安全地可以使用Hashtable了;而對於HashMap,則需要額外的同步機制。但HashMap的同步問題可通過Collections的一個靜態方法得到解決:
     Map Collections.synchronizedMap(Map m)
這個方法返回一個同步的Map,這個Map封裝了底層的HashMap的所有方法,使得底層的HashMap即使是在多線程的環境中也是安全的。

(3)只有HashMap可以讓你將空值作為一個表的條目的key或value。HashMap中只有一條記錄可以是一個空的key,但任意數量的條目可以是空的value。這就是說,如果在表中沒有發現搜索鍵,或者如果發現了搜索鍵,但它是一個空的值,那么get()將返回null。如果有必要,用containKey()方法來區別這兩種情況。

 

其它的一些資料:

 

1.HashTable的方法是同步的,HashMap未經同步,所以在多線程場合要手動同步HashMap這個區別就像Vector和ArrayList一樣。(最主要的區別)
    2.HashTable不允許null值(key和value都不可以),HashMap允許null值(key和value都可以,只容許有一個null值的key,可以有多個null值的value)。
    3.HashTable有一個contains(Object value),功能和containsValue(Object value)功能一樣。
    4.HashTable使用Enumeration,HashMap使用Iterator。
以上只是表面的不同,它們的實現也有很大的不同。
    5.HashTable中hash數組默認大小是11,增加的方式是 old*2+1。HashMap中hash數組的默認大小是16,而且一定是2的指數。
    6.哈希值的使用不同,HashTable直接使用對象的hashCode,代碼是這樣的:
      int hash = key.hashCode();
      int index = (hash & 0x7FFFFFFF) % tab.length;
而HashMap重新計算hash值,而且用與代替求模:
int hash = hash(k);
int i = indexFor(hash, table.length);

 

static int hash(Object x) {
   int h = x.hashCode();
   h += ~(h << 9);
   h ^= (h >>> 14);
   h += (h << 4);
   h ^= (h >>> 10);
   return h;
}
static int indexFor(int h, int length) {
   return h & (length-1);
}
以上只是一些比較突出的區別,當然他們的實現上還是有很多不同的,比如
HashMap對null的操作。
 
 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM