散列表(hash table)

A hash table generalizes the simpler notion of an ordinary array. Directly addressing into an ordinary array makes effective use of our ability to examine an arbitrary position in an array in O(1) time.
散列表(hash table)是普通数组概念的推广。在其上进行增删查等操作,有着出色的期望性能。
冲突(collision)即多个关键字映射到数组的同一下标。
处理(减少)冲突的方法
1、精心的设计散列函数(hash function);

A good hash function satisfies (approximately) the assumption of simple uniform hashing: each key is equally likely to hash to any of the m slots, independently of where any other key has hashed to. 
一个好的散列函数应(近似地)满足简单一致散列的假设:每个关键字都等可能地散列到m个槽位的任何一个之中去,并与其他的已经在槽位的关键字无关(独立性)。
设计方法:1)除法;2)乘法;3)全域散列。
2、链接法(chainning):将散列到同一个槽中的所有元素都放到一个链表中;
     开放寻址法(open addressing):通过探查(probe),将所有元素都存放到散列表里。

     开放寻址三种常用的探测技术:线性探测(linear probing)、二次探测(quadratic probing)、双重探测(double hashing)。

(1)链接法(chainning)

#ifndef _MY_HASH_TABLE_H
#define _MY_HASH_TABLE_H

/* singly linked list */
typedef struct hash_node {
	struct hash_node *next;
} HASH_NODE;


typedef int (*CMP_FUNC)(void *node1, void *node2);
typedef void (*FREE_FUNC)(void *node);

typedef struct hash_table {
	HASH_NODE *array;
	unsigned long size;
	unsigned long count;
	unsigned long key_offset;
	CMP_FUNC hash_cmp;
	FREE_FUNC hash_free;
} HASH_TABLE;

void hash_create(HASH_TABLE *hash_table, unsigned long size, unsigned long key_offset, 
	CMP_FUNC hash_cmp, FREE_FUNC hash_free);

void hash_insert(HASH_TABLE *hash_table, HASH_NODE *node);

void hash_delete(HASH_TABLE *hash_table, HASH_NODE *node);

void hash_destroy(HASH_TABLE *hash_table);

HASH_NODE *hash_find_node_by_key(HASH_TABLE *hash_table, unsigned long key);

#endif
#include <stdlib.h>
#include <stdio.h>

#include "hash.h"

#define HASH_GET_NODE_KEY(hash_table, node)                                   \
    (*(((unsigned long *)(((unsigned char *)(node)) + (hash_table)->key_offset))))

/* hash function */
#define HASH_GET_BUCKET_INDEX(hash_table, key)                                   \
    (key  % (hash_table)->size)

/*
参数:HASH_TABLE *hash_table, unsigned long size, unsigned long key_offset,
     CMP_FUNC hash_cmp, FREE_FUNC hash_free
返回值:void
作用:创建一个哈希表
*/
void hash_create(HASH_TABLE *hash_table, unsigned long size, unsigned long key_offset,
	CMP_FUNC hash_cmp, FREE_FUNC hash_free)
{
	int index = 0;

	if (hash_table == NULL) {
		return;
	}

	hash_table->array = (HASH_NODE *)malloc(sizeof(HASH_NODE) * size);
	if (hash_table->array == NULL) {
		printf("malloc failed!\n");
		return;
	}

	hash_table->size = size;
	hash_table->count = 0;
	hash_table->key_offset = key_offset;
	hash_table->hash_cmp = hash_cmp;
	hash_table->hash_free = hash_free;

	for (; index < size; index++) {
		hash_table->array[index].next = NULL;
	}
}

/*
参数:HASH_TABLE *hash_table, HASH_NODE *node
返回值:void
作用:将节点node插入到哈希表
*/
void hash_insert(HASH_TABLE *hash_table, HASH_NODE *node)
{
	unsigned long key = 0;
	unsigned long index = 0;

	if (hash_table == NULL || node == NULL) {
		return;
	}

	key = HASH_GET_NODE_KEY(hash_table, node);
	index = HASH_GET_BUCKET_INDEX(hash_table, key);

	/* 首部插入 */
	node->next = hash_table->array[index].next;
	hash_table->array[index].next = node;
	hash_table->count++;
}

/*
参数:HASH_TABLE *hash_table, HASH_NODE *node
返回值:void
作用:从哈希表中删除节点node
*/
void hash_delete(HASH_TABLE *hash_table, HASH_NODE *node)
{
	unsigned long key = 0;
	unsigned long index = 0;
	HASH_NODE *prev = NULL;
	HASH_NODE *iter = NULL;

	if (hash_table == NULL || node == NULL) {
		return;
	}

	key = HASH_GET_NODE_KEY(hash_table, node);
	index = HASH_GET_BUCKET_INDEX(hash_table, key);

	prev = &(hash_table->array[index]);
	iter = hash_table->array[index].next;
	while (iter != NULL) {
		// if (hash_cmp(iter, node) == 0) {
		if (iter == node) {
			prev->next = node->next;
			node->next = NULL;
			hash_table->count--;
			break;
		}

		prev = iter;
		iter = iter->next;
	}
}

/*
参数:HASH_TABLE *hash_table
返回值:void
作用:释放哈希表
*/
void hash_destroy(HASH_TABLE *hash_table)
{
	unsigned long index = 0;
	HASH_NODE *tmp = NULL;
	HASH_NODE *iter = NULL;

	if (hash_table == NULL) {
		return;
	}

	for (index = 0; index < hash_table->size; index++) {
		iter = hash_table->array[index].next;
		while (iter != NULL) {
			tmp = iter;
			iter = iter->next;
			hash_table->hash_free(tmp);
			hash_table->count--;
		}
	}

	free(hash_table->array);
	hash_table->array = NULL;
}

/*
参数:HASH_TABLE *hash_table, unsigned long key
返回值:HASH_NODE *
作用:通过key来查找节点
*/
HASH_NODE *hash_find_node_by_key(HASH_TABLE *hash_table, unsigned long key)
{
	unsigned long index = 0;
	HASH_NODE *node = NULL;

	if (hash_table == NULL) {
		return NULL;
	}

	index = HASH_GET_BUCKET_INDEX(hash_table, key);
	node = hash_table->array[index].next;
	while (node != NULL) {
		if (key == HASH_GET_NODE_KEY(hash_table, node)) {
			return node;
		}

		node = node->next;
	}

	return NULL;
}
#ifndef _MY_HASH3_TABLE_H
#define _MY_HASH3_TABLE_H

/* doubly linked list */
typedef struct hash_node {
	struct hash_node *next;
	struct hash_node *prev;
} HASH_NODE;

typedef struct hash_table {
	HASH_NODE **array;
	unsigned long size;
	unsigned long count;
	unsigned long key_offset;
} HASH_TABLE;

void hash_create(HASH_TABLE *hash_table, unsigned long size, unsigned long key_offset);

void hash_insert(HASH_TABLE *hash_table, HASH_NODE *node);

void hash_delete(HASH_TABLE *hash_table, HASH_NODE *node);

void hash_destroy(HASH_TABLE *hash_table);

HASH_NODE *hash_find_node_by_key(HASH_TABLE *hash_table, unsigned long key);

#endif
#include <stdlib.h>
#include <stdio.h>

#include "hash3.h"

#define HASH_GET_NODE_KEY(hash_table, node)                                   \
    (*(((unsigned long *)(((unsigned char *)(node)) + (hash_table)->key_offset))))

#define HASH_GET_BUCKET_INDEX(hash_table, key)                                   \
    (key  % hash_table->size)

/*
参数:HASH_TABLE *hash_table, unsigned long size, unsigned long key_offset
返回值:void
作用:创建一个哈希表
*/
void hash_create(HASH_TABLE *hash_table, unsigned long size, unsigned long key_offset)
{
	unsigned long index = 0;

	if (hash_table == NULL) {
		return;
	}

	hash_table->array = (HASH_NODE **)malloc(sizeof(HASH_NODE *) * size);
	if (hash_table->array == NULL) {
		printf("malloc error!\n");
		return;
	}

	hash_table->size = size;
	hash_table->count = 0;
	hash_table->key_offset = key_offset;

	for (; index < size; index++) {
		hash_table->array[index] = NULL;
	}
}

/*
参数:HASH_TABLE *hash_table, HASH_NODE *node
返回值:void
作用:将节点node插入到哈希表
*/
void hash_insert(HASH_TABLE *hash_table, HASH_NODE *node)
{
	unsigned long key = 0;
	unsigned long index = 0;

	if (hash_table == NULL || node == NULL) {
		return;
	}

	key = HASH_GET_NODE_KEY(hash_table, node);
	index = HASH_GET_BUCKET_INDEX(hash_table, key);

	/* 首部插入 */
	node->prev = NULL;
	node->next = hash_table->array[index];
	hash_table->array[index] = node;
	if (node->next != NULL) { // not empty
		node->next->prev = node;
	}

	hash_table->count++;
}

/*
参数:HASH_TABLE *hash_table, HASH_NODE *node
返回值:void
作用:从哈希表中删除节点node
*/
void hash_delete(HASH_TABLE *hash_table, HASH_NODE *node)
{
	unsigned long key = 0;
	unsigned long index = 0;

	if (hash_table == NULL || node == NULL) {
		return;
	}

	if (node->prev != NULL) { // not first one
		node->prev->next = node->next;
	} else { 
		key = HASH_GET_NODE_KEY(hash_table, node);
		index = HASH_GET_BUCKET_INDEX(hash_table, key);
		hash_table->array[index] = node->next;
	}

	if (node->next != NULL) { // not last one
		node->next->prev = node->prev;
	}

	node->prev = NULL;
	node->next = NULL;
	hash_table->count--;
}

/*
参数:HASH_TABLE *hash_table
返回值:void
作用:释放哈希表(不完善)
*/
void hash_destroy(HASH_TABLE *hash_table)
{
	if (hash_table == NULL) {
		return;
	}

	free(hash_table->array);
	hash_table->array = NULL;
}

/*
参数:HASH_TABLE *hash_table, unsigned long key
返回值:HASH_NODE *
作用:通过key来查找节点
*/
HASH_NODE *hash_find_node_by_key(HASH_TABLE *hash_table, unsigned long key)
{
	unsigned long index = 0;
	HASH_NODE *node = NULL;

	if (hash_table == NULL) {
		return NULL;
	}

	index = HASH_GET_BUCKET_INDEX(hash_table, key);
	node = hash_table->array[index];
	while (node != NULL) {
		if (key == HASH_GET_NODE_KEY(hash_table, node)) {
			return node;
		}

		node = node->next;
	}

	return NULL;
}

#endif
#include <stdlib.h>
#include <stdio.h>
#include <string.h>

#include "hash3.h"

#ifndef offsetof(TYPE, MEMBER)
#define offsetof(TYPE, MEMBER) ((size_t) &((TYPE *)0)->MEMBER)
#endif

#define GET_POS(node, node_offset) ((size_t)node - node_offset)

typedef struct life {
	HASH_NODE node;
	int work;
	int study;
	int play;
} LIFE;

int hash_cmp(void *node1, void *node2)
{
	LIFE *pleft1 = (LIFE *)node1;
	LIFE *pleft2 = (LIFE *)node2;

	return pleft1->work - pleft2->work;
}

void hash_free(void *node)
{
	LIFE *pleft = (LIFE *)node;

	printf(" %d", pleft->work);
	free(pleft);
	pleft = NULL;
}

#if 0
void hash_print(HASH_TABLE *hash_table)
{
	unsigned long index = 0;
	HASH_NODE *iter = NULL;
	LIFE *life = NULL;

	for (; index < hash_table->size; index++) {
		iter = hash_table->array[index].next;
		printf("%2d:", index);
		while (iter != NULL) {
			life = (LIFE *)iter;
			printf(" --->work: %2d, strudy: %2d, play: %2d",
				life->work, life->study, life->play);
			iter = iter->next;
		}
		printf("\n");
	}

	printf("\n");
}

void hash2_print(HASH_TABLE *hash_table)
{
	unsigned long index = 0;
	HASH_NODE *iter = NULL;
	LIFE *life = NULL;

	for (; index < hash_table->size; index++) {
		iter = hash_table->array[index].next;
		printf("%2d:", index);
		while (iter != hash_table->array + index) {
			life = (LIFE *)iter;
			printf(" --->work: %2d, strudy: %2d, play: %2d",
				life->work, life->study, life->play);
			iter = iter->next;
		}
		printf("\n");
	}

	printf("\n");
}
#endif

void hash3_print(HASH_TABLE *hash_table)
{
	unsigned long index = 0;
	HASH_NODE *iter = NULL;
	LIFE *life = NULL;

	for (; index < hash_table->size; index++) {
		iter = hash_table->array[index];
		printf("%2d:", index);
		while (iter != NULL) {
			life = (LIFE *)iter;
			printf(" --->work: %2d, strudy: %2d, play: %2d",
				life->work, life->study, life->play);
			iter = iter->next;
		}
		printf("\n");
	}

	printf("\n");
}

int main()
{
	int i = 0;
	int arr[] = { 13, 14, 3, 34, 35, 27, 8, 9, 25, 4, 2, 1 };
	int len = sizeof(arr) / sizeof(arr[0]);
	HASH_TABLE real_life;
	LIFE *my_life = NULL;

	hash_create(&real_life, len, offsetof(LIFE, work));
	for (i = 0; i < len; i++) {
		my_life = (struct life *)malloc(sizeof(struct life));
		if (my_life == NULL) {
			printf("malloc error!\n");
			return -1;
		}

		my_life->node.next = NULL;
		my_life->work = arr[i];
		my_life->study = arr[i] + 1;
		my_life->play = arr[i] + 2;	
		hash_insert(&real_life, &(my_life->node));
	}

	hash3_print(&real_life);

	for (i = 0; i < len; i++) {
		my_life = hash_find_node_by_key(&real_life, arr[i]);
		hash_delete(&real_life, &(my_life->node));
		free(my_life);
		my_life = NULL;
		hash3_print(&real_life);
	}

	hash_destroy(&real_life);

	getchar();

	return 0;
}

(2)开放寻址(open addressing)
用大小为M的数组保存N个键值对,其中M>N,通过数组中的空位来解决碰撞冲突问题。
开放寻址散列表中最简单的方法叫做线性探测法(linear probing):当碰撞发生时,直接检测散列表中的下一个位置。

 

#ifndef _MY_LINEAR_PROBING_HASH_H
#define _MY_LINEAR_PROBING_HASH_H

/* linear probing list */
typedef struct hash_node {
	int key;
	int value;
} HASH_NODE;

typedef struct hash_table {
	HASH_NODE *array;
	unsigned long size;
	unsigned long count;
} HASH_TABLE;

/*
参数:HASH_TABLE *hash_table, int key
返回值:int
作用:哈希函数
*/
int hash(HASH_TABLE *hash_table, int key);

/*
参数:HASH_TABLE *hash_table
返回值:void
作用:创建一个哈希表
*/
void hash_create(HASH_TABLE *hash_table);

/*
参数:HASH_TABLE *hash_table, int key, int value
返回值:void
作用:修改哈希表大小
*/
void hash_resize(HASH_TABLE *hash_table, unsigned long size);

/*
参数:HASH_TABLE *hash_table, int key
返回值:int
作用:通过key获取value
*/
int hash_get(HASH_TABLE *hash_table, int key);

/*
参数:HASH_TABLE *hash_table, int key, int value
返回值:void
作用:设置key与value
*/
void hash_put(HASH_TABLE *hash_table, int key, int value);

/*
参数:HASH_TABLE *hash_table, int key
返回值:void
作用:移除key与value
*/
void hash_remove(HASH_TABLE *hash_table, int key);

/*
参数:HASH_TABLE *hash_table
返回值:void
作用:打印哈希表
*/
void hash_print(HASH_TABLE *hash_table);

#endif

#include <stdlib.h>
#include <stdio.h>

#include "lphash.h" 

#define HASH_DEFAULT_SIZE  13
#define HASH_INVALID_VALUE -1

/*
参数:HASH_TABLE *hash_table, int key
返回值:int
作用:哈希函数
*/
int hash(HASH_TABLE *hash_table, int key)
{
	return key % hash_table->size;
}

/*
参数:HASH_TABLE *hash_table
返回值:void
作用:创建一个哈希表
*/
void hash_create(HASH_TABLE *hash_table)
{
	int i = 0;

	if (hash_table == NULL) {
		return; 
	}

	hash_table->size = HASH_DEFAULT_SIZE;
	hash_table->array = (HASH_NODE *)malloc(sizeof(HASH_NODE) * hash_table->size);
	if (hash_table->array == NULL) {
		printf("malloc error!\n");
		return;
	}

	hash_table->count = 0;
	for (; i < hash_table->size; i++) {
		hash_table->array[i].key = HASH_INVALID_VALUE;
	}
}

/*
参数:HASH_TABLE *hash_table, int key, int value
返回值:void
作用:修改哈希表大小
*/
void hash_resize(HASH_TABLE *hash_table, unsigned long size)
{
	HASH_TABLE ht;
	int i = 0;
	int j = 0;

	if (hash_table == NULL) {
		return;
	}

	ht.array = (HASH_NODE *)malloc(sizeof(HASH_NODE) * size);
	if (ht.array == NULL) {
		printf("malloc error!\n");
		return;
	}

	ht.count = 0;
	ht.size = size;
	for (i = 0; i < ht.size; i++) {
		ht.array[i].key = HASH_INVALID_VALUE;
	}

	/* 重新计算哈希值,刷新哈希表 */
	for (i = 0; i < hash_table->size; i++) {
		for (j = hash(&ht, hash_table->array[i].key);
			ht.array[j].key != HASH_INVALID_VALUE;
			j = (j + 1) % hash_table->size) {
			if (ht.array[j].key == hash_table->array[i].key) {
				ht.array[j].value = hash_table->array[i].value;
				break;
			}
		}

		if (ht.array[j].key == HASH_INVALID_VALUE) {
			ht.array[j].key = hash_table->array[i].key;
			ht.array[j].value = hash_table->array[i].value;
		}
	}

	hash_table->size = size;
	free(hash_table->array);
	hash_table->array = ht.array;
}

/*
参数:HASH_TABLE *hash_table, int key
返回值:int
作用:通过key获取value
*/
int hash_get(HASH_TABLE *hash_table, int key)
{
	int i = 0;

	if (hash_table == NULL) {
		return HASH_INVALID_VALUE;
	}

	for (i = hash(hash_table, key);
		hash_table->array[i].key != HASH_INVALID_VALUE;
		i = (i + 1) % hash_table->size) {
		if (key == hash_table->array[i].key) {
			return hash_table->array[i].value;
		}
	}

	return HASH_INVALID_VALUE;
}

/*
参数:HASH_TABLE *hash_table, int key, int value
返回值:void
作用:设置key与value
*/
void hash_put(HASH_TABLE *hash_table, int key, int value)
{
	int i = 0;

	if (hash_table == NULL) {
		return;
	}
	
	if (hash_table->count >= hash_table->size / 2) {
		hash_resize(hash_table, hash_table->size * 2);
	}

	for (i = hash(hash_table, key); 
		hash_table->array[i].key != HASH_INVALID_VALUE;
		i = (i + 1) % hash_table->size) {
		if (key == hash_table->array[i].key) {
			hash_table->array[i].value = value;
			return;
		}
	}

	hash_table->array[i].key = key;
	hash_table->array[i].value = value;
	hash_table->count++;
}

/*
参数:HASH_TABLE *hash_table, int key
返回值:void
作用:移除key与value
*/
void hash_remove(HASH_TABLE *hash_table, int key)
{
	int i = 0;
	int tmp_key = 0;
	int tmp_val = 0;

	if (hash_table == NULL) {
		return;
	}

	i = hash(hash_table, key);
	while ((hash_table->array[i].key != HASH_INVALID_VALUE)
		&& (hash_table->array[i].key != key)) {
		i = (i + 1) % hash_table->size;
	}

	/* key不存在 */
	if (hash_table->array[i].key == HASH_INVALID_VALUE) {
		return;
	}

	/* 设置key无效,同时需要更新键簇 */
	hash_table->array[i].key = HASH_INVALID_VALUE;
	i = (i + 1) % hash_table->size;
	while (hash_table->array[i].key != HASH_INVALID_VALUE) {
		tmp_key = hash_table->array[i].key;
		tmp_val = hash_table->array[i].value;
		hash_table->array[i].key = HASH_INVALID_VALUE;
		hash_table->count--;
		hash_put(hash_table, tmp_key, tmp_val);
		i = (i + 1) % hash_table->size;
	}

	hash_table->count--;
	if ((hash_table->count > HASH_DEFAULT_SIZE)
		&& (hash_table->count <= hash_table->size / 8)) {
		hash_resize(hash_table, hash_table->size / 2);
	}
}

/*
参数:HASH_TABLE *hash_table
返回值:void
作用:释放哈希表
*/
void hash_destroy(HASH_TABLE *hash_table)
{
	if (hash_table == NULL) {
		return;
	}

	free(hash_table->array);
	hash_table->array = NULL;
	hash_table->size = 0;
	hash_table->count = 0;
}

/*
参数:HASH_TABLE *hash_table
返回值:void
作用:打印哈希表
*/
void hash_print(HASH_TABLE *hash_table)
{
	int i = 0;

	for (; i < hash_table->size; i++) {
		if (hash_table->array[i].key != HASH_INVALID_VALUE) {
			printf("%2d: key[%d] value[%d]\n", i,
				hash_table->array[i].key, hash_table->array[i].value);
		} else {
			printf("%2d:\n", i);
		}
	}

	printf("\n");
}
#include <stdlib.h>
#include <stdio.h>
#include <string.h>

#include "lphash.h"

int main()
{
	int i = 0;
	int key = 0;
	int value = 0;
	int arr[] = { 13, 14, 3, 34, 35, 27, 8, 9, 25, 4, 2, 1 };
	int len = sizeof(arr) / sizeof(arr[0]);
	HASH_TABLE ht;

	hash_create(&ht);

	printf("\n*insert*****************************\n");
	for (i = 0; i < len; i++) {
		key = arr[i];
		value = arr[i] + 1;
		hash_put(&ht, key, value);
		hash_print(&ht);
	}

	printf("\n*delete*****************************\n");
	for (i = 0; i < len; i++) {
		key = arr[i];
		hash_remove(&ht, key);
		hash_print(&ht);
	}

	printf("\n*insert*****************************\n");
	for (i = 0; i < len; i++) {
		key = arr[i];
		value = arr[i] + 1;
		hash_put(&ht, key, value);
		hash_print(&ht);
	}

	hash_destroy(&ht);
	getchar();

	return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值