哈希表

/*
 * Copyright 2014 YU Heng-yang. All rights reserved.
 *
 * hashtable.c - Simple hash table implementation.
 *
 * Modify List to any other types as you need as long as
 *  the list structure is retained. Remember also to provide
 *  the hash function and key compare function if necessary.
 *
 * 2014-7-7 YU Heng-yang.
 */
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <assert.h>

#define ALLOC(size) malloc(size)
#define FREE(p)     free(p)

typedef struct List List;
struct List {
	const char *key;	/* can be other types */
	void *data;		/* generic, can be a specific type if necessary */
	List *next;
};

typedef struct HTable *HTable;
struct HTable {
	unsigned size;
	int (*hash) (const char *key);
	int (*cmp) (const void *x, const void *y);
	List **buckets;
};

HTable htable_new(unsigned hint, int (*hash) (const char *key),
		  int (*cmp) (const void *x, const void *y));

/* create new item if data is not found and create is nonzero */
void *htable_lookup(HTable table, const char *key, void *data, int create);
void *htable_remove(HTable table, const char *key);
HTable htable_destroy(HTable table);
void htable_traversal(HTable table, void (*apply) (void *data, void *arg),
		      void *arg);

void print(void *data, void *arg)
{
	assert(arg);
	printf((char *)arg, (char *)data);
}

int main(int argc, char *argv[])
{
#define N 5
	int i;
	char str[32], format[5];
	char *keys[N] = {
		"abc",
		"sjdfkl",
		"12ASJ34lj",
		"89",
		"weuriozuioeaZLBN"
	};

	/* use default hash and key compare functions, 30 elements */
	HTable table = htable_new(30, NULL, NULL);
	sprintf(format, "%%%ds", sizeof(str) - 1);
	for (i = 0; i < N; i++) {
		char *data;
		fscanf(stdin, format, str);
		str[sizeof(str) - 1] = '\0';
		data = strcpy(ALLOC(strlen(str) + 1), str);	/* bad! */
		htable_lookup(table, keys[i], data, 1);
		printf("After insert %s: ", data);
		htable_traversal(table, print, "%s ");
		putchar('\n');
	}

	for (i = 0; i < N; i++) {
		void *data = htable_remove(table, keys[i]);
		assert(data);
		FREE(data);
	}

	table = htable_destroy(table);
	return 0;
}

static int default_hash(const char *key);
static int default_cmp(const void *x, const void *y);
static unsigned next_prime(unsigned hint);
HTable htable_new(unsigned hint,
		  int (*hash) (const char *key),
		  int (*cmp) (const void *x, const void *y))
{
	HTable table;
	unsigned size = next_prime(hint);

	assert(size);

	table = ALLOC(sizeof(*table));
	assert(table);

	table->buckets = ALLOC(size * sizeof(**table->buckets));
	assert(table->buckets);

	table->size = size;
	table->hash = hash ? hash : default_hash;
	table->cmp = cmp ? cmp : default_cmp;

	memset(table->buckets, 0, size * sizeof(**table->buckets));
	return table;
}

/* create new item if data is not found and create is nonzero */
void *htable_lookup(HTable table, const char *key, void *data, int create)
{
	assert(table);
	assert(key);

	unsigned index = table->hash(key) % table->size;
	List *p;
	for (p = table->buckets[index]; p; p = p->next)
		if (0 == table->cmp(key, p->key))
			break;	/* found */

	/* not found, create if needed */
	if (!p && create) {
		p = ALLOC(sizeof(*p));
		assert(p);
		p->key = key;	/* assume key won't be modified */
		p->data = data;
		p->next = table->buckets[index];
		table->buckets[index] = p;
	}

	return p ? p->data : NULL;
}

void *htable_remove(HTable table, const char *key)
{
	assert(table && key);

	unsigned index = table->hash(key) % table->size;
	List **pp;
	void *data = NULL;

	for (pp = &table->buckets[index]; *pp; pp = &(*pp)->next)
		if (0 == table->cmp((*pp)->key, key)) {
			List *p = *pp;
			*pp = p->next;
			data = p->data;
			FREE(p);
			break;
		}

	return data;
}

HTable htable_destroy(HTable table)
{
	assert(table);

	/* assume data is freed some where else */
	FREE(table->buckets);
	memset(table, 0, sizeof(*table));
	FREE(table);

	return NULL;
}

void htable_traversal(HTable table, void (*apply) (void *data, void *arg),
		      void *arg)
{
	assert(table);
	assert(apply);

	int i;
	List *p;

	for (i = 0; i < table->size; i++)
		for (p = table->buckets[i]; p; p = p->next)
			apply(p->data, arg);
}

/* see The Practice of Programming, p.57 */
static int default_hash(const char *key)
{
	const int MULTIPLIER = 31;
	unsigned h;
	const unsigned char *p;

	for (h = 0, p = (const unsigned char *)key; *p; p++)
		h = MULTIPLIER * h + *p;
	return h;
}

static int default_cmp(const void *x, const void *y)
{
	return strcmp((const char *)x, (const char *)y);
}

static unsigned next_prime(unsigned size)
{
	/*
	 * Just randomly chosen prime numbers between 1 and 10000, not
	 * empirical data. Add more primes as you need if table
	 * is expected to be very large.
	 */
	static unsigned primes[] = {
		31, 53, 67, 79, 97, 113, 127, 139, 151, 163,
		181, 211, 257, 307, 409, 577, 683, 827, 1013, 1571,
		2833, 3347, 3571, 4989, 5833, 6469, 7518, 9999
	};

	int i;
	for (i = 0; i < sizeof(primes) / sizeof(primes[0]); i++)
		if (primes[i] > size)
			return primes[i];

	assert(0 == "table size is too large!");
	return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值