實際上這個問題不光C++會遇到,其餘全部語言的標準容器的實現及選擇上都是要考慮的。作應用程序你可能以爲影響不大,可是寫算法或者核心代碼就要當心了。今天改進代碼,順便又來溫習基礎功課了。
還記得Herb Sutter那極有味道的《C++對話系列》麼,在其中《產生真正的hash對象》這個故事裏就講了map的選擇。順便回顧一下,也講一下我在實用中的理解。
選擇map容器,是爲了更快的從關鍵字查找到相關的對象。與使用list這樣的線性表容器相比,一能夠簡化查找的算法,二可使任意的關鍵字作索引,並與目標對象配對,優化查找算法。在C++的STL中map是使用樹來作查找算法,這種算法差很少至關與list線性容器的折半查找的效率同樣,都是O(log2N),而list就沒有map這樣易定製和操做了。
相比hash_map,hash_map使用hash表來排列配對,hash表是使用關鍵字來計算表位置。當這個表的大小合適,而且計算算法合適的狀況下,hash表的算法複雜度爲O(1)的,可是這是理想的狀況下的,若是hash表的關鍵字計算與表位置存在衝突,那麼最壞的複雜度爲O(n)。
那麼有了這樣的認識,咱們應該怎麼樣選用算法呢?前兩天看Python文章的時候,不知道哪一個小子說Python的map比c++的map快,如何如何的。可是他並不知道Python是默認使用的hash_map,並且這些語言特徵本質上是使用c/c++寫出來的,問題在與算法和手段,而不是在於語言自己的優劣,你熟悉了各類算法,各類語言的細節、設計思想,還能在這偏激的嚷嚷孰好孰壞(片面與偏激的看待事物只能代表愚昧與無知,任何事物都有存在的價值,包括技術)。顯然C++的STL默認使用樹結構來實現map,是有考究的。
樹查找,在總查找效率上比不上hash表,可是它很穩定,它的算法複雜度不會出現波動。在一次查找中,你能夠判定它最壞的狀況下其複雜度不會超過O(log2N)。而hash表就不同,是O(1),仍是O(N),或者在其之間,你並不能把握。倘若你在開發一個供外部調用的接口,其內部有關鍵字的查找,可是這個接口調用並不頻繁,你是會但願其調用速度快、但不穩定呢,仍是但願其調用時間平均、且穩定呢。反之倘若你的程序須要查找一個關鍵字,這個操做很是頻繁,你但願這些操做在整體上的時間較短,那麼hash表查詢在總時間上會比其餘要短,平均操做時間也會短。這裏就須要權衡了。
這裏總結一下,選用map仍是hash_map,關鍵是看關鍵字查詢操做次數,以及你所須要保證的是查詢整體時間仍是單個查詢的時間。若是是要不少次操做,要求其總體效率,那麼使用hash_map,平均處理時間短。若是是少數次的操做,使用hash_map可能形成不肯定的O(N),那麼使用平均處理時間相對較慢、單次處理時間恆定的map,考慮總體穩定性應該要高於總體效率,由於前提在操做次數較少。若是在一次流程中,使用hash_map的少數操做產生一個最壞狀況O(N),那麼hash_map的優點也所以喪盡了。 c++