সি ++ এ হ্যাশম্যাপ ব্যবহার করার সর্বোত্তম উপায় কী?


174

আমি জানি যে এসটিএলের একটি হ্যাশম্যাপ এপিআই রয়েছে, তবে এ সম্পর্কিত ভাল উদাহরণ সহ আমি কোনও ভাল এবং পুঙ্খানুপুঙ্খ ডকুমেন্টেশন পাই না।

যে কোনও ভাল উদাহরণ প্রশংসা করা হবে।


আপনি কি সি ++ 1 এক্স হ্যাশ_ম্যাপ, বা স্টাডি :: ম্যাপ সম্পর্কে জিজ্ঞাসা করছেন?
ফিলান্ট

2
আমি সি ++ তে java.util.HashMap এর মতো কিছু চাই এবং যদি এটি থাকে তবে এটি করার স্ট্যান্ডার্ডাইজড উপায়। অন্যটি সেরা অ-মানক গ্রন্থাগার। সি ++ বিকাশকারীরা যখন হ্যাশম্যাপের প্রয়োজন হয় তখন তারা সাধারণত কী ব্যবহার করে?
ব্যবহারকারী 855

উত্তর:


237

স্ট্যান্ডার্ড লাইব্রেরিতে অর্ডারযুক্ত এবং অযৌক্তিক মানচিত্র ( std::mapএবং std::unordered_map) পাত্রে অন্তর্ভুক্ত রয়েছে। অর্ডার করা মানচিত্রে উপাদানগুলি কী দ্বারা বাছাই করা হয়, সন্নিবেশ করা এবং অ্যাক্সেস ও (লগ এন) এ থাকে । সাধারণত মানক পাঠাগারটি অভ্যন্তরীণভাবে অর্ডার করা মানচিত্রের জন্য লাল কালো গাছ ব্যবহার করে। তবে এটি কেবল একটি বাস্তবায়ন বিশদ। একটি অ-নিয়ন্ত্রিত মানচিত্রে সন্নিবেশ করুন এবং অ্যাক্সেস ও (1) এ রয়েছে। এটি হ্যাশটেবলের অন্য একটি নাম।

(অর্ডার) এর সাথে একটি উদাহরণ std::map:

#include <map>
#include <iostream>
#include <cassert>

int main(int argc, char **argv)
{
  std::map<std::string, int> m;
  m["hello"] = 23;
  // check if key is present
  if (m.find("world") != m.end())
    std::cout << "map contains key world!\n";
  // retrieve
  std::cout << m["hello"] << '\n';
  std::map<std::string, int>::iterator i = m.find("hello");
  assert(i != m.end());
  std::cout << "Key: " << i->first << " Value: " << i->second << '\n';
  return 0;
}

আউটপুট:

23
কী: হ্যালো মূল্য: 23

আপনার যদি আপনার ধারকটিতে অর্ডার দেওয়ার প্রয়োজন হয় এবং ও (লগ এন) রানটাইমের সাথে ভাল থাকেন তবে কেবল ব্যবহার করুন std::map

অন্যথায়, যদি আপনার সত্যিই একটি হ্যাশ-টেবিল (O (1) সন্নিবেশ / অ্যাক্সেস) প্রয়োজন হয় তবে দেখুন std::unordered_map, যা std::mapএপিআই এর অনুরূপ (যেমন উপরের উদাহরণে আপনাকে কেবল অনুসন্ধান এবং এর সাথে প্রতিস্থাপন mapকরতে হবে unordered_map)।

unordered_mapধারক সঙ্গে চালু করা হয় সি ++ 11 মান সংস্করণ। সুতরাং, আপনার সংকলকটির উপর নির্ভর করে আপনাকে সি ++ ১১ টি বৈশিষ্ট্য সক্ষম করতে হবে (যেমন জিসিসি ৪.৮ ব্যবহার -std=c++11করার সময় আপনাকে সিএক্সএক্সএফএলএজিএসে যুক্ত করতে হবে)।

সি ++ 11 প্রকাশের আগেও জিসিসি সমর্থিত unordered_map- নেমস্পেসে std::tr1। সুতরাং, পুরানো জিসিসি সংকলকগুলির জন্য আপনি এটি এটি ব্যবহার করার চেষ্টা করতে পারেন:

#include <tr1/unordered_map>

std::tr1::unordered_map<std::string, int> m;

এটি বুস্টেরও একটি অংশ, অর্থাত্ আপনি আরও ভাল বহনযোগ্যতার জন্য সংশ্লিষ্ট বুস্ট-শিরোনামটি ব্যবহার করতে পারেন ।


1
যদিও মান গ্রন্থাগার একটি হ্যাশ টেবিল ভিত্তিক ধারক নেই, প্রায় সব বাস্তবায়নের অন্তর্ভুক্ত কিছু ফর্ম বা অন্য SGI STL থেকে। hash_map
জেমস ম্যাকনেলিস

@ জেমস ম্যাকনেলিস যা হ্যাশম্যাপ বাস্তবায়নের জন্য অযৌক্তিক_ম্যাপ বা হ্যাশ_ম্যাপের পরামর্শ দেওয়া হচ্ছে
মোহাম্মদ

2
@ শামিলমোহ্মেদ, ২০১,, অর্থাৎ সি ++ ১১ এর 6 বছর পরে এটি সরবরাহ করে না এমন একটি এসটিএল খুঁজে পাওয়া শক্ত হওয়া উচিত unordered_map। সুতরাং, অ-মানক বিবেচনা করার কোনও কারণ নেই hash_map
ম্যাক্সচলেপজিগ

30

একটি hash_mapএকটি পুরোনো, প্রমিতকরণ উদ্দেশ্যে কি বলা হয় একটি এর unstandardized সংস্করণ unordered_map(মূলত TR1, এবং যেহেতু সি ++ 11 মান অন্তর্ভুক্ত)। নাম থেকেই বোঝা যায়, তা থেকে ভিন্ন std::mapunordered হচ্ছে প্রাথমিকভাবে - যদি, উদাহরণস্বরূপ, আপনি পুনরুক্তি থেকে একটি মানচিত্র মাধ্যমে begin()করতে end(), আপনি মূল দ্বারা অনুক্রমে আইটেম পাওয়া 1 , কিন্তু আপনি বারবার একটি মাধ্যমে যদি unordered_mapথেকে begin()থেকে end(), আপনি একটি আইটেম পেতে কমবেশি স্বেচ্ছাসেবী ক্রম।

একটি unordered_mapসাধারণত ধ্রুবক জটিলতা প্রত্যাশিত হয়। এটি কোনও সন্নিবেশ, অনুসন্ধান ইত্যাদি সাধারণত টেবিলে থাকা কতগুলি আইটেমই নির্বিশেষে মূলত একটি নির্দিষ্ট পরিমাণ সময় নেয়। একটিতে std::mapএমন জটিলতা রয়েছে যা সংরক্ষণ করা হচ্ছে এমন আইটেমের সংখ্যার উপর লোগারিথমিক - যার অর্থ একটি আইটেম সন্নিবেশ করানো বা পুনরুদ্ধারের সময়টি বৃদ্ধি পায় তবে মানচিত্রটি বড় হওয়ার সাথে সাথে ধীরে ধীরে । উদাহরণস্বরূপ, যদি 1 মিলিয়ন আইটেমগুলির মধ্যে একটি অনুসন্ধান করতে 1 মাইক্রোসেকেন্ড লাগে তবে আপনি আশা করতে পারেন যে এটি 2 মিলিয়ন আইটেমের মধ্যে একটি অনুসন্ধান করতে প্রায় 2 মাইক্রোসেকেন্ড নেবে, 4 মিলিয়ন আইটেমের মধ্যে 3 টি মাইক্রোসেকেন্ড, 8 মিলিয়নের একটির জন্য 4 মাইক্রোসেকেন্ড আইটেম, ইত্যাদি

ব্যবহারিক দৃষ্টিকোণ থেকে, যদিও এটি পুরো গল্পটি নয়। প্রকৃতির দ্বারা, একটি সাধারণ হ্যাশ টেবিলের একটি নির্দিষ্ট আকার থাকে। সাধারণ উদ্দেশ্যে ধারকটির জন্য পরিবর্তনশীল-আকারের প্রয়োজনীয়তার সাথে এটি মানিয়ে নেওয়া কিছুটা তুচ্ছ নয় is ফলস্বরূপ, টেবিলগুলি বাড়ানো (সম্ভাব্যভাবে) যে ক্রিয়াকলাপগুলি (উদাহরণস্বরূপ, সন্নিবেশ) সম্ভবত তুলনামূলকভাবে ধীরে ধীরে ধীরে ধীরে ধীরে ধীরে ধীরে ধীরে ধীরে ধীরে ধীরে ধীরে ধীরে ধীরে ধীরে ধীরে ধীরে ধীরে ধীরে ধীরে বেড়ে যায়। চেহারাগুলি, যা টেবিলের আকার পরিবর্তন করতে পারে না, সাধারণত অনেক দ্রুত হয়। ফলস্বরূপ, সন্নিবেশনের সংখ্যার তুলনায় আপনি অনেকগুলি অনুসন্ধান করতে গেলে বেশিরভাগ হ্যাশ-ভিত্তিক টেবিলগুলি তাদের সেরা হতে থাকে। এমন পরিস্থিতিতে যেখানে আপনি প্রচুর ডেটা সন্নিবেশ করান, তারপরে ফলাফল পুনরুদ্ধার করতে একবার টেবিলের মাধ্যমে পুনরাবৃত্তি করুন (উদাহরণস্বরূপ, কোনও ফাইলে অনন্য শব্দের সংখ্যা গণনা করা) সম্ভাবনাগুলি হ'লstd::map ঠিক তত দ্রুত এবং খুব সম্ভবত আরও দ্রুত হবে (তবে, আবার গণনা জটিলতা আলাদা, যাতে এটি ফাইলের অনন্য শব্দের সংখ্যার উপরও নির্ভর করতে পারে)।


1 আপনি যখন মানচিত্র তৈরি করবেন তখন তৃতীয় টেম্পলেট প্যারামিটার দিয়ে অর্ডার সংজ্ঞায়িত std::less<T>করা হবে default


1
আমি বুঝতে পেরেছি যে উত্তর পোস্ট হওয়ার 9 বছর পরে আসছি তবে ... আপনার কি কোনও ডকের সাথে একটি লিঙ্ক আছে যা একটি নিরক্ষিত মানচিত্রের আকারে সঙ্কুচিত হতে পারে তার উল্লেখ রয়েছে? সাধারণত, স্ট্যান্ডের সংগ্রহগুলি কেবল বৃদ্ধি পায়। তদুপরি, আপনি যদি প্রচুর ডেটা সন্নিবেশ করান তবে আপনি কতগুলি কী সন্নিবেশ করান তা কম বেশি আগে থেকে জেনে থাকেন তবে আপনি তৈরির ক্ষেত্রে মানচিত্রের আকার নির্দিষ্ট করতে পারেন যা মূলত পুনরায় আকারটি ব্যয়কে বাতিল করে দেয় (কারণ কোনও কিছুই হবে না) ।
জোনকো

@ জোনকো: দুঃখিত, জিজ্ঞাসা করার সময় আমি এটি লক্ষ্য করিনি। আমি যতদূর জানি, কল করার প্রতিক্রিয়া ব্যতীত একটি অর্ডারড_ম্যাপ সঙ্কুচিত হয় না rehash। আপনি যখন কল করবেন তখন আপনি rehashটেবিলের জন্য একটি আকার নির্দিষ্ট করবেন। এই আকারটি ব্যবহার করা হবে যদি না এটি করা সারণীর জন্য নির্দিষ্ট সর্বাধিক লোড ফ্যাক্টরটিকে অতিক্রম করে (তবে সেক্ষেত্রে লোড ফ্যাক্টরের সীমাতে রাখতে আকারটি স্বয়ংক্রিয়ভাবে বৃদ্ধি করা হবে))
জেরি কফিন

22

এখানে আরও একটি সম্পূর্ণ এবং নমনীয় উদাহরণ যা সংকলন ত্রুটিগুলি উত্পন্ন করার জন্য প্রয়োজনীয়গুলি বাদ দেয় না:

#include <iostream>
#include <unordered_map>

class Hashtable {
    std::unordered_map<const void *, const void *> htmap;

public:
    void put(const void *key, const void *value) {
            htmap[key] = value;
    }

    const void *get(const void *key) {
            return htmap[key];
    }

};

int main() {
    Hashtable ht;
    ht.put("Bob", "Dylan");
    int one = 1;
    ht.put("one", &one);
    std::cout << (char *)ht.get("Bob") << "; " << *(int *)ht.get("one");
}

এখনও কীগুলির জন্য বিশেষভাবে কার্যকর নয়, যদি না সেগুলি পয়েন্টার হিসাবে পূর্বনির্ধারিত করা হয়, কারণ একটি মিল মানটি না করে! (তবে, যেহেতু আমি সাধারণত কীগুলির জন্য স্ট্রিং ব্যবহার করি, তাই কীটির ঘোষণায় "কনস্টেট শূন্য *" এর জন্য "স্ট্রিং" প্রতিস্থাপন করলে এই সমস্যাটি সমাধান করা উচিত))


4
আমার বলতে হবে, এই উদাহরণটি C ++ এ খুব খারাপ অভ্যাস। আপনি একটি দৃ strongly়ভাবে টাইপ করা ভাষা ব্যবহার করছেন এবং এটি ব্যবহার করে এটি ধ্বংস করছেন void*। প্রারম্ভিকদের জন্য, মোড়ানোর কোনও কারণ নেই কারণ unordered_mapএটি স্ট্যান্ডার্ডের অংশ এবং কোড রক্ষণাবেক্ষণযোগ্যতা হ্রাস করে। এরপরে, যদি এটি মোড়ানো জেদ করে, ব্যবহার করুনtemplates । ঠিক এটাই তারা তাদের জন্য।
গিয়ারাড

জোরালোভাবে টাইপ করা? আপনি সম্ভবত স্ট্যাটিকালি টাইপ করা মানে। তিনি কন্সট চর পিটিআর থেকে নিঃশব্দে অকার্যকর হয়ে যেতে পারেন তা সি ++ স্থিতিশীল করে, তবে দৃ strongly়ভাবে টাইপ করা হয় না। প্রকারভেদ রয়েছে, তবে সংকলক কোনও কথা বলবে না আপনি যদি না কিছু অস্পষ্ট পতাকা সক্ষম করেন যা সম্ভবত উপস্থিত থাকে না।
সাহসাহে

6

std::unordered_mapজিসিসি stdlibc ++ 6.4 এ হ্যাশ ম্যাপ ব্যবহার করার প্রমাণ

এটি এখানে উল্লেখ করা হয়েছিল: https://stackoverflow.com/a/3578247/895245 তবে নিম্নলিখিত উত্তরে: সি ++ তে স্ট্যান্ড :: মানচিত্রের অভ্যন্তরে কোন ডেটা কাঠামো রয়েছে? আমি জিসিসি stdlibc ++ 6.4 বাস্তবায়নের জন্য এরকম আরও প্রমাণ দিয়েছি:

  • ক্লাসে ডিবিগিংয়ের জিডিবি পদক্ষেপ
  • কর্মক্ষমতা বৈশিষ্ট্যগত বিশ্লেষণ

এই উত্তরে বর্ণিত পারফরম্যান্স বৈশিষ্ট্যযুক্ত গ্রাফের পূর্বরূপ এখানে দেওয়া হয়েছে:

এখানে চিত্র বর্ণনা লিখুন

কীভাবে কাস্টম ক্লাস এবং হ্যাশ ফাংশন ব্যবহার করবেন unordered_map

এই উত্তরটি এটিকে নখ করে: C ++ আনর্ডার্ড_ম্যাপটি কী হিসাবে একটি কাস্টম শ্রেণীর ধরণ ব্যবহার করে

অংশ: সমতা:

struct Key
{
  std::string first;
  std::string second;
  int         third;

  bool operator==(const Key &other) const
  { return (first == other.first
            && second == other.second
            && third == other.third);
  }
};

হ্যাশ ফাংশন:

namespace std {

  template <>
  struct hash<Key>
  {
    std::size_t operator()(const Key& k) const
    {
      using std::size_t;
      using std::hash;
      using std::string;

      // Compute individual hash values for first,
      // second and third and combine them using XOR
      // and bit shifting:

      return ((hash<string>()(k.first)
               ^ (hash<string>()(k.second) << 1)) >> 1)
               ^ (hash<int>()(k.third) << 1);
    }
  };

}

0

আমরা যারা স্ট্যান্ডার্ড টেম্পলেট ব্যবহার করে এখনও আমাদের নিজস্ব ক্লাস হ্যাশ করব তা বোঝার চেষ্টা করার জন্য, একটি সহজ সমাধান রয়েছে:

  1. আপনার শ্রেণিতে আপনাকে একটি সমতা অপারেটর ওভারলোড বোঝাতে হবে ==। আপনি যদি এটি করতে না জানেন তবে গিকসফোরগিক্সের একটি দুর্দান্ত টিউটোরিয়াল রয়েছে https://www.geeksforgeeks.org/operator-overloading-c/

  2. স্ট্যান্ডার্ড নেমস্পেসের অধীনে, আপনার শ্রেণীর নাম সহ হ্যাশ নামে একটি টেম্পলেট কাঠামো প্রকার হিসাবে ঘোষণা করুন (নীচে দেখুন)) আমি একটি দুর্দান্ত ব্লগপোস্ট পেয়েছি যা এক্সওআর এবং বিটশিফিং ব্যবহার করে হ্যাশ গণনা করার উদাহরণও দেখায়, তবে এটি এই প্রশ্নের ক্ষেত্রের বাইরে নয়, তবে এটিতে হ্যাশ ফাংশনগুলি কীভাবে কীভাবে সম্পন্ন করা যায় সে সম্পর্কে বিস্তারিত নির্দেশাবলীও অন্তর্ভুক্ত রয়েছে https://prateekvjoshi.com/ 2014/06/05 / ব্যবহার-হ্যাশ ফাংশন-ইন-গ-জন্য-ব্যবহারকারী-সংজ্ঞায়িত-শ্রেণীর /

namespace std {

  template<>
  struct hash<my_type> {
    size_t operator()(const my_type& k) {
      // Do your hash function here
      ...
    }
  };

}
  1. আমি তখন আপনার নতুন হ্যাশ ফাংশন ব্যবহার করে একটি hashtable বাস্তবায়ন, আপনি শুধু একটি তৈরি করতে std::mapবা std::unordered_mapঠিক আপনি সাধারণত কি করবেন এবং ব্যবহার my_typeকী-এর মত, মানক গ্রন্থাগার স্বয়ংক্রিয়ভাবে হ্যাশ করার হ্যাশ ফাংশন আপনি আগে সংজ্ঞায়িত (ধাপ 2) ব্যবহার করা হবে আপনার চাবি
#include <unordered_map>

int main() {
  std::unordered_map<my_type, other_type> my_map;
}
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.