学习笔记:数据结构(四)哈希表

双链表的查询只能从头往尾找,或者从尾往头找, 效率低下, 所以就有了哈希表。哈希表是将双链表通过一个hash函数分类,分成若干类,形成一个索引,然后查找的时候就可以快速的定位到某一类,减少查询的时间。下面是用哈希表的底层使用内核链表实现的。

.h文件

#pragma once
#include "list.h"

struct hash_table {
	struct list_head *tab;  /* 哈希表首元素的地址 */
	size_t nmemb;           /* 哈希表元素个数 */
	size_t (*hash)(const struct list_head *node); /* 哈希函数  */
	int (*hash_cmp)(const struct list_head *a, const struct list_head *b); /*哈希比较 */
	int (*push)(struct hash_table *phtable, struct list_head *node);
	struct list_head *(*search)(const struct hash_table *phtable, const struct list_head *key);
	int (*del)(struct hash_table *phtable, struct list_head *node);
};

int hash_table_init(struct hash_table *phtable, size_t nmemb,
		size_t (*hash)(const struct list_head *node),
		int (*hash_cmp)(const struct list_head *a, const struct list_head *b));

int hash_table_destroy(struct hash_table *phtable);

.c文件
#include <stdio.h>
#include "hash_table.h"
#include <assert.h>
#include <stdlib.h>



static int hash_del(struct hash_table *phtable, struct list_head *node)
{
	assert(phtable != NULL);
	assert(node != NULL);
	size_t v = phtable->hash(node) % phtable->nmemb;
	struct list_head *cur = phtable->tab + v;
	list_for_each(cur, phtable->tab + v) {
		if (phtable->hash_cmp(cur, node)) {
			node_del_init(cur);
			return 0;
		}
	}
	return -1;
}

static int hash_push(struct hash_table *phtable, struct list_head *node)
{
	assert(phtable != NULL);
	assert(node != NULL);
	size_t v = phtable->hash(node) % phtable->nmemb;
	list_add_tail(node, phtable->tab + v);
	return 0;
}

static struct list_head *hash_search(const struct hash_table *phtable, const struct list_head *key)
{
	assert(phtable != NULL);
	assert(key != NULL);

	size_t v = phtable->hash(key) % phtable->nmemb;
	static struct list_head *cur = NULL;

	if (cur == NULL || !phtable->hash_cmp(key, cur)) {
		cur = phtable->tab + v;
	}

	list_for_each_continue(cur, phtable->tab + v) {
		if (phtable->hash_cmp(cur, key)) {
			return cur;
		}
	}
	return NULL;
}



int hash_table_init(struct hash_table *phtable, size_t nmemb,
		size_t (*hash)(const struct list_head *node),
		int (*hash_cmp)(const struct list_head *a, const struct list_head *b))
{
	assert(phtable != NULL);
	assert(hash != NULL);
	assert(hash_cmp != NULL);

	phtable->tab = (struct list_head *)malloc(sizeof(struct list_head) * nmemb);

	assert(phtable->tab != NULL);
	int i = 0;
	for (; i < nmemb; i++) {
		list_head_init(phtable->tab + i);
	}

	phtable->nmemb = nmemb;
	phtable->hash = hash;
	phtable->hash_cmp = hash_cmp;
	phtable->search = hash_search;
	phtable->push = hash_push;
	phtable->del = hash_del;

	return 0;
}

int hash_table_destroy(struct hash_table *phtable)
{
	int i;
	struct list_head *cur = NULL;
	struct list_head *Next = NULL;
	for (i = 0; i < phtable->nmemb; i++) {
		list_for_each_safe(cur, Next, phtable->tab + i) {
			node_del_init(cur);
		}
	}
	free(phtable->tab);
	return 0;
}
测试
#include <stdio.h>
#include "hash_table.h"
#include <stdlib.h>
#include <assert.h>
#include <string.h>

struct data_info {
	char *name;
	char *tel;
	struct list_head list;
};


size_t hash(const struct list_head *node)
{
	struct data_info *pa = container_of(node, struct data_info, list);
	return pa->name[0];
}


int hash_cmp(const struct list_head *a, const struct list_head *b)
{
	struct data_info *pa = container_of(a, struct data_info, list);
	struct data_info *pb = container_of(b, struct data_info, list);
	return strcmp(pa->name, pb->name) == 0;
}


int main(void)
{
	struct data_info s[] = {
		{"tom", "137"},
		{"mary", "135"},
		{"candy", "155"},
		{"jack", "189"},
		{"richard", "131"},
	};
	
	struct hash_table *phtable = (struct hash_table *)malloc(sizeof(*phtable));
	assert(phtable != NULL);
	hash_table_init(phtable, 3, hash, hash_cmp);

	int i = 0;
	for(; i < sizeof(s) / sizeof(s[0]); i++) {
		phtable->push(phtable, &s[i].list);
	}

	
	struct data_info person = {"jack"};
	phtable->del(phtable, &(person.list));
	struct list_head *pa = phtable->search(phtable, &(person.list));
	if (pa == NULL) {
		printf("not fount\n");
	} else {
		struct data_info *p = container_of(pa, struct data_info, list);
		printf("%s %s\n", p->name, p->tel);
	}
	hash_table_destroy(phtable);
	free(phtable);
	return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值