hash_chaining.c

Download
c 368 lines 10.2 KB
  1/*
  2 * hash_chaining.c
  3 * ์ฒด์ด๋‹(Separate Chaining)์„ ์ด์šฉํ•œ ํ•ด์‹œ ํ…Œ์ด๋ธ” ๊ตฌํ˜„
  4 *
  5 * ์ฒด์ด๋‹ ๋ฐฉ์‹:
  6 * - ์ถฉ๋Œ ๋ฐœ์ƒ ์‹œ ๊ฐ™์€ ๋ฒ„ํ‚ท์— ์—ฐ๊ฒฐ ๋ฆฌ์ŠคํŠธ๋กœ ์ €์žฅ
  7 * - ์žฅ์ : ์‚ฝ์ž…/์‚ญ์ œ ๊ฐ„๋‹จ, ํ…Œ์ด๋ธ” ํฌ๊ธฐ ์ œํ•œ ์—†์Œ
  8 * - ๋‹จ์ : ํฌ์ธํ„ฐ ์ถ”๊ฐ€ ๋ฉ”๋ชจ๋ฆฌ, ์บ์‹œ ํšจ์œจ ๋‚ฎ์Œ
  9 */
 10
 11#include <stdio.h>
 12#include <stdlib.h>
 13#include <string.h>
 14#include <stdbool.h>
 15
 16#define TABLE_SIZE 10
 17#define KEY_SIZE 50
 18#define VALUE_SIZE 100
 19
 20// ๋…ธ๋“œ ๊ตฌ์กฐ์ฒด (ํ‚ค-๊ฐ’ ์Œ์„ ์ €์žฅ)
 21typedef struct Node {
 22    char key[KEY_SIZE];
 23    char value[VALUE_SIZE];
 24    struct Node *next;  // ๋‹ค์Œ ๋…ธ๋“œ (์ฒด์ด๋‹)
 25} Node;
 26
 27// ํ•ด์‹œ ํ…Œ์ด๋ธ” ๊ตฌ์กฐ์ฒด
 28typedef struct {
 29    Node *buckets[TABLE_SIZE];  // ๋ฒ„ํ‚ท ๋ฐฐ์—ด
 30    int count;                   // ์ €์žฅ๋œ ํ•ญ๋ชฉ ๊ฐœ์ˆ˜
 31    int collisions;              // ์ถฉ๋Œ ํšŸ์ˆ˜
 32} HashTable;
 33
 34// ํ†ต๊ณ„ ์ •๋ณด
 35typedef struct {
 36    int total_inserts;
 37    int total_searches;
 38    int total_deletes;
 39    int chain_lengths[TABLE_SIZE];
 40} Statistics;
 41
 42// djb2 ํ•ด์‹œ ํ•จ์ˆ˜
 43unsigned int hash(const char *key) {
 44    unsigned int hash = 5381;
 45    int c;
 46    while ((c = *key++)) {
 47        hash = ((hash << 5) + hash) + c;
 48    }
 49    return hash % TABLE_SIZE;
 50}
 51
 52// ํ•ด์‹œ ํ…Œ์ด๋ธ” ์ƒ์„ฑ
 53HashTable* ht_create(void) {
 54    HashTable *ht = malloc(sizeof(HashTable));
 55    if (!ht) {
 56        fprintf(stderr, "๋ฉ”๋ชจ๋ฆฌ ํ• ๋‹น ์‹คํŒจ\n");
 57        return NULL;
 58    }
 59
 60    // ๋ชจ๋“  ๋ฒ„ํ‚ท ์ดˆ๊ธฐํ™”
 61    for (int i = 0; i < TABLE_SIZE; i++) {
 62        ht->buckets[i] = NULL;
 63    }
 64    ht->count = 0;
 65    ht->collisions = 0;
 66
 67    return ht;
 68}
 69
 70// ํ•ด์‹œ ํ…Œ์ด๋ธ” ํ•ด์ œ
 71void ht_destroy(HashTable *ht) {
 72    if (!ht) return;
 73
 74    // ๊ฐ ๋ฒ„ํ‚ท์˜ ์ฒด์ธ ํ•ด์ œ
 75    for (int i = 0; i < TABLE_SIZE; i++) {
 76        Node *current = ht->buckets[i];
 77        while (current) {
 78            Node *next = current->next;
 79            free(current);
 80            current = next;
 81        }
 82    }
 83    free(ht);
 84}
 85
 86// ์‚ฝ์ž… ๋˜๋Š” ์ˆ˜์ •
 87bool ht_set(HashTable *ht, const char *key, const char *value) {
 88    if (!ht || !key || !value) return false;
 89
 90    unsigned int index = hash(key);
 91
 92    // ๊ธฐ์กด ํ‚ค๊ฐ€ ์žˆ๋Š”์ง€ ํ™•์ธ
 93    Node *current = ht->buckets[index];
 94    while (current) {
 95        if (strcmp(current->key, key) == 0) {
 96            // ๊ธฐ์กด ํ‚ค ๋ฐœ๊ฒฌ โ†’ ๊ฐ’๋งŒ ์—…๋ฐ์ดํŠธ
 97            strncpy(current->value, value, VALUE_SIZE - 1);
 98            current->value[VALUE_SIZE - 1] = '\0';
 99            return true;
100        }
101        current = current->next;
102    }
103
104    // ์ƒˆ ๋…ธ๋“œ ์ƒ์„ฑ
105    Node *node = malloc(sizeof(Node));
106    if (!node) {
107        fprintf(stderr, "๋ฉ”๋ชจ๋ฆฌ ํ• ๋‹น ์‹คํŒจ\n");
108        return false;
109    }
110
111    strncpy(node->key, key, KEY_SIZE - 1);
112    node->key[KEY_SIZE - 1] = '\0';
113    strncpy(node->value, value, VALUE_SIZE - 1);
114    node->value[VALUE_SIZE - 1] = '\0';
115
116    // ๋ฒ„ํ‚ท ๋งจ ์•ž์— ์‚ฝ์ž… (O(1))
117    node->next = ht->buckets[index];
118
119    // ์ถฉ๋Œ ํ™•์ธ (๋ฒ„ํ‚ท์— ์ด๋ฏธ ๋…ธ๋“œ๊ฐ€ ์žˆ์œผ๋ฉด ์ถฉ๋Œ)
120    if (ht->buckets[index] != NULL) {
121        ht->collisions++;
122    }
123
124    ht->buckets[index] = node;
125    ht->count++;
126
127    return true;
128}
129
130// ๊ฒ€์ƒ‰
131char* ht_get(HashTable *ht, const char *key) {
132    if (!ht || !key) return NULL;
133
134    unsigned int index = hash(key);
135
136    // ์ฒด์ธ ํƒ์ƒ‰
137    Node *current = ht->buckets[index];
138    while (current) {
139        if (strcmp(current->key, key) == 0) {
140            return current->value;  // ์ฐพ์Œ!
141        }
142        current = current->next;
143    }
144
145    return NULL;  // ์ฐพ์ง€ ๋ชปํ•จ
146}
147
148// ์‚ญ์ œ
149bool ht_delete(HashTable *ht, const char *key) {
150    if (!ht || !key) return false;
151
152    unsigned int index = hash(key);
153
154    Node *current = ht->buckets[index];
155    Node *prev = NULL;
156
157    // ์ฒด์ธ์—์„œ ๋…ธ๋“œ ์ฐพ๊ธฐ
158    while (current) {
159        if (strcmp(current->key, key) == 0) {
160            // ๋…ธ๋“œ ์ œ๊ฑฐ
161            if (prev) {
162                prev->next = current->next;  // ์ค‘๊ฐ„ ๋˜๋Š” ๋
163            } else {
164                ht->buckets[index] = current->next;  // ๋งจ ์•ž
165            }
166            free(current);
167            ht->count--;
168            return true;
169        }
170        prev = current;
171        current = current->next;
172    }
173
174    return false;  // ์ฐพ์ง€ ๋ชปํ•จ
175}
176
177// ํ•ด์‹œ ํ…Œ์ด๋ธ” ์ถœ๋ ฅ
178void ht_print(HashTable *ht) {
179    if (!ht) return;
180
181    printf("\nโ•”โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•—\n");
182    printf("โ•‘         ํ•ด์‹œ ํ…Œ์ด๋ธ” ์ƒํƒœ (์ฒด์ด๋‹)         โ•‘\n");
183    printf("โ• โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•ฃ\n");
184    printf("โ•‘  ํ•ญ๋ชฉ ๊ฐœ์ˆ˜: %-5d                          โ•‘\n", ht->count);
185    printf("โ•‘  ์ถฉ๋Œ ํšŸ์ˆ˜: %-5d                          โ•‘\n", ht->collisions);
186    printf("โ•‘  ๋กœ๋“œ ํŒฉํ„ฐ: %.2f                           โ•‘\n",
187           (double)ht->count / TABLE_SIZE);
188    printf("โ•šโ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•\n\n");
189
190    for (int i = 0; i < TABLE_SIZE; i++) {
191        printf("[%d]: ", i);
192
193        Node *current = ht->buckets[i];
194        if (!current) {
195            printf("(๋น„์–ด์žˆ์Œ)\n");
196            continue;
197        }
198
199        // ์ฒด์ธ ์ถœ๋ ฅ
200        int chain_length = 0;
201        while (current) {
202            printf("[\"%s\":\"%s\"]", current->key, current->value);
203            if (current->next) printf(" โ†’ ");
204            current = current->next;
205            chain_length++;
206        }
207        printf(" (๊ธธ์ด: %d)\n", chain_length);
208    }
209}
210
211// ํ†ต๊ณ„ ์ˆ˜์ง‘
212void ht_get_statistics(HashTable *ht, Statistics *stats) {
213    if (!ht || !stats) return;
214
215    memset(stats, 0, sizeof(Statistics));
216
217    stats->total_inserts = ht->count;
218
219    // ๊ฐ ๋ฒ„ํ‚ท์˜ ์ฒด์ธ ๊ธธ์ด ๊ณ„์‚ฐ
220    for (int i = 0; i < TABLE_SIZE; i++) {
221        int length = 0;
222        Node *current = ht->buckets[i];
223        while (current) {
224            length++;
225            current = current->next;
226        }
227        stats->chain_lengths[i] = length;
228    }
229}
230
231// ํ†ต๊ณ„ ์ถœ๋ ฅ
232void print_statistics(HashTable *ht) {
233    Statistics stats;
234    ht_get_statistics(ht, &stats);
235
236    printf("\n=== ์„ฑ๋Šฅ ํ†ต๊ณ„ ===\n\n");
237
238    // ์ตœ๋Œ€ ์ฒด์ธ ๊ธธ์ด
239    int max_length = 0;
240    int empty_buckets = 0;
241    for (int i = 0; i < TABLE_SIZE; i++) {
242        if (stats.chain_lengths[i] > max_length) {
243            max_length = stats.chain_lengths[i];
244        }
245        if (stats.chain_lengths[i] == 0) {
246            empty_buckets++;
247        }
248    }
249
250    double avg_chain_length = (double)ht->count / (TABLE_SIZE - empty_buckets);
251
252    printf("์ €์žฅ๋œ ํ•ญ๋ชฉ:     %d\n", ht->count);
253    printf("์ถฉ๋Œ ํšŸ์ˆ˜:       %d\n", ht->collisions);
254    printf("๋น„์–ด์žˆ๋Š” ๋ฒ„ํ‚ท:   %d / %d\n", empty_buckets, TABLE_SIZE);
255    printf("์ตœ๋Œ€ ์ฒด์ธ ๊ธธ์ด:  %d\n", max_length);
256    printf("ํ‰๊ท  ์ฒด์ธ ๊ธธ์ด:  %.2f\n", avg_chain_length);
257    printf("๋กœ๋“œ ํŒฉํ„ฐ:       %.2f\n", (double)ht->count / TABLE_SIZE);
258
259    // ์ฒด์ธ ๊ธธ์ด ๋ถ„ํฌ
260    printf("\n์ฒด์ธ ๊ธธ์ด ๋ถ„ํฌ:\n");
261    for (int i = 0; i < TABLE_SIZE; i++) {
262        if (stats.chain_lengths[i] > 0) {
263            printf("  ๋ฒ„ํ‚ท %d: ", i);
264            for (int j = 0; j < stats.chain_lengths[i]; j++) {
265                printf("โ–ˆ");
266            }
267            printf(" (%d)\n", stats.chain_lengths[i]);
268        }
269    }
270}
271
272// ํ‚ค ์กด์žฌ ์—ฌ๋ถ€ ํ™•์ธ
273bool ht_contains(HashTable *ht, const char *key) {
274    return ht_get(ht, key) != NULL;
275}
276
277// ๋ชจ๋“  ํ‚ค ์ถœ๋ ฅ
278void ht_print_keys(HashTable *ht) {
279    if (!ht) return;
280
281    printf("\n=== ์ €์žฅ๋œ ํ‚ค ๋ชฉ๋ก ===\n");
282    int count = 0;
283    for (int i = 0; i < TABLE_SIZE; i++) {
284        Node *current = ht->buckets[i];
285        while (current) {
286            printf("  %d. %s\n", ++count, current->key);
287            current = current->next;
288        }
289    }
290    printf("์ด %d๊ฐœ\n", count);
291}
292
293// ํ…Œ์ŠคํŠธ ํ•จ์ˆ˜
294int main(void) {
295    printf("โ•”โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•—\n");
296    printf("โ•‘      ์ฒด์ด๋‹ ํ•ด์‹œ ํ…Œ์ด๋ธ” ๊ตฌํ˜„ ๋ฐ ํ…Œ์ŠคํŠธ    โ•‘\n");
297    printf("โ•šโ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•\n");
298
299    HashTable *ht = ht_create();
300    if (!ht) return 1;
301
302    // 1. ์‚ฝ์ž… ํ…Œ์ŠคํŠธ
303    printf("\n[ 1๋‹จ๊ณ„: ์‚ฝ์ž… ํ…Œ์ŠคํŠธ ]\n");
304    printf("์—ฌ๋Ÿฌ ๊ณผ์ผ ์ด๋ฆ„๊ณผ ํ•œ๊ธ€๋ช…์„ ์‚ฝ์ž…ํ•ฉ๋‹ˆ๋‹ค...\n");
305
306    ht_set(ht, "apple", "์‚ฌ๊ณผ");
307    ht_set(ht, "banana", "๋ฐ”๋‚˜๋‚˜");
308    ht_set(ht, "cherry", "์ฒด๋ฆฌ");
309    ht_set(ht, "date", "๋Œ€์ถ”์•ผ์ž");
310    ht_set(ht, "elderberry", "์—˜๋”๋ฒ ๋ฆฌ");
311    ht_set(ht, "fig", "๋ฌดํ™”๊ณผ");
312    ht_set(ht, "grape", "ํฌ๋„");
313    ht_set(ht, "honeydew", "ํ—ˆ๋‹ˆ๋“€ ๋ฉœ๋ก ");
314
315    ht_print(ht);
316
317    // 2. ๊ฒ€์ƒ‰ ํ…Œ์ŠคํŠธ
318    printf("\n[ 2๋‹จ๊ณ„: ๊ฒ€์ƒ‰ ํ…Œ์ŠคํŠธ ]\n");
319    const char *search_keys[] = {"apple", "grape", "kiwi", "banana"};
320    for (int i = 0; i < 4; i++) {
321        char *value = ht_get(ht, search_keys[i]);
322        if (value) {
323            printf("โœ“ '%s' โ†’ '%s'\n", search_keys[i], value);
324        } else {
325            printf("โœ— '%s' โ†’ (์ฐพ์„ ์ˆ˜ ์—†์Œ)\n", search_keys[i]);
326        }
327    }
328
329    // 3. ์ˆ˜์ • ํ…Œ์ŠคํŠธ
330    printf("\n[ 3๋‹จ๊ณ„: ์ˆ˜์ • ํ…Œ์ŠคํŠธ ]\n");
331    printf("'apple'์˜ ๊ฐ’์„ ์ˆ˜์ •ํ•ฉ๋‹ˆ๋‹ค...\n");
332    ht_set(ht, "apple", "๋ง›์žˆ๋Š” ์‚ฌ๊ณผ ๐ŸŽ");
333    printf("์ˆ˜์ • ํ›„: apple โ†’ %s\n", ht_get(ht, "apple"));
334
335    // 4. ์‚ญ์ œ ํ…Œ์ŠคํŠธ
336    printf("\n[ 4๋‹จ๊ณ„: ์‚ญ์ œ ํ…Œ์ŠคํŠธ ]\n");
337    printf("'banana'๋ฅผ ์‚ญ์ œํ•ฉ๋‹ˆ๋‹ค...\n");
338    if (ht_delete(ht, "banana")) {
339        printf("โœ“ ์‚ญ์ œ ์„ฑ๊ณต\n");
340    }
341    printf("์‚ญ์ œ ํ™•์ธ: banana โ†’ %s\n",
342           ht_get(ht, "banana") ?: "(์ฐพ์„ ์ˆ˜ ์—†์Œ)");
343
344    ht_print(ht);
345
346    // 5. ์ถฉ๋Œ ํ…Œ์ŠคํŠธ (๊ฐ™์€ ํ•ด์‹œ๊ฐ’์„ ๊ฐ€์ง€๋„๋ก)
347    printf("\n[ 5๋‹จ๊ณ„: ์ถฉ๋Œ ๋ฐœ์ƒ ํ…Œ์ŠคํŠธ ]\n");
348    printf("์ถ”๊ฐ€ ๋ฐ์ดํ„ฐ๋ฅผ ์‚ฝ์ž…ํ•˜์—ฌ ์ถฉ๋Œ์„ ์œ ๋ฐœํ•ฉ๋‹ˆ๋‹ค...\n");
349
350    ht_set(ht, "kiwi", "ํ‚ค์œ„");
351    ht_set(ht, "lemon", "๋ ˆ๋ชฌ");
352    ht_set(ht, "mango", "๋ง๊ณ ");
353
354    ht_print(ht);
355
356    // 6. ์„ฑ๋Šฅ ํ†ต๊ณ„
357    print_statistics(ht);
358
359    // 7. ํ‚ค ๋ชฉ๋ก
360    ht_print_keys(ht);
361
362    // ์ •๋ฆฌ
363    ht_destroy(ht);
364
365    printf("\nํ”„๋กœ๊ทธ๋žจ์„ ์ข…๋ฃŒํ•ฉ๋‹ˆ๋‹ค.\n");
366    return 0;
367}