哈希(hash)表--链地址法解决冲突

首先要感谢下面博主: mark 一下
https://www.cnblogs.com/s-b-b/p/6208565.html
说的很清楚,代码也能直接用,只是做了一点点小改进:1,将冲突的hash值存放到了链尾.2.增加了remove函数,方便删除不要的节点.此方法中,一个key至只对应一个value.

lookup函数:
//定义一个查找根据key查找结点的方法,首先是用Hash函数计算头地址,然后根据头地址向下一个个去查找结点,如果结点的key和查找的key值相同,则匹配成功,lookup即为查找key
install 函数:
//定义一个插入结点的方法,首先是查看该key值的结点是否存在,如果存在则更改value值就好,如果不存在,则插入新结点。

HashList3.h的代码如下

#include "stdio.h"
#include "stdlib.h"
#include "string.h"
#define HASHSIZE 10
typedef unsigned int uint;
//节点定义,key,value,与next指针
typedef struct Node{
	const char* key;
	const char* value;
	Node *next;
}Node;

//one key to one value
class HashTable{
private:
	Node* node[HASHSIZE];//定义节点数
public:
	HashTable();//构造函数
	uint hash(const char* key);//hash函数
	uint BKDRHash(const char* key);//BKDRHash函数
	Node* lookup(const char* key,uint &pos);//find 函数
	bool install(const char* key,const char* value);//insert节点
	bool remove(const char* key);//删除节点
	const char* get(const char* key);
	void display();
};

HashTable::HashTable(){
	// for (int i = 0; i < HASHSIZE; ++i)
	// {
	// 	node[i] = NULL;
	// }
}

//BKDR hash 算法 
uint HashTable::BKDRHash(const char* key)
{
    uint seed = 131;
    /* 31 131 1313 13131 131313 etc.. */
    uint hash = 0;
    for (; *key; ++key)
    {
        hash = (hash * seed) + (*key);
    }
    return hash%HASHSIZE;
}


uint HashTable::hash(const char* key){

	uint hash=0;
	for (; *key; ++key)
	{
		hash=hash*33+*key;
	}
	return hash%HASHSIZE;
}

Node* HashTable::lookup(const char* key,uint &pos){
	Node *np;
	uint index;
	index = BKDRHash(key);
	uint ipos = 0;
	for(np=node[index];np;np=np->next,ipos++)
	{
		if(!strcmp(key,np->key))//equel return 0 
		{
			pos = ipos;
			return np;
		}
	}
	return NULL;
}

bool HashTable::install(const char* key,const char* value){
	uint index,pos;
	Node *np,*tail;
	if(!(np=lookup(key,pos)))
	{
		index = BKDRHash(key);
		np = (Node*)malloc(sizeof(Node));
		if(!np) return false;
		np->key=key;

		if (!(node[index]))
		{
			node[index] = np;
		}
		else
		{
			tail=node[index];
			while(tail->next)
			{
				tail=tail->next;
			}

			tail->next = np;
		}
		// np->next = node[index];
		// node[index] = np;
	}

	np->value=value;
	return true;
}
bool HashTable::remove(const char* key)
{
	Node *np,*pre;
	uint pos;
	uint index = BKDRHash(key);
	if((np=lookup(key,pos)))
	{	
		if (pos == 0)
		{
			node[index] = np->next;			
		} 
		else
		{
			pre = node[index];
			for (int i = 1; i < pos; ++i)
			{
				pre = pre->next;
			}
			pre->next = pre->next->next;
		}

		free(np);
		return true;
	}
	return false;
}

void HashTable::display(){
	Node* temp;
	for (int i = 0; i < HASHSIZE; ++i)
	{
		if(!node[i])
		{
			printf("[]\n");
		}
		else
		{
			printf("[");
			for (temp=node[i]; temp; temp=temp->next)
			{
				printf("[%s : %s] -> ",temp->key,temp->value );
			}
			printf("]\n");
		}
	}
}

测试代码(HashList3.cpp)如下

#include "HashList3.h"

int main(int argc, char const *argv[])
{
	HashTable *ht = new HashTable();
	const char* key[]={"a","b","k","u","9"};
	const char* value[]={"value1","value2","value3","nihao","shide"};
	for (int i = 0; i < 5; ++i)
	{
		ht->install(key[i],value[i]);
	}
	printf("-------------------------\n");
	ht->display();
	printf("-------------------------\n\n");
	ht->remove("u");
	ht->display();
	printf("-------------------------\n\n");
	ht->remove("a");
	ht->display();
	return 0;
}

运行结果:
在这里插入图片描述
原文是将后加入的节点放在链表的最前端,这里将后加入的节点放置链表最末端.hash算法有更该.当然少量数据看不到区别,大量数据才有对比性.

猜你喜欢

转载自blog.csdn.net/mhsszm/article/details/87347453