テキストp.112のハッシュ法の実装を行う。
ChainHash.h
#ifndef __ChainHash
#define __ChainHash
#include "Member.h"
typedef struct __node {
Member data;
struct __node *next;
} Node;
typedef struct {
int size;
Node **table;
} ChainHash;
int Initialize(ChainHash *h, int size);
Node *Search(const ChainHash *h, const Member *x);
int Add(ChainHash *h, const Member *x);
int Remove(ChainHash *h, const Member *x);
void Dump(const ChainHash *h);
void Clear(ChainHash *h);
void Terminate(ChainHash *h);
#endif
ChainHash.c
#include <stdio.h>
#include <stdlib.h>
#include "Member.h"
#include "ChainHash.h"
static int hash(int key, int size)
{
return key % size;
}
static void SetNode(Node *n, const Member *x, const Node *next)
{
n->data = *x;
n->next = next;
}
int Initialize(ChainHash *h, int size)
{
int i;
if((h->table = calloc(size, sizeof(Node *))) == NULL) {
h->size = 0;
return 0;
}
h->size = size;
for (i = 0; i < size; i++)
h->table[i] = NULL;
return 1;
}
Node *Search(const ChainHash *h, const Member *x)
{
int key = hash(x->no, h->size);
Node *p = h->table[key];
while (p != NULL) {
if (p->data.no == x->no)
return p;
p = p->next;
}
return NULL;
}
int Add(ChainHash *h, const Member *x)
{
int key = hash(x->no, h->size);
Node *p = h->table[key];
Node *temp;
while (p != NULL) {
if (p->data.no == x->no)
return 1;
p = p->next;
}
if ((temp = calloc(1, sizeof(Node))) == NULL)
return 2;
SetNode(temp, x, h->table[key]);
h->table[key] = temp;
return 0;
}
int Remove(ChainHash *h, const Member *x)
{
int key = hash(x->no, h->size);
Node *p = h->table[key];
Node **pp = &h->table[key];
while (p != NULL) {
if (p->data.no == x->no) {
*pp = p->next;
free(p);
return 0;
}
pp = &p->next;
p = p->next;
}
return 1;
}
void Dump(const ChainHash *h)
{
int i;
for (i = 0; i < h->size; i++) {
Node *p = h->table[i];
printf("%02d ", i);
while (p != NULL) {
printf("→ %d (%s) ", p->data.no, p->data.name);
p = p->next;
}
putchar('\n');
}
}
void Clear(ChainHash *h)
{
int i;
for (i = 0; i < h->size; i++) {
Node *p = h->table[i];
while (p != NULL) {
Node *next = p->next;
free(p);
p = next;
}
h->table[i] = NULL;
}
}
void Terminate(ChainHash *h)
{
Clear(h);
free(h->table);
h->size = 0;
}
ChainHashTest.c
#include <stdio.h>
#include "Member.h"
#include "ChainHash.h"
typedef enum {
TERMINATE, ADD, DELETE, SEARCH, CLEAR, DUMP
} Menu;
Menu SelectMenu(void)
{
int ch;
do {
printf("(1)追加 (2)削除 (3)探索 (4)全削除 (5)ダンプ (0)終了: ");
scanf_s("%d", &ch);
} while (ch < TERMINATE || ch > DUMP);
return (Menu)ch;
}
int main(void)
{
Menu menu;
ChainHash hash;
Initialize(&hash, 13);
do {
int result;
Member x;
Node *temp;
switch (menu = SelectMenu()) {
case ADD:
x = ScanMember("追加", MEMBER_NO | MEMBER_NAME);
result = Add(&hash, &x);
if (result)
printf("エラー:追加に失敗しました(%s)。\n", (result == 1) ? "登録済み" : "メモリ不足");
break;
case DELETE:
x = ScanMember("削除", MEMBER_NO);
result = Remove(&hash, &x);
if (result == 1)
printf("エラー:その番号のデータは存在しません。\n");
break;
case SEARCH:
x = ScanMember("探索", MEMBER_NO);
temp = Search(&hash, &x);
if (temp == NULL)
printf("探索に失敗しました。\n");
else {
printf("探索に成功しました。\n");
PrintLnMember(&temp->data);
}
break;
case CLEAR:
Clear(&hash);
break;
case DUMP:
Dump(&hash);
break;
}
} while (menu != TERMINATE);
Terminate(&hash);
return 0;
}