web-dev-qa-db-ja.com

C ++でのmapとhash_map

C++のhash_mapおよびmapに関して質問があります。 mapはSTLにありますが、hash_mapは標準ではないことを理解しています。 2つの違いは何ですか?

110
skydoor

それらは非常に異なる方法で実装されます。

hash_map(TR1およびBoostではunordered_map;代わりに使用)は、キーがテーブルのスロットにハッシュされ、値がそのキーに関連付けられたリストに格納されるハッシュテーブルを使用します。

mapは、バランスの取れたバイナリ検索ツリー(通常は赤/黒ツリー)として実装されます。

unordered_mapは、コレクションの既知の要素にアクセスするためのパフォーマンスをわずかに向上させる必要がありますが、mapには追加の有用な特性があります(たとえば、ソート順で格納され、最初から最後までトラバースできます)。 unordered_mapは、mapよりも挿入および削除の方が高速です。

129
Joe

hash_mapは、多くのライブラリ実装によって提供される一般的な拡張機能でした。それがまさに、TR1の一部としてC++標準に追加されたときにunordered_mapに名前が変更された理由です。 mapは通常、赤黒木のようなバランスの取れた二分木で実装されます(実装はもちろん異なります)。 hash_mapおよびunordered_mapは通常、ハッシュテーブルで実装されます。したがって、順序は維持されません。 unordered_map insert/delete/queryはO(1)(一定時間)になります。マップはO(log n)になります。nはデータ構造内のアイテムの数です。したがって、unordered_mapはより高速であり、項目の順序を気にしない場合は、mapよりも優先する必要があります。順序を維持したい場合があります(キーで順序付けされます)。そのためには、mapが選択されます。

34
janglin

主な違いのいくつかは、複雑さの要件にあります。

  • mapは、挿入および検索操作にO(log(N))時間を必要とします。これはRed-Black Treeデータ構造として実装されているためです。

  • unordered_mapは、挿入と検索にO(1)の '平均'時間を必要としますが、O(N)のワーストケース時間を許可されています。これは、ハッシュテーブルデータ構造を使用して実装されているためです。

したがって、通常、unordered_mapは高速になりますが、キーと保存するハッシュ関数によっては、さらに悪化する可能性があります。

14

C++仕様では、STLコンテナにどのアルゴリズムを使用する必要があるかについて正確には述べていません。ただし、パフォーマンスに一定の制約を課しているため、mapおよびその他の連想コンテナ用のハッシュテーブルの使用が除外されています。 (最も一般的には、赤/黒ツリーで実装されます。)これらの制約は、ハッシュテーブルが提供できるよりも優れた最悪の場合のこれらのコンテナーのパフォーマンスを必要とします。

ただし、多くの人がハッシュテーブルを本当に必要としているため、ハッシュベースのSTL連想コンテナは長年にわたって一般的な拡張機能でした。その結果、彼らはunordered_mapなどを後のバージョンのC++標準に追加しました。

4
Warren Young

mapbalanced binary search tree(通常はrb_tree)から実装されます。これは、balanced binary search tree内のすべてのメンバーが並べ替えられるため、マップも同様です。

hash_maphashtableから実装されます。hashtableのすべてのメンバーはソートされていないため、hash_map(unordered_map)のメンバーはソートされません。

hash_mapはc ++標準ライブラリではありませんが、今ではunordered_map(名前を変更すると考えることができます)に名前が変更され、c ++ 11でこの質問が表示されるため、c ++標準ライブラリになります hash_mapの違いおよびunordered_map? .

以下に、2つのタイプマップの実装方法のソースコードからのコアインターフェイスを示します。

地図:

以下のコードは、マップがbalanced binary search treeの単なるラッパーであり、その機能のほとんどすべてがbalanced binary search tree関数を呼び出すだけであることを示すためのものです。

template <typename Key, typename Value, class Compare = std::less<Key>>
class map{
    // used for rb_tree to sort
    typedef Key    key_type;

    // rb_tree node value
    typedef std::pair<key_type, value_type> value_type;

    typedef Compare key_compare;

    // as to map, Key is used for sort, Value used for store value
    typedef rb_tree<key_type, value_type, key_compare> rep_type;

    // the only member value of map (it's  rb_tree)
    rep_type t;
};

// one construct function
template<typename InputIterator>
map(InputIterator first, InputIterator last):t(Compare()){
        // use rb_tree to insert value(just insert unique value)
        t.insert_unique(first, last);
}

// insert function, just use tb_tree insert_unique function
//and only insert unique value
//rb_tree insertion time is : log(n)+rebalance
// so map's  insertion time is also : log(n)+rebalance 
typedef typename rep_type::const_iterator iterator;
std::pair<iterator, bool> insert(const value_type& v){
    return t.insert_unique(v);
};

hash_map

hash_mapは、構造が次のようなhashtableから実装されます。

enter image description here

以下のコードでは、hashtableの主要部分を指定し、hash_mapを指定します。

// used for node list
template<typename T>
struct __hashtable_node{
    T val;
    __hashtable_node* next;
};

template<typename Key, typename Value, typename HashFun>
class hashtable{
    public:
        typedef size_t   size_type;
        typedef HashFun  hasher;
        typedef Value    value_type;
        typedef Key      key_type;
    public:
        typedef __hashtable_node<value_type> node;

        // member data is buckets array(node* array)
        std::vector<node*> buckets;
        size_type num_elements;

        public:
            // insert only unique value
            std::pair<iterator, bool> insert_unique(const value_type& obj);

};

map'sのみのメンバーはrb_treeのように、hash_map'sのみのメンバーはhashtableです。以下のようなメインコードです。

template<typename Key, typename Value, class HashFun = std::hash<Key>>
class hash_map{
    private:
        typedef hashtable<Key, Value, HashFun> ht;

        // member data is hash_table
        ht rep;

    public:
        // 100 buckets by default
        // it may not be 100(in this just for simplify)
        hash_map():rep(100){};

        // like the above map's insert function just invoke rb_tree unique function
        // hash_map, insert function just invoke hashtable's unique insert function
        std::pair<iterator, bool> insert(const Value& v){
                return t.insert_unique(v);
        };

};

以下の画像は、hash_mapに53個のバケットがあり、いくつかの値を挿入するときの内部構造を示しています。

enter image description here

以下の画像は、mapとhash_map(unordered_map)の違いを示しています。画像は mapとunordered_mapを選択する方法?

enter image description here

2
Jayhello

何が得られるのかわかりませんが、hash_mapは、150Kの符号なし整数キーとfloat値をclear()するのに20秒以上かかります。私はただ他の人のコードを実行して読んでいます。

これがhash_mapを含む方法です。

#include "StdAfx.h"
#include <hash_map>

ここでこれを読みます https://bytes.com/topic/c/answers/570079-perfomance-clear-vs-swap

clear()はO(N)の順序であると言っています。私にはそれは非常に奇妙ですが、それはそうです。

0
BoBoDev