C ++ 'da eşleme ile hash_map karşılaştırması


117

C ++ ile hash_mapve mapiçinde bir sorum var . Bunun STL'de olduğunu anlıyorum map, ancak hash_mapbir standart değil. İkisi arasındaki fark nedir?

Yanıtlar:


133

Çok farklı şekillerde uygulanırlar.

hash_map( unordered_mapTR1 ve Boost'ta; bunun yerine bunları kullanın), anahtarın tablodaki bir yuvaya karma hale getirildiği ve değerin bu anahtara bağlı bir listede saklandığı bir karma tablo kullanın.

map dengeli bir ikili arama ağacı (genellikle kırmızı / siyah bir ağaç) olarak uygulanır.

An unordered_map, koleksiyonun bilinen öğelerine erişmek için biraz daha iyi performans sağlamalıdır, ancak a mapek yararlı özelliklere sahip olacaktır (örneğin, baştan sona geçişe izin veren sıralı sırayla depolanır). unordered_mapekleme ve silme işlemlerinde a'dan daha hızlı olacaktır map.


7
Performans konusunda sana tam olarak katılmıyorum. Performans, bir dizi parametreden etkilenir ve herhangi bir programcıyı sadece 10 giriş için bir unordered_map kullanarak azarlardım çünkü "Daha hızlı". Önce arayüz / işlevsellik, sonra performans hakkında endişelenin.
Matthieu M.

24
Evet, problemini anlarsan yardımcı olur. Belirli büyüklük sıralarına kadar, muhtemelen yıkama performansı açısından önemlidir, ancak her iki kabın performans özelliklerinin, veri hacimleri büyüdükçe farklı şekillerde sapmalarından dolayı anlamak önemlidir.
Joe

7
İlginç bir şekilde, çok sayıda rastgele arama yaptığım ve aynı zamanda haritadaki tüm anahtarları yinelediğim bir uygulamada std :: map'i boost :: unordered_map ile değiştirdim. Aramada büyük miktarda zamandan tasarruf ettim, ancak yinelemelerle geri kazandım, bu yüzden haritaya geri döndüm ve uygulama performansını iyileştirmenin başka yollarını arıyorum.
Erik Garrison

4
@ErikGarrison Rastgele erişim ve yinelemeyi, öğeleri ekleyip silmekten çok daha fazla kullanırsanız, nesnelerinizi hem bir ağaçta hem de bir hash_map'te (bir işaretçi veya daha iyisi bir shared_ptr depolayarak, her ikisinde de aynı nesnelere depolayabilirsiniz) gerçek örnekleri kullanıyor olmanız durumunda). Daha sonra hash_map aracılığıyla O (1) kez erişim süresine ve harita boyunca O (n) yineleme süresine sahip olacaksınız. Elbette, her seferinde işaretçileri eklemeyi ve çıkarmayı unutmamalısınız. Bu davranışı sizin için kapsayacak (muhtemelen şablon olarak da) özel bir kapsayıcı sınıfı yazabilirsiniz.
sprite

2
@ErikGarrison Elbette bu yöntemi denerseniz, küçük bir ek alanla ödeme yapmış olursunuz. Ancak, işaretçi kullanacağınız için bu çok fazla olmamalı. Gerçekten istiyorsanız, denize girebilir ve kendi AVL uygulamanızı yazabilir ve hash_map'de veri türünüz olarak düğüm işaretçisini kullanabilirsiniz, bu size ağaçtaki bir düğüme O (1) zamanlı erişim sağlayacaktır. İhtiyaç duyduğunuz her yere doğrusal olarak yineleme yapabileceksiniz. Tabii ki bu oldukça fazla kodlama gerektirecektir ve rastgele erişim konumlarından çok fazla yineleme yapmanız gerekmedikçe karşılığını alacağından emin değilim.
sprite

35

hash_mapbirçok kütüphane uygulaması tarafından sağlanan yaygın bir uzantıdır. Bu yüzden unordered_mapTR1'in bir parçası olarak C ++ standardına eklendiği zaman olarak yeniden adlandırıldı . harita genellikle kırmızı-siyah ağaç gibi dengeli bir ikili ağaçla gerçekleştirilir (uygulamalar elbette değişiklik gösterir). hash_mapve unordered_mapgenellikle karma tablolarla uygulanır. Böylece düzen korunmaz. unordered_mapekle / sil / sorgu O (1) (sabit zaman) olacaktır burada harita O (log n) olacaktır, burada n, veri yapısındaki öğelerin sayısıdır. Yani unordered_mapdaha hızlı ve eğer ilginizi çekmiyorsa öğelerin sırasına göre tercih edilmelidir map. Bazen düzeni korumak istersiniz (anahtara göre sıralanır) ve mapbunun için seçim olur.


9
Çarpışmalar olası olduğunda (kötü hash fcn, yükleme faktörü çok yüksek vb.)
Hashmap'in

İyi bir hashmap'in beklenen maliyeti O (1) olur, böyle olacağı garanti edilmez. Kötü hashmap'lerin, O (1) olmayan beklenen bir maliyeti olabilir.
daha

14

Temel farklılıklardan bazıları karmaşıklık gereksinimlerindedir.

  • A map, Kırmızı-Siyah Ağaç veri yapısı O(log(N))olarak uygulandığı için, ekleme ve bulma işlemleri için zaman gerektirir .

  • Bir unordered_map, O(1)ekleme ve buluntular için 'ortalama' bir süre gerektirir , ancak en kötü durum süresine sahip olmasına izin verilir O(N). Bunun nedeni, Hash Table veri yapısı kullanılarak uygulanmasıdır .

Bu nedenle, genellikle unordered_mapdaha hızlı olacaktır, ancak anahtarlara ve sakladığınız hash işlevine bağlı olarak çok daha kötü hale gelebilir.


4

C ++ belirtimi, STL kapsayıcıları için tam olarak hangi algoritmayı kullanmanız gerektiğini söylemez. Bununla birlikte, performanslarına bazı kısıtlamalar koyar, bu da karma tabloların mapve diğer ilişkili kapların kullanımını dışlar . (Genellikle kırmızı / siyah ağaçlarda uygulanırlar.) Bu kısıtlamalar, bu kapsayıcılar için karma tabloların sağlayabileceğinden daha iyi en kötü durum performansı gerektirir.

Bununla birlikte, birçok insan gerçekten karma tablolar istemektedir, bu nedenle karma tabanlı STL ilişkisel kapsayıcılar yıllardır yaygın bir uzantı olmuştur. Sonuç olarak, unordered_mapC ++ standardının sonraki sürümlerine ve benzerlerini eklediler .


Aslında TR1'e (std :: tr1 :: unordered_map) eklendi, C ++ 0x değil
Terry Mahaffey

Bunun sebebinin mapgenellikle dengeli bir ağaç olduğunu düşündüm, operator<()yer belirleme aracı olarak kullanılmasıydı .
KitsuneYMG

@kts: Herhangi bir STL uygulaması aslında bir B ağacı kullanıyor mu?
bk1e

Teknik olarak tüm ikili arama ağaçları b-ağaçlarıdır (1-2 ağaç). Olduğu söyleniyor, kırmızı / siyah dışında bir şey kullanan herhangi bir STL bilmiyorum
KitsuneYMG

@ bk1e "Uygun" B ağaçları, disk sayfalarıyla iyi hizalanan "şişman" ağaç düğümleri istediğiniz veritabanlarında son derece kullanışlıdır. OTOH, bu "normal" programlarda kullanılan "düz" bellek modelinde pek kullanışlı değil - bildiğim tüm STL uygulamaları kırmızı-siyah ağaçları kullanıyor.
Branko Dimitrijevic

3

mapbalanced binary search tree(genellikle a rb_tree) ' dan gerçeklenir , çünkü içindeki tüm üye balanced binary search treesıralanır ve harita da öyle;

hash_mapiçindeki hashtabletüm hashtableüyeler sıralanmadığından, içindeki üyeler hash_map(unordered_map)sıralanmaz.

hash_mapbir c ++ standart kitaplık değil, ancak şimdi olarak yeniden adlandırıldı unordered_map( yeniden adlandırıldığını düşünebilirsiniz) ve c ++ standart kitaplık haline geldi çünkü c ++ 11 bu soruyu görüyor Hash_map ve unordered_map arasındaki fark? daha fazla ayrıntı için.

Aşağıda, iki tip haritasının nasıl uygulandığına dair kaynak kodundan bazı temel arayüzler vereceğim.

harita:

Aşağıdaki kod, haritanın yalnızca bir sarmalayıcı olduğunu balanced binary search tree, hemen hemen tüm işlevinin yalnızca balanced binary search treeişlevi çağırdığını göstermek içindir .

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_maphashtableyapısı biraz aşağıdaki gibi olanlardan uygulanır :

görüntü açıklamasını buraya girin

Aşağıdaki kodda ana kısmını vereceğim hashtableve sonra vereceğim 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'sTek üye gibi rb_tree, hash_map'stek üye de hashtable. Aşağıdaki gibi ana kod:

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);
        };

};

Aşağıdaki resim, hash_map'in 53 kovaya sahip olduğunu ve bazı değerleri eklediğini gösterir, dahili yapısı.

görüntü açıklamasını buraya girin

Aşağıdaki resim, map ve hash_map (unordered_map) arasındaki bazı farkları gösterir, resim, Harita ve unordered_map arasında nasıl seçim yapılır? :

görüntü açıklamasını buraya girin


1

Ne verir bilmiyorum ama hash_map'in 150K işaretsiz tamsayı anahtarlarını ve float değerlerini temizlemesi () 20 saniyeden fazla sürüyor. Sadece koşuyorum ve başka birinin kodunu okuyorum.

Hash_map'i bu şekilde içerir.

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

Bunu burada okudum https://bytes.com/topic/c/answers/570079-perfomance-clear-vs-swap

clear (), O (N) 'nin sırasıdır. Bu benim için çok tuhaf, ama bu böyle.

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.