একটি স্ট্যান্ড :: মানচিত্র সন্নিবেশের ক্রমটি ট্র্যাক করে রাখে?


113

আমার কাছে বর্তমানে std::map<std::string,int>একটি অনন্য স্ট্রিং শনাক্তকরণের জন্য একটি পূর্ণসংখ্যার মান সঞ্চয় করে এবং আমি স্ট্রিংটি সন্ধান করি। এটি বেশিরভাগই আমি যা চাই তা করি তা ছাড়া এটি সন্নিবেশ ক্রমের উপর নজর রাখে না। সুতরাং যখন মানগুলি মুদ্রণের জন্য মানচিত্রটির পুনরাবৃত্তি করি তখন সেগুলি স্ট্রিং অনুসারে বাছাই করা হয়; তবে আমি এগুলি (প্রথম) সন্নিবেশের ক্রম অনুসারে বাছাই করা চাই।

আমি vector<pair<string,int>>পরিবর্তে ব্যবহারের কথা ভেবেছিলাম , তবে আমার প্রায় 10,000,000 বার স্ট্রিংটি এবং পূর্ণসংখ্যার মানগুলি বাড়ানো দরকার, তাই আমি জানি না যে std::vectorএটি উল্লেখযোগ্যভাবে ধীর হবে।

ব্যবহার করার কোনও উপায় আছে std::mapবা এমন কোনও stdধারক আছে যা আমার প্রয়োজনের সাথে আরও ভাল করে খাপ খায়?

[আমি জিসিসি ৩.৪ এ আছি এবং আমার মধ্যে সম্ভবত 50 জোড়ের বেশি মান নেই std::map]।

ধন্যবাদ।


8
ভাল স্ট্যান্ড আপ সময়ের জন্য স্ট্যান্ডার্ড :: ম্যাপটি এটি যাতে ক্রম অনুসারে বাছাই করা হয়েছে তা করতে হবে, তাই এটি বাইনারি অনুসন্ধান করতে পারে। শুধু আপনার পিষ্টক আছে এবং এটি খেতে পারে না!
বোবোবো

1
আপনি ফিরে ব্যবহার করে কি শেষ করেছেন?
অ্যাগসোল

উত্তর:


56

স্টাড :: ম্যাপে আপনার যদি 50 টি মান থাকে তবে আপনি প্রিন্ট আউট করার আগে স্টাড :: ভেক্টর এ অনুলিপি করতে পারেন এবং উপযুক্ত ফান্টর ব্যবহার করে std :: সাজানোর মাধ্যমে বাছাই করতে পারেন।

অথবা আপনি বুস্ট :: মাল্টি_ইন্ডেক্স ব্যবহার করতে পারেন । এটি বেশ কয়েকটি সূচী ব্যবহার করতে দেয়। আপনার ক্ষেত্রে এটি নীচের মত দেখতে পারে:

struct value_t {
      string s;
      int    i;
};
struct string_tag {};
typedef multi_index_container<
    value_t,
    indexed_by<
        random_access<>, // this index represents insertion order
        hashed_unique< tag<string_tag>, member<value_t, string, &value_t::s> >
    >
> values_t;

দারুণ! এমনকি বুস্টের একজন সদস্য-নির্বাচকও কাজটি করার জন্য রয়েছে!
xtofl

2
হ্যাঁ, মাল্টি_ইন্ডেক্স আমার উত্সাহে প্রিয় বৈশিষ্ট্য :)
কিরিল ভি লিয়াডভিনস্কি

3
@ ক্রিস্টো: এটি ধারক আকারের বিষয়ে নয়, ঠিক এই সমস্যার জন্য বিদ্যমান প্রয়োগকে পুনরায় ব্যবহার করার বিষয়ে। এটা উত্কৃষ্ট। স্বীকার করা, সি ++ একটি কার্যকরী ভাষা নয়, তাই বাক্য গঠনটি কিছুটা বিস্তৃত।
xtofl

4
কখন থেকে কী স্ট্রোক সংরক্ষণের বিষয়ে প্রোগ্রামিং করা হয়েছিল?
GManNGG

1
এই পোস্ট করার জন্য ধন্যবাদ। "ডামিগুলির জন্য বুস্ট মাল্টি-ইনডেক্স" বইটি কি আছে? আমি এটি ব্যবহার করতে পারি ...
ডোন উজ্জ্বল

25

আপনি একটি std::vectorসাথে একটি std::tr1::unordered_map(একটি হ্যাশ টেবিল) একত্রিত করতে পারেন । বুস্টের ডকুমেন্টেশনের জন্য এখানে একটি লিঙ্ক unordered_map। ঘন ঘন লুকআপ করার জন্য আপনি সন্নিবেশ ক্রম এবং হ্যাশ টেবিলের উপর নজর রাখতে ভেক্টর ব্যবহার করতে পারেন। আপনি যদি কয়েক হাজার লোগো করে থাকেন তবে std::mapহ্যাশ টেবিলের জন্য ও (লগ এন) অনুসন্ধান এবং ও (1) এর মধ্যে পার্থক্যটি উল্লেখযোগ্য হতে পারে।

std::vector<std::string> insertOrder;
std::tr1::unordered_map<std::string, long> myTable;

// Initialize the hash table and record insert order.
myTable["foo"] = 0;
insertOrder.push_back("foo");
myTable["bar"] = 0;
insertOrder.push_back("bar");
myTable["baz"] = 0;
insertOrder.push_back("baz");

/* Increment things in myTable 100000 times */

// Print the final results.
for (int i = 0; i < insertOrder.size(); ++i)
{
    const std::string &s = insertOrder[i];
    std::cout << s << ' ' << myTable[s] << '\n';
}

4
@xtofl, এটি কীভাবে আমার উত্তরকে সহায়ক করে না এবং এভাবে একটি ডাউনটাওয়েটের যোগ্য হয়? আমার কোডটি কি কোনওভাবে ভুল?
মাইকেল ক্রিস্টোফিক

এটি করার সেরা উপায় এটি। খুব সস্তা মেমরির ব্যয় (কেবলমাত্র 50 টি স্ট্রিংয়ের জন্য!), std::mapএটি যেমন অনুমিত হয় তার কাজ করতে দেয় (যেমন আপনি sertোকানো হিসাবে নিজেকে বাছাই করে) এবং দ্রুত রানটাইম রয়েছে। (আমি আমার সংস্করণটি লেখার পরে এটি পড়েছি, যেখানে আমি
স্টাড

আমি মনে করি স্টাডি :: ভেক্টর বা স্টাডি :: তালিকাটি স্বাদের বিষয়, এবং কোনটি ভাল তা পরিষ্কার নয়। (ভেক্টরের এলোমেলো অ্যাক্সেস রয়েছে যা প্রয়োজন হয় না, এর সাথে স্বচ্ছ মেমোরিও থাকে, যা প্রয়োজন হয় না। তালিকাটি সেই দুটি বৈশিষ্ট্যগুলির কোনওটির ব্যয় ছাড়াই অর্ডার সঞ্চয় করে রাখে, যেমন বাড়ার সময় পুনরুদ্ধার)।
অলিভার শানরোক

14

সমান্তরাল রাখুন list<string> insertionOrder

মুদ্রণের সময় হয়ে গেলে তালিকাটিতে পুনরাবৃত্তি করুন এবং মানচিত্রে লকআপ করুন ।

each element in insertionOrder  // walks in insertionOrder..
    print map[ element ].second // but lookup is in map

1
এটিও আমার প্রথম চিন্তা ছিল, তবে এটি দ্বিতীয় পাত্রে কীগুলি নকল করে, তাই না? একটি স্ট্যান্ড :: স্ট্রিং কী এর ক্ষেত্রে এটি উজ্জ্বল নয়, তাই না?
অলিভার শানরোক

2
C- এর @OliverSchonrock ++ ও 17, আপনি ব্যবহার করতে পারেন std::string_viewমানচিত্রের উল্লেখ করা কী জন্য std::stringinsertionOrderতালিকা। এটি অনুলিপি করা এড়ায় কিন্তু আপনাকে সাবধান হওয়া দরকার যে insertionOrderউপাদানগুলি মানচিত্রের কীগুলি তাদের উল্লেখ করে রেখেছে।
ফ্লাইএক্স

: আমি একটি ধারক যা এক বা মানচিত্র এবং তালিকা একত্রিত লেখার শেষ পর্যন্ত codereview.stackexchange.com/questions/233177/... কোন অনুলিপি
অলিভার Schönrock

10

টেসিলের অর্ডার করা মানচিত্রের একটি খুব সুন্দর বাস্তবায়ন রয়েছে (এবং সেট) যা এমআইটি লাইসেন্স। আপনি এটি এখানে খুঁজে পেতে পারেন: আদেশযুক্ত-মানচিত্র

মানচিত্রের উদাহরণ

#include <iostream>
#include <string>
#include <cstdlib>
#include "ordered_map.h"

int main() {
tsl::ordered_map<char, int> map = {{'d', 1}, {'a', 2}, {'g', 3}};
map.insert({'b', 4});
map['h'] = 5;
map['e'] = 6;

map.erase('a');


// {d, 1} {g, 3} {b, 4} {h, 5} {e, 6}
for(const auto& key_value : map) {
    std::cout << "{" << key_value.first << ", " << key_value.second << "}" << std::endl;
}


map.unordered_erase('b');

// Break order: {d, 1} {g, 3} {e, 6} {h, 5}
for(const auto& key_value : map) {
    std::cout << "{" << key_value.first << ", " << key_value.second << "}" << std::endl;
}
}

4

আপনার যদি উভয় অনুসন্ধান কৌশল প্রয়োজন হয় তবে আপনার দুটি পাত্রে শেষ হবে। আপনি vectorআপনার প্রকৃত মান ( intগুলি) এর সাথে একটি ব্যবহার করতে পারেন এবং map< string, vector< T >::difference_type> এটির পাশে একটি ভেল্টারে সূচকটি ফেরত দিতে পারেন।

এই সমস্ত সম্পূর্ণ করতে, আপনি উভয়ই একটি শ্রেণিতে সজ্জিত করতে পারেন।

তবে আমি বিশ্বাস করি বুস্টের একাধিক সূচকের ধারক রয়েছে।


3

আপনি যা চান (বুস্টের অবলম্বন না করে) তাকেই আমি "অর্ডার করা হ্যাশ" বলি, যা মূলত একটি হ্যাশের ম্যাসআপ এবং স্ট্রিং বা পূর্ণসংখ্যা কীগুলির সাথে যুক্ত লিঙ্কযুক্ত তালিকা (বা উভয় একই সময়ে) both একটি আদেশযুক্ত হ্যাশ একটি হ্যাশের সম্পূর্ণ পারফরম্যান্সের সাথে পুনরাবৃত্তির সময় উপাদানগুলির ক্রম বজায় রাখে।

আমি তুলনামূলকভাবে নতুন সি ++ স্নিপেট লাইব্রেরি একসাথে রেখেছি যা আমি সি ++ গ্রন্থাগার বিকাশকারীদের জন্য সি ++ ভাষার গর্ত হিসাবে পূরণ করি। এখানে যাও:

https://github.com/cubiclesoft/cross-platform-cpp

দখল:

templates/detachable_ordered_hash.cpp
templates/detachable_ordered_hash.h
templates/detachable_ordered_hash_util.h

যদি ব্যবহারকারী-নিয়ন্ত্রিত ডেটা হ্যাশের মধ্যে স্থাপন করা হয় তবে আপনি এটিও চাইতে পারেন:

security/security_csprng.cpp
security/security_csprng.h

এটি আহ্বান:

#include "templates/detachable_ordered_hash.h"
...
// The 47 is the nearest prime to a power of two
// that is close to your data size.
//
// If your brain hurts, just use the lookup table
// in 'detachable_ordered_hash.cpp'.
//
// If you don't care about some minimal memory thrashing,
// just use a value of 3.  It'll auto-resize itself.
int y;
CubicleSoft::OrderedHash<int> TempHash(47);
// If you need a secure hash (many hashes are vulnerable
// to DoS attacks), pass in two randomly selected 64-bit
// integer keys.  Construct with CSPRNG.
// CubicleSoft::OrderedHash<int> TempHash(47, Key1, Key2);
CubicleSoft::OrderedHashNode<int> *Node;
...
// Push() for string keys takes a pointer to the string,
// its length, and the value to store.  The new node is
// pushed onto the end of the linked list and wherever it
// goes in the hash.
y = 80;
TempHash.Push("key1", 5, y++);
TempHash.Push("key22", 6, y++);
TempHash.Push("key3", 5, y++);
// Adding an integer key into the same hash just for kicks.
TempHash.Push(12345, y++);
...
// Finding a node and modifying its value.
Node = TempHash.Find("key1", 5);
Node->Value = y++;
...
Node = TempHash.FirstList();
while (Node != NULL)
{
  if (Node->GetStrKey())  printf("%s => %d\n", Node->GetStrKey(), Node->Value);
  else  printf("%d => %d\n", (int)Node->GetIntKey(), Node->Value);

  Node = Node->NextList();
}

আমার গবেষণা পর্যায়ে আমি এই এস থ্রেডে দৌড়ে এসেছি যে অর্ডারহ্যাশের মতো কোনও কিছু ইতিমধ্যে আমার কাছে কোনও বৃহত লাইব্রেরিতে না নামার প্রয়োজন আছে কিনা তা দেখার জন্য। আমি হতাশ ছিলাম. তাই আমি আমার নিজের লিখেছি। এবং এখন আমি এটি ভাগ করে নিয়েছি।


2

আপনি মানচিত্রের সাহায্যে এটি করতে পারবেন না, তবে আপনি দুটি পৃথক কাঠামো ব্যবহার করতে পারেন - মানচিত্র এবং ভেক্টর এবং সেগুলিকে সিঙ্ক্রোনাইজ রাখতে পারেন - এটি যখন আপনি মানচিত্র থেকে মুছবেন, ভেক্টর থেকে উপাদানটি সন্ধান করুন এবং মুছবেন। অথবা আপনি একটি তৈরি করতে পারেন map<string, pair<int,int>>- এবং আপনার জোড়ায় মানচিত্রের আকার () সন্নিবেশের উপর অবস্থানটি রেকর্ড করতে ইন্টের মান সহ, এবং তারপরে আপনি যখন মুদ্রণ করবেন তখন অবস্থান সদস্যকে বাছাই করতে ব্যবহার করুন।


2

এটি প্রয়োগের আরেকটি উপায় হ'ল একটি এর mapপরিবর্তে vector। আমি আপনাকে এই পদ্ধতিটি দেখাব এবং পার্থক্যগুলি নিয়ে আলোচনা করব:

পর্দার পিছনে দুটি মানচিত্র রয়েছে এমন একটি শ্রেণী তৈরি করুন।

#include <map>
#include <string>

using namespace std;

class SpecialMap {
  // usual stuff...

 private:
  int counter_;
  map<int, string> insertion_order_;
  map<string, int> data_;
};

তারপরে আপনি data_যথাযথ ক্রমে একটি পুনরাবৃত্তিকে পুনরুক্তি করতে পারবেন । আপনি যেভাবে এটি করেন তা হ'ল পুনরাবৃত্তি insertion_order_এবং প্রতিটি উপাদানটির জন্য আপনি সেই পুনরাবৃত্তিটি থেকে পেয়ে যাবেন data_সেখান থেকে মান সহ একটি সন্ধান করুনinsertion_order_

আপনি hash_mapiteোকানো_অর্ডারের জন্য আরও দক্ষ ব্যবহার করতে পারেন যেহেতু আপনি সরাসরি পুনরাবৃত্তি করার বিষয়ে চিন্তা করেন না insertion_order_

সন্নিবেশগুলি করতে, আপনার এই জাতীয় পদ্ধতি থাকতে পারে:

void SpecialMap::Insert(const string& key, int value) {
  // This may be an over simplification... You ought to check
  // if you are overwriting a value in data_ so that you can update
  // insertion_order_ accordingly
  insertion_order_[counter_++] = key;
  data_[key] = value;
}

আপনি নকশাটিকে আরও উন্নত করতে এবং পারফরম্যান্স সম্পর্কে চিন্তিত করতে পারেন এমন অনেকগুলি উপায় রয়েছে তবে আপনি নিজেরাই এই কার্যকারিতা বাস্তবায়নের জন্য শুরু করার জন্য এটি একটি ভাল কঙ্কাল। আপনি এটিকে টেম্পলেটেড করে তুলতে পারেন, এবং আপনি সম্ভবত ডেটা_তে জোড়গুলি মান হিসাবে সংরক্ষণ করতে পারেন যাতে আপনি সহজেই সন্নিবেশ_আর্ডার_-এ প্রবেশদ্বারটি উল্লেখ করতে পারেন। তবে আমি এই নকশাগুলির বিষয়গুলি অনুশীলন হিসাবে ছেড়ে দিচ্ছি :-)।

আপডেট : আমি মনে করি সন্নিবেশ_অর্ডার_এর জন্য ভেক্টর বনাম ভেক্টর ব্যবহারের দক্ষতা সম্পর্কে আমার কিছু বলা উচিত supp

  • উভয় ক্ষেত্রেই সরাসরি ডেটাতে অনুসন্ধান করা হয় ও (1)
  • ভেক্টর পদ্ধতির সন্নিবেশগুলি হ'ল (1), মানচিত্রের পদ্ধতির সন্নিবেশগুলি হ'ল (লগইন)
  • ভেক্টর পদ্ধতির মোছা হ'ল ও (এন) কারণ আইটেমটি অপসারণ করার জন্য আপনাকে স্ক্যান করতে হবে। মানচিত্রের পদ্ধতির সাথে তারা ও (লগইন)।

সম্ভবত আপনি যদি মুছে ফেলা যতটা ব্যবহার না করে থাকেন তবে আপনার ভেক্টর পদ্ধতির ব্যবহার করা উচিত। যদি আপনি সন্নিবেশ ক্রমের পরিবর্তে কোনও ভিন্ন ক্রম (অগ্রাধিকারের মতো) সমর্থন করে থাকেন তবে মানচিত্রের পদ্ধতিরটি আরও ভাল।


"সন্নিবেশ আইডি" দ্বারা আইটেমগুলি নেওয়া দরকার হলে মানচিত্রের পদ্ধতিরও আরও ভাল। উদাহরণস্বরূপ, আপনি যদি 5 ম wasোকানো আইটেমটি চান, আপনি কী 5 (বা 4, যেখানে আপনি কাউন্টার শুরু করবেন) তার উপর নির্ভর করে সন্নিবেশ_অর্ডারে একটি অনুসন্ধান করুন। ভেক্টর পদ্ধতির সাথে, যদি 5 ম আইটেমটি মুছে ফেলা হয় তবে আপনি আসলে theোকানো 6 তম আইটেমটি পাবেন।
টম

2

এখানে এমন সমাধান রয়েছে যার জন্য বুস্টের মাল্টিইন্ডেক্স ব্যবহার না করে কেবলমাত্র স্ট্যান্ডার্ড টেম্পলেট লাইব্রেরির প্রয়োজন:
আপনি ব্যবহার করতে পারেন std::map<std::string,int>;এবং vector <data>;মানচিত্রে আপনি ভেক্টারে ডেটার অবস্থানের সূচকটি এবং ভেক্টর স্টোরের তথ্য সন্নিবেশ ক্রমে সংরক্ষণ করেন। এখানে ডেটা অ্যাক্সেসে ও (লগ এন) জটিলতা রয়েছে। সন্নিবেশ ক্রমে ডেটা প্রদর্শন করার ক্ষেত্রে ও (এন) জটিলতা রয়েছে। ডেটা সন্নিবেশকরণে ও (লগ এন) জটিলতা রয়েছে।

উদাহরণ স্বরূপ:

#include<iostream>
#include<map>
#include<vector>

struct data{
int value;
std::string s;
}

typedef std::map<std::string,int> MapIndex;//this map stores the index of data stored 
                                           //in VectorData mapped to a string              
typedef std::vector<data> VectorData;//stores the data in insertion order

void display_data_according_insertion_order(VectorData vectorData){
    for(std::vector<data>::iterator it=vectorData.begin();it!=vectorData.end();it++){
        std::cout<<it->value<<it->s<<std::endl;
    }
}
int lookup_string(std::string s,MapIndex mapIndex){
    std::MapIndex::iterator pt=mapIndex.find(s)
    if (pt!=mapIndex.end())return it->second;
    else return -1;//it signifies that key does not exist in map
}
int insert_value(data d,mapIndex,vectorData){
    if(mapIndex.find(d.s)==mapIndex.end()){
        mapIndex.insert(std::make_pair(d.s,vectorData.size()));//as the data is to be
                                                               //inserted at back 
                                                               //therefore index is
                                                               //size of vector before
                                                               //insertion
        vectorData.push_back(d);
        return 1;
    }
    else return 0;//it signifies that insertion of data is failed due to the presence
                  //string in the map and map stores unique keys
}

1

এটি কিছুটা ফয়সাল উত্তরের সাথে সম্পর্কিত। আপনি কেবল একটি মানচিত্র এবং ভেক্টরের চারপাশে একটি মোড়কের ক্লাস তৈরি করতে এবং এগুলিকে সহজেই সিঙ্ক্রোনাইজ রাখতে পারেন। যথাযথ এনক্যাপসুলেশন আপনাকে অ্যাক্সেস পদ্ধতি নিয়ন্ত্রণ করতে দেয় এবং সেইজন্য কোন ধারকটি ব্যবহার করবে ... ভেক্টর বা মানচিত্র। এটি বুস্ট বা এ জাতীয় কিছু ব্যবহার করা এড়িয়ে যায়।


1

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


1

// এই মানুষটির মতো হওয়া উচিত!

// এটি সন্নিবেশকরণের জটিলতা বজায় রাখে ও (লগএন) এবং মুছে ফেলাও ও (লগএন) হয়।

class SpecialMap {
private:
  int counter_;
  map<int, string> insertion_order_;
  map<string, int> insertion_order_reverse_look_up; // <- for fast delete
  map<string, Data> data_;
};


-1

জোড়ার মানচিত্র (স্ট্রিং, ইনট) এবং স্ট্যাটিক ইনট যা সন্নিবেশে ইনক্রিমেন্টগুলি ইনডেক্সকে ডেটা জোড়া বলে। এমন একটি কাঠামো রাখুন যা কোনও সূচক () সদস্যের সাথে স্ট্যাটিক ইনট ভ্যালুকে ফিরে আসতে পারে?


2
আপনার একটি উদাহরণ যুক্ত করা উচিত।
m02ph3u5
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.