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}