C ++ में मैप बनाम हैश_मैप


117

मैं के साथ एक सवाल है hash_mapऔर mapसी ++ में। मैं समझता हूं कि mapएसटीएल में है, लेकिन hash_mapएक मानक नहीं है। दोनों में क्या अंतर है?

जवाबों:


133

उन्हें बहुत अलग तरीकों से लागू किया जाता है।

hash_map( unordered_mapटीआर 1 और बूस्ट में; इसके बजाय उन का उपयोग करें) एक हैश तालिका का उपयोग करें जहां कुंजी को तालिका में एक स्लॉट में रखा जाता है और मूल्य उस कुंजी से जुड़ी सूची में संग्रहीत होता है।

map एक संतुलित बाइनरी सर्च ट्री (आमतौर पर लाल / काला पेड़) के रूप में लागू किया जाता है।

एक unordered_mapसंग्रह के ज्ञात तत्वों तक पहुँचने के लिए थोड़ा बेहतर प्रदर्शन देने चाहिए, लेकिन एक map(जैसे यह क्रमबद्ध आदेश है, जो शुरू से आखिर तक ट्रेवर्सल की अनुमति देता है में संग्रहित है) अतिरिक्त उपयोगी विशेषताओं होगा। unordered_mapडालने पर और तेज़ हो जाएगा और एक से हटा देगा map


7
मैं प्रदर्शन के संबंध में आपसे पूरी तरह सहमत नहीं हूं। प्रदर्शन कई मापदंडों से प्रभावित होता है और मैं केवल 10 प्रविष्टियों के लिए unordered_map का उपयोग करके किसी भी प्रोग्रामर को डांट दूंगा क्योंकि "यह तेज है"। पहले इंटरफ़ेस / कार्यक्षमता के बारे में चिंता, बाद में प्रदर्शन।
मैथ्यू एम।

24
ठीक है, हाँ, यह आपकी समस्या को समझने में मदद करता है। परिमाण के कुछ आदेशों तक यह संभवतः एक धोने का प्रदर्शन-वार है, लेकिन दोनों कंटेनरों की प्रदर्शन विशेषताओं को समझना महत्वपूर्ण है क्योंकि वे अलग-अलग तरीकों से विचलन करते हैं क्योंकि डेटा वॉल्यूम बड़ा हो जाता है।
जो

7
दिलचस्प बात यह है कि, मैंने एक आवेदन के साथ एक :: सीडी :: मैप को बढ़ावा दिया है :: unordered_map एक आवेदन में जिसमें मैं बहुत सारे यादृच्छिक लुकअप करता हूं, लेकिन नक्शे में सभी कुंजियों पर पुनरावृति भी करता हूं। मैंने देखने में बड़ी मात्रा में समय बचाया, लेकिन पुनरावृत्तियों के माध्यम से इसे वापस प्राप्त किया, इसलिए मैंने मानचित्र पर वापस स्विच किया और आवेदन प्रदर्शन में सुधार करने के अन्य तरीकों की तलाश कर रहा हूं।
एरिक गैरीसन

4
@ErikGarrison यदि आप यादृच्छिक अभिगम और पुनरावृत्ति का उपयोग करते हैं, जिसमें आप तत्व सम्मिलित करते हैं और हटाते हैं, तो आप अपनी वस्तुओं को एक पेड़ और एक हैश_मैप दोनों में रख सकते हैं (एक सूचक को संग्रहीत करके, या बेहतर अभी तक एक साझा_पार्ट, दोनों में समान वस्तुओं के लिए। आप वास्तविक उदाहरणों का उपयोग कर रहे थे)। फिर आपके पास हैश_मैप के माध्यम से O (1) समय पहुंच का समय होगा और मैप के माध्यम से O (n) पुनरावृत्ति समय होगा। बेशक, आपको हर बार दोनों से बिंदुओं को जोड़ने और हटाने के लिए याद रखना होगा। आप आसानी से एक कस्टम कंटेनर क्लास लिख सकते हैं जो (शायद इसे अच्छी तरह से टेंपलेट करें) जो आपके लिए इस व्यवहार को प्रोत्साहित करेगा।
स्प्राइट

2
@ ErikGarrison बेशक, अगर आप इस तरीके को आजमाते हैं, तो आप एक मामूली अतिरिक्त जगह के साथ भुगतान करेंगे। हालाँकि, चूंकि आप पॉइंटर्स का उपयोग कर रहे हैं, इसलिए यह बहुत अधिक नहीं होना चाहिए। यदि आप वास्तव में चाहते हैं, तो आप ओवरबोर्ड जा सकते हैं, और एवीएल के अपने स्वयं के कार्यान्वयन को लिख सकते हैं और नोड पॉइंटर का उपयोग अपने डेटा प्रकार के रूप में हैश_मैप में कर सकते हैं, इससे आपको पेड़ में एक नोड के लिए ओ (1) का समय मिल जाएगा। आप जहां भी जरूरत है, आप रैखिक रूप से पुनरावृति करने में सक्षम होंगे। बेशक यह कोडिंग का एक बहुत कुछ शामिल होगा और मुझे यकीन नहीं है कि यह तब तक भुगतान करेगा जब तक आपको बहुत से स्थानों से और यादृच्छिक स्थानों को पुनरावृत्त करने की आवश्यकता नहीं है।
स्प्राइट

35

hash_mapकई पुस्तकालय कार्यान्वयन द्वारा प्रदान किया गया एक सामान्य विस्तार था। यही कारण है कि unordered_mapTR1 के भाग के रूप में इसे C ++ मानक में जोड़ने पर इसका नाम बदल दिया गया। नक्शा आमतौर पर एक संतुलित बाइनरी ट्री के साथ लागू किया जाता है जैसे लाल-काला पेड़ (कार्यान्वयन अलग-अलग होते हैं)। hash_mapऔर unordered_mapआम तौर पर हैश टेबल के साथ लागू किया जाता है। इस प्रकार आदेश का रखरखाव नहीं किया जाता है। unordered_mapडालें / हटाएं / क्वेरी ओ (1) (निरंतर समय) होगी जहां मानचित्र ओ (लॉग एन) होगा जहां एन डेटा संरचना में वस्तुओं की संख्या है। तो unordered_mapतेज है, और यदि आप आइटम के आदेश के बारे में परवाह नहीं करते हैं, तो इसे प्राथमिकता दी जानी चाहिए map। कभी-कभी आप ऑर्डर बनाए रखना चाहते हैं (कुंजी द्वारा आदेश दिया गया) और इसके लिए mapविकल्प होगा।


9
मुझे लगता है कि हैशमैप ओ (एन) की सबसे खराब स्थिति है जब टकराव की संभावना होती है (खराब हैश fcn, लोडिंग कारक बहुत अधिक है, आदि)
KitsuneYMG

एक अच्छे हैशमैप में O (1) की अपेक्षित लागत होती है, ऐसा होने की गारंटी नहीं है। खराब हैशमैप में अपेक्षित लागत हो सकती है जो O (1) नहीं है।
स्पष्ट

14

कुछ प्रमुख अंतर जटिलता आवश्यकताओं में हैं।

  • एक mapआवश्यकता O(log(N))के रूप में यह एक के रूप में लागू है, आवेषण और पाता कार्यों के लिए समय लाल काला पेड़ डेटा संरचना।

  • एक unordered_mapके एक 'औसत' समय की आवश्यकता है O(1)आवेषण और पाता है, लेकिन की बुरी से बुरी हालत समय बिताने के लिए अनुमति दी है O(N)। ऐसा इसलिए है क्योंकि इसे हैश टेबल डेटा संरचना का उपयोग करके लागू किया गया है ।

तो, आमतौर पर, unordered_mapतेजी से होगा, लेकिन आपके द्वारा संग्रहीत कीज़ और हैश फ़ंक्शन के आधार पर, बहुत अधिक खराब हो सकता है।


4

C ++ कल्पना बिल्कुल नहीं कहती है कि STL कंटेनरों के लिए आपको किस एल्गोरिथ्म का उपयोग करना चाहिए। हालांकि, यह उनके प्रदर्शन पर कुछ बाधाओं को डालता है, जो mapअन्य सहयोगी कंटेनरों के लिए हैश तालिकाओं के उपयोग को नियंत्रित करता है। (वे आम तौर पर लाल / काले पेड़ों के साथ लागू होते हैं।) इन बाधाओं को इन कंटेनरों के लिए बेहतर खराब स्थिति वाले प्रदर्शन की आवश्यकता होती है, जैसे कि हैश टेबल वितरित कर सकते हैं।

बहुत से लोग वास्तव में हैश टेबल चाहते हैं, हालांकि, हैश-आधारित एसटीएल सहयोगी कंटेनर वर्षों से एक सामान्य विस्तार है। नतीजतन, उन्होंने unordered_mapC ++ मानक के बाद के संस्करणों को जोड़ा और इस तरह के।


यह वास्तव में TR1 (std :: tr1 :: unordered_map) में जोड़ा गया था, न कि C ++ 0x
टेरी महाफ़ी

मुझे लगा कि mapआमतौर पर एक संतुलित btree operator<()स्थान निर्धारण के साधन के रूप में उपयोग करने के कारण था ।
KitsuneYMG

@kts: क्या कोई एसटीएल कार्यान्वयन वास्तव में बी-ट्री का उपयोग करता है?
bk1e

तकनीकी रूप से सभी बाइनरी सर्च पेड़ बी-ट्री (एक 1-2 पेड़) हैं। कहा जा रहा है, मैं किसी भी एसटीएल के बारे में नहीं जानता, जो लाल / काले के अलावा कुछ भी इस्तेमाल करता हो
KitsuneYMG

@ bk1e "उचित" बी-पेड़ डेटाबेस में असाधारण रूप से उपयोगी हैं, जहां आप "वसा" ट्री नोड चाहते हैं जो डिस्क पृष्ठों पर अच्छी तरह से संरेखित होते हैं। OTOH, यह "सामान्य" कार्यक्रमों में उपयोग किए जाने वाले "फ्लैट" मेमोरी मॉडल में इतना उपयोगी नहीं है - सभी एसटीएल कार्यान्वयन जिन्हें मैं लाल-काले पेड़ों का उपयोग करने के बारे में जानता हूं।
ब्रांको दिमित्रिजेविक

3

mapbalanced binary search tree(आमतौर पर rb_tree) से कार्यान्वित किया जाता है , क्योंकि सभी सदस्य balanced binary search treeको क्रमबद्ध किया जाता है, इसलिए यह नक्शा है;

hash_mapसे कार्यान्वित किया जाता है hashtable। सभी hashtableसदस्यों को अलग-थलग कर दिया जाता है, ताकि सदस्यों को hash_map(unordered_map)क्रमबद्ध न किया जाए।

hash_mapc ++ मानक पुस्तकालय नहीं है, लेकिन अब इसका नाम बदल दिया गया है unordered_map(आप इसका नाम बदल सकते हैं) और c ++ मानक पुस्तकालय बन जाता है, क्योंकि c ++ 11 इस प्रश्न को hash_map और unordered_map के बीच अंतर करता है? अधिक विस्तार के लिए।

नीचे मैं दो प्रकार का नक्शा कैसे लागू किया जाता है के स्रोत कोड से कुछ मुख्य इंटरफ़ेस देगा।

नक्शा:

नीचे दिया गया कोड केवल यह दिखाने के लिए है कि, नक्शा सिर्फ एक आवरण है 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जिसका ढांचा कुछ इस तरह है:

यहां छवि विवरण दर्ज करें

नीचे दिए गए कोड में, मैं मुख्य भाग दूंगा 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);
        };

};

नीचे दी गई छवि से पता चलता है कि एक हैश_मैप में 53 बाल्टियाँ हैं, और कुछ मान डालें, यह आंतरिक संरचना है।

यहां छवि विवरण दर्ज करें

नीचे दी गई छवि नक्शे और hash_map (unordered_map) के बीच कुछ अंतर दिखाती है, छवि आती है कि कैसे मानचित्र और unordered_map के बीच चयन करें? :

यहां छवि विवरण दर्ज करें


1

मुझे नहीं पता कि क्या देता है, लेकिन, hash_map को साफ़ करने के लिए 20 सेकंड से अधिक समय लगता है () 150K अहस्ताक्षरित पूर्णांक कुंजियाँ और फ़्लोट मान। मैं अभी किसी और का कोड चला रहा हूं और पढ़ रहा हूं।

इस तरह इसमें हैश_मैप शामिल है।

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

मैंने इसे यहाँ पढ़ा https://bytes.com/topic/c/answers/570079-perfomance-clear-vs-swap

यह कहना कि स्पष्ट () O (N) का आदेश है। यह मेरे लिए, बहुत अजीब है, लेकिन, यह जिस तरह से है।

हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.