সি তে অভিধান প্রয়োগ করার দ্রুত উপায়


132

সি-তে প্রোগ্রাম লেখার সময় আমি যে জিনিসগুলি মিস করি তার মধ্যে একটি হ'ল অভিধানের কাঠামো। সি-তে একটি কার্যকর করার সবচেয়ে সুবিধাজনক উপায় কোনটি? আমি পারফরম্যান্স খুঁজছি না, তবে এটিকে স্ক্র্যাচ থেকে কোড করা সহজ ease আমি চাই না যে এটি জেনেরিক হোক - স্ট্রিং-> ইনট এর মতো কিছু করবে। তবে আমি চাই এটি একটি স্বেচ্ছাসেবী সংখ্যক আইটেম সংরক্ষণ করতে সক্ষম হোক।

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


4
যদি আপনি এটি সরবরাহ করে থাকেন তবে আপনি যদি তৃতীয় পক্ষের প্রয়োগ ব্যবহার না করে স্ক্র্যাচ থেকে এটি তৈরি করতে চান তবে কেন?
কার্ল নচেটেল

হ্যাঁ, সেই বিকল্পটি সর্বদা বিদ্যমান। আমি এই প্রশ্নটি অনুশীলন হিসাবে আরও উত্থাপন করেছি।
রোহিত

10
সি তে হ্যাশটেবল লেখা মজাদার অনুশীলন - প্রতিটি সিরিয়াস সি প্রোগ্রামার কমপক্ষে একবার এটি করা উচিত।
লি

আমি একটি অভিধানকে ডেটাস্ট্রাকচারের পরিবর্তে ডেটাটাইপ বলে মনে করি, যেহেতু এটি প্রচুর উপায়ে প্রয়োগ করা যেতে পারে - একটি তালিকা, একটি হ্যাশটেবল, একটি গাছ, একটি স্ব-ভারসাম্য গাছ ইত্যাদি আপনি কি অভিধান বা হ্যাশটেবল চাইছেন? ?
পল হানকিন

1
সম্পর্কিত: সি-তে পাইথন-এর মতো অভিধানটি কীভাবে উপস্থাপন করবেন? [] ( স্ট্যাকওভারফ্লো / প্রশ্ন / 69২69৯৮৮১/২ )
গৌরাঙ্গ ট্যান্ডন

উত্তর:


114

সি প্রোগ্রামিং ল্যাঙ্গুয়েজের বিভাগ 6.। একটি সাধারণ অভিধান (হ্যাশটেবল) ডেটা কাঠামো উপস্থাপন করে। আমি মনে করি না যে একটি কার্যকর অভিধান বাস্তবায়ন এর চেয়ে সহজতর কোনও পেতে পারে। আপনার সুবিধার জন্য, আমি এখানে কোড পুনরুত্পাদন।

struct nlist { /* table entry: */
    struct nlist *next; /* next entry in chain */
    char *name; /* defined name */
    char *defn; /* replacement text */
};

#define HASHSIZE 101
static struct nlist *hashtab[HASHSIZE]; /* pointer table */

/* hash: form hash value for string s */
unsigned hash(char *s)
{
    unsigned hashval;
    for (hashval = 0; *s != '\0'; s++)
      hashval = *s + 31 * hashval;
    return hashval % HASHSIZE;
}

/* lookup: look for s in hashtab */
struct nlist *lookup(char *s)
{
    struct nlist *np;
    for (np = hashtab[hash(s)]; np != NULL; np = np->next)
        if (strcmp(s, np->name) == 0)
          return np; /* found */
    return NULL; /* not found */
}

char *strdup(char *);
/* install: put (name, defn) in hashtab */
struct nlist *install(char *name, char *defn)
{
    struct nlist *np;
    unsigned hashval;
    if ((np = lookup(name)) == NULL) { /* not found */
        np = (struct nlist *) malloc(sizeof(*np));
        if (np == NULL || (np->name = strdup(name)) == NULL)
          return NULL;
        hashval = hash(name);
        np->next = hashtab[hashval];
        hashtab[hashval] = np;
    } else /* already there */
        free((void *) np->defn); /*free previous defn */
    if ((np->defn = strdup(defn)) == NULL)
       return NULL;
    return np;
}

char *strdup(char *s) /* make a duplicate of s */
{
    char *p;
    p = (char *) malloc(strlen(s)+1); /* +1 for ’\0’ */
    if (p != NULL)
       strcpy(p, s);
    return p;
}

মনে রাখবেন যে দুটি স্ট্রিংয়ের হ্যাশগুলি যদি সংঘর্ষ হয়, তবে এটি O(n)অনুসন্ধানের সময় নিয়ে যেতে পারে । এর মান বাড়িয়ে সংঘর্ষের সম্ভাবনা হ্রাস করতে পারেন HASHSIZE। ডেটা কাঠামোর সম্পূর্ণ আলোচনার জন্য, দয়া করে বইটি দেখুন।


1
এটি যদি সি বই থেকে আসে তবে আমি আরও অবাক হচ্ছি যে আরও কমপ্যাক্ট বাস্তবায়ন হতে পারে কিনা।
রোহিত

30
@ রোহিত, কিছু দরকারী সি কোডের জন্য, এটি এর চেয়ে বেশি কমপ্যাক্ট পায় না। আমি মনে করি আপনি সর্বদা কিছু সাদা জায়গা সরিয়ে ফেলতে পারেন ...
রায়ান ক্যালহাউন

7
কেন hashval = *s + 31 * hashval;ঠিক এখানে 31 এবং অন্য কিছু না?
レ ッ ク ス

12
31 প্রধান। সংঘর্ষের সম্ভাবনা কমাতে প্রায়শই প্রাইজগুলি হ্যাশ ফাংশনে ব্যবহৃত হয়। এটি পূর্ণসংখ্যার ফ্যাক্টরীকরণের সাথে কিছু করার আছে (যেমন আপনি প্রাইমকে ফ্যাক্ট করতে পারবেন না)।
jnovacho

2
@ ওভারড্রাইভার: এই ক্ষেত্রে প্রয়োজনীয় নয়। হ্যাশটব স্থির সময়সীমার হয়। স্থির সময়কালের সাথে একনীতিবিহীন ভেরিয়েবলগুলি (যেগুলি ফাংশনের বাইরে ঘোষণা করা এবং স্টোরেজ শ্রেণীর স্ট্যাটিকের সাথে ঘোষিত), সঠিক ধরণের শূন্য হিসাবে
উদ্বোধনের

19

দ্রুততম উপায় মত ইতিমধ্যেই বিদ্যমান বাস্তবায়ন ব্যবহার করার হবে uthash

এবং, আপনি যদি সত্যিই এটিকে কোড করতে চান, তবে অ্যালগরিদমগুলি uthashপরীক্ষা করে আবার ব্যবহার করা যেতে পারে। এটি বিএসডি-লাইসেন্সযুক্ত তাই কপিরাইট নোটিশ দেওয়ার প্রয়োজন ব্যতীত, আপনি এটির সাথে যা করতে পারেন তাতে আপনি বেশ সীমাহীন।


8

বাস্তবায়নের স্বাচ্ছন্দ্যের জন্য, অ্যারের মাধ্যমে নির্লজ্জভাবে অনুসন্ধান করা শক্ত। কিছু ত্রুটি যাচাইয়ের পাশাপাশি, এটি একটি সম্পূর্ণ বাস্তবায়ন (অনির্ধারিত)।

typedef struct dict_entry_s {
    const char *key;
    int value;
} dict_entry_s;

typedef struct dict_s {
    int len;
    int cap;
    dict_entry_s *entry;
} dict_s, *dict_t;

int dict_find_index(dict_t dict, const char *key) {
    for (int i = 0; i < dict->len; i++) {
        if (!strcmp(dict->entry[i], key)) {
            return i;
        }
    }
    return -1;
}

int dict_find(dict_t dict, const char *key, int def) {
    int idx = dict_find_index(dict, key);
    return idx == -1 ? def : dict->entry[idx].value;
}

void dict_add(dict_t dict, const char *key, int value) {
   int idx = dict_find_index(dict, key);
   if (idx != -1) {
       dict->entry[idx].value = value;
       return;
   }
   if (dict->len == dict->cap) {
       dict->cap *= 2;
       dict->entry = realloc(dict->entry, dict->cap * sizeof(dict_entry_s));
   }
   dict->entry[dict->len].key = strdup(key);
   dict->entry[dict->len].value = value;
   dict->len++;
}

dict_t dict_new(void) {
    dict_s proto = {0, 10, malloc(10 * sizeof(dict_entry_s))};
    dict_t d = malloc(sizeof(dict_s));
    *d = proto;
    return d;
}

void dict_free(dict_t dict) {
    for (int i = 0; i < dict->len; i++) {
        free(dict->entry[i].key);
    }
    free(dict->entry);
    free(dict);
}

2
"বাস্তবায়নের স্বাচ্ছন্দ্যের জন্য": আপনি ঠিক বলেছেন: এটি সবচেয়ে সহজ। এছাড়াও এটি ওপি-র অনুরোধটিকে বাস্তবায়িত করে "আমি এটি একটি নির্বিচার সংখ্যক আইটেম সংরক্ষণ করতে সক্ষম হতে চাই" - সর্বোচ্চ ভোট প্রাপ্ত উত্তরটি তা করে না (যদি না আপনি বিশ্বাস করেন যে একটি সংকলিত সময় বেছে নেওয়া ধীরে ধীরে "স্বেচ্ছাসেবক" সন্তুষ্ট হয় ...)
ডেভিডবাক

1
এটি ব্যবহারের ক্ষেত্রে নির্ভর করে একটি বৈধ পন্থা হতে পারে, তবে ওপি স্পষ্টভাবে একটি অভিধানের জন্য অনুরোধ করেছে, এবং এটি অবশ্যই অভিধান নয়।
ড্যান বেচার্ড

3

একটি হ্যাশ ফাংশন এবং কাঠামোর কয়েকটি সংযুক্ত তালিকাগুলি তৈরি করুন, হ্যাশের উপর নির্ভর করে কোন লিঙ্কযুক্ত তালিকাটি মান সন্নিবেশ করানোর জন্য নির্ধারণ করুন। এটি পুনরুদ্ধারের জন্য হ্যাশটি ব্যবহার করুন।

কিছুক্ষণ আগে আমি একটি সাধারণ বাস্তবায়ন করেছি:

...
# ডিফাইন কে 16 // শৃঙ্খলা সহগ

কাঠামো
{
    চর * নাম; / * কী এর নাম * /
    ইন্ট ভাল; / * মান * /
    স্ট্রাক ডিক * পরবর্তী; / * লিঙ্ক ক্ষেত্র * /
};

টাইপডেফ স্ট্রাক্ট ডোক;
ডিক * টেবিল [কে];
int প্রারম্ভিক = 0;


অকার্যকর পুটওয়াল (চর *, ইনট);

অকার্যকর init_dict ()
{   
    প্রারম্ভিক = 1;
    int i;  
    (i = 0; iname = (চর *) ম্যালোক (স্ট্রেন (কী_নাম) +1) এর জন্য;
    ptr-> val = sval;
    strcpy (ptr-> নাম, কী_নাম);


    ptr-> পরের = (স্ট্রাক ডিক্ট *) সারণী [এইচএসএস];
    টেবিল [hsh] = পিটিআর;

}


int getval (চর * কী_নাম)
{   
    int hsh = hash (key_name);   
    ডিক * পিটিআর;
    (পিটিআর = টেবিল [এইচএসএস]; পিটিআর! = (ডিক *) 0;
        ptr = (ডিক্ট *) পিটিআর-> পরবর্তী)
    যদি (strcmp (ptr-> নাম, কী_নাম) == 0)
        পিটিআর-> ভাল;
    প্রত্যাবর্তন -1;
}

1
আপনি কি অর্ধেক কোডটি মিস করছেন না? "হ্যাশ ()" এবং "পুতাল ()" কোথায়?
swDP

3

GLib এবং gnulib

আপনার যদি আরও নির্দিষ্ট প্রয়োজনীয়তা না থাকে তবে এগুলি আপনার সম্ভাব্য সেরা বেটস, যেহেতু তারা ব্যাপকভাবে উপলব্ধ, বহনযোগ্য এবং সম্ভবত দক্ষ।

  • জিএলিব: জিনোম প্রকল্পের মাধ্যমে https://developer.gnome.org/glib/ "হ্যাশ টেবিলগুলি" এবং "ভারসাম্য বাইনারি গাছগুলি" সহ বেশ কয়েকটি পাত্রে নথিভুক্ত রয়েছে: https://developer.gnome.org/glib/stable/glib-data-types.html লাইসেন্স: এলজিপিএল

  • gnulib: https://www.gnu.org/software/gnulib/ GNU প্রকল্প দ্বারা / আপনি আপনার কোডটিতে উত্সটি অনুলিপি করার জন্য বোঝানো হচ্ছে। বেশ কয়েকটি পাত্রে নথিভুক্ত রয়েছে: https://www.gnu.org/software/gnulib/MODULES.html#ansic_ext_container সহ "rbtree- তালিকা", "লিঙ্কড্যাশ-তালিকা" এবং "rbtreehash- তালিকা"। জিপিএল লাইসেন্স।

আরও দেখুন: সাধারণ ডেটা স্ট্রাকচার সহ কোনও ওপেন সোর্স সি লাইব্রেরি আছে কি?


2

এখানে একটি দ্রুত বাস্তবায়ন করা হয়েছে, আমি একটি স্ট্রিং থেকে 'ম্যাট্রিক্স' (স্ক্র্ট) পেতে এটি ব্যবহার করেছি। আপনি একটি বড় অ্যারে থাকতে পারে এবং রান চলাকালীন তার মান পরিবর্তন করতে পারেন:

typedef struct  { int** lines; int isDefined; }mat;
mat matA, matB, matC, matD, matE, matF;

/* an auxilary struct to be used in a dictionary */
typedef struct  { char* str; mat *matrix; }stringToMat;

/* creating a 'dictionary' for a mat name to its mat. lower case only! */
stringToMat matCases [] =
{
    { "mat_a", &matA },
    { "mat_b", &matB },
    { "mat_c", &matC },
    { "mat_d", &matD },
    { "mat_e", &matE },
    { "mat_f", &matF },
};

mat* getMat(char * str)
{
    stringToMat* pCase;
    mat * selected = NULL;
    if (str != NULL)
    {
        /* runing on the dictionary to get the mat selected */
        for(pCase = matCases; pCase != matCases + sizeof(matCases) / sizeof(matCases[0]); pCase++ )
        {
            if(!strcmp( pCase->str, str))
                selected = (pCase->matrix);
        }
        if (selected == NULL)
            printf("%s is not a valid matrix name\n", str);
    }
    else
        printf("expected matrix name, got NULL\n");
    return selected;
}

2

আমি আশ্চর্য হয়েছি যে কেউ লাইব্রেরির hsearch / hcreate সেট উল্লেখ করেনি যা উইন্ডোতে উপলভ্য নয় তবে পসিক্স দ্বারা বাধ্যতামূলক এবং লিনাক্স / জিএনইউ সিস্টেমে উপলব্ধ available

লিঙ্কটির একটি সহজ এবং সম্পূর্ণ মৌলিক উদাহরণ রয়েছে যা এর ব্যবহারটি খুব ভালভাবে ব্যাখ্যা করে।

এটিতে থ্রেড নিরাপদ বৈকল্পিক রয়েছে, ব্যবহার করা সহজ এবং খুব পারফর্মেন্ট।


2
: তিনি লক্ষ করেন এখানে মানুষ বলে এটা অব্যবহারযোগ্য ধরনের, যদিও আমি নিজেকে চেষ্টা করিনি ওয়ার্থ stackoverflow.com/a/6118591/895245
সিরো Santilli郝海东冠状病六四事件法轮功

1
যথেষ্ট উপযুক্ত, তবে, আমি অন্তত একটি অ্যাপ্লিকেশনটিতে hcreate_r (একাধিক হ্যাশ টেবিলের জন্য) সংস্করণটি চেষ্টা করেছি যা এটি বাস্তব বিশ্বের বিবেচনা করার জন্য যথেষ্ট দীর্ঘ সময় ধরে চলেছিল। সম্মত হয়েছেন যে এটি একটি জিএনইউ সম্প্রসারণ তবে তারপরে এটি অন্যান্য অনেকগুলি লিবার ক্ষেত্রেও। যদিও আমি এখনও তর্ক করব যে আপনি এখনও কিছু বড় ওয়ার্ল্ড অ্যাপ্লিকেশনটিতে পরিচালিত একটি বড় মূল মান জুটির জন্য এটি ব্যবহার করতে সক্ষম হতে পারেন
fkl

0

একটি হ্যাশটেবল হ'ল একটি সাধারণ "অভিধান" এর traditionalতিহ্যগত প্রয়োগ। আপনি যদি গতি বা আকার সম্পর্কে চিন্তা না করেন তবে কেবল এটির জন্য গুগল করুন । অবাধে উপলভ্য অনেকগুলি বাস্তবায়ন রয়েছে।

এখানে আমি প্রথম দেখেছি - এক নজরে, এটি আমার কাছে ঠিক আছে। (এটি বেশ বেসিক।

শুভকামনা!


-1

হ্যাশিং চাবিকাঠি। আমি মনে করি এটির জন্য লুকিং টেবিল এবং হ্যাশিং কী ব্যবহার করুন। আপনি অনলাইনে অনেক হ্যাশিং ফাংশন খুঁজে পেতে পারেন।


-1

দ্রুততম পদ্ধতিটি বাইনারি ট্রি ব্যবহার করা হবে। এটির সবচেয়ে খারাপ পরিস্থিতি কেবল ও (লগইন) is


15
এটি ভুল। বাইনারি গাছের জন্য সবচেয়ে খারাপ কেস সন্ধানের বিষয়টি হ'ল ভারসাম্যহীন হলে ও (এন) (খারাপ সন্নিবেশ ক্রমের কারণে অধঃপতন কেস, যার ফলে একটি লিঙ্ক তালিকার ফলস্বরূপ) হয়।
র্যান্ডি হাওয়ার্ড
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.