⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 hashtable.c

📁 数据结构的C语言实现
💻 C
字号:
/*****************************************************************/
/*
* Copyright (c) 2008,北京归创科技有限公司技术部
* All rights reserved.
* 
* 文件名称:hashtable.c
* 用    途:哈希表的实现
* 创建日期:2008年5月29日
*/

/*****************************************************************/


#include "hashtable.h"
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <math.h>
#include <assert.h>


const unsigned int default_minsize = 100;
const float default_factor = 0.7;
const BOOL default_checkkeymutex = TRUE;


//DJB string hash
static unsigned long default_hashfromstringkey(const void *key)
{
    char *str = (char *)key;
    unsigned long hash = 5381;
    int c;
    while (c = *str++) hash = ((hash << 5) + hash) + c; /* hash * 33 + c */
    return hash;
}

static int default_equalstringkeys(const void *key1,const void *key2)
{
    return strcmp((char *)key1,(char *)key2);
}
//Thomas Wang int hash
static unsigned long default_hashfromintkey(const void *key)
{
    int k = (int)key;
	k = ~k + (k << 15); // key = (key << 15) - key - 1;
    k = k ^ (k >> 12);
    k = k + (k << 2);
    k = k ^ (k >> 4);
    k = k * 2057; // key = (key + (key << 3)) + (key << 11);
    k = k ^ (k >> 16);
    return (unsigned long)k;
}
static int default_equalintkeys(const void *key1,const void *key2)
{
	return (int)key1 == (int)key2 ? 0 : 1;
}

static unsigned int gettableindex(unsigned long hashvalue,int tablelengthindex)
{
	return hashvalue - ( hashvalue >> tablelengthindex << tablelengthindex );//取模运算
	//return (unsigned int)(hashvalue % (unsigned long)tablelength);
}

static DS_RESULT hashtable_expand(hashtable *dh)
{
	hashtable_node *dh_node;
	unsigned int t_index,index,newsize;
	BOOL freetable = FALSE;
	hashtable_node **newtable;
	if((dh->tablelengthindex + 1) > 32) return DS_TABLELENGTH_LIMIT;
	newsize = dh->tablelength << 1;//链表长度增加一倍
	newtable = (hashtable_node **)malloc(sizeof(hashtable_node *) * newsize);
	if(newtable) 
	{
		memset(newtable,0,sizeof(hashtable_node *) * newsize);
		freetable = TRUE;
	}
	else 
	{
		newtable = (hashtable_node **)realloc(dh->node_table,sizeof(hashtable_node *) * newsize);
		if(newtable) 
		{
			memset(dh->node_table + sizeof(hashtable_node *) * dh->tablelength,0,
				sizeof(hashtable_node *) * ( newsize - dh->tablelength));
		}
	}
	if(newtable)
	{
        for(t_index = 0; t_index < dh->tablelength; t_index++)
		{
			while((dh_node = dh->node_table[t_index]) != NULL)
			{
				dh->node_table[t_index] = dh_node->next;
				index = gettableindex(dh->hashfromkey(dh_node->key),dh->tablelengthindex + 1);
				dh_node->next = newtable[index];
                newtable[index] = dh_node;
			}
		}
		if(freetable) free(dh->node_table);
		dh->node_table = newtable;
		dh->tablelength = newsize;
		dh->tablelengthindex++;
		dh->entrylimit *= 2;
		return DS_SUCCESS;
	}
	else 
	{
		return DS_MEMORY_ERROR;
	}
}

hashtable *hashtable_create_default_intkey()
{
    return hashtable_create_factor(default_minsize,default_factor,default_checkkeymutex,
		default_hashfromintkey,default_equalintkeys);
}
hashtable *hashtable_create_intkey(unsigned int minsize,BOOL checkkeymutex)
{
	return hashtable_create_factor(minsize,default_factor,checkkeymutex,
		default_hashfromintkey,default_equalintkeys);
}

hashtable *hashtable_create_intkey_factor(unsigned int minsize,float factor,BOOL checkkeymutex)
{
	return hashtable_create_factor(minsize,factor,checkkeymutex,
		default_hashfromintkey,default_equalintkeys);
}

hashtable *hashtable_create_default_stringkey()
{
	return hashtable_create_factor(default_minsize,default_factor,default_checkkeymutex,
		default_hashfromstringkey,default_equalstringkeys);
}

hashtable *hashtable_create_stringkey(unsigned int minsize,BOOL checkkeymutex)
{
    return hashtable_create_factor(minsize,default_factor,checkkeymutex,
		default_hashfromstringkey,default_equalstringkeys);
}

hashtable *hashtable_create_stringkey_factor(unsigned int minsize,float factor,BOOL checkkeymutex)
{
	return hashtable_create_factor(minsize,factor,checkkeymutex,
		default_hashfromstringkey,default_equalstringkeys);
}

hashtable *hashtable_create(unsigned int minsize,BOOL checkkeymutex,
	unsigned int (*hashfromkey)(void *key),int (*equalbykey)(void *key1,void *key2))
{
	return hashtable_create_factor(minsize,default_factor,checkkeymutex,
		hashfromkey,equalbykey);
}

hashtable *hashtable_create_factor(unsigned int minsize,float factor,BOOL checkkeymutex,
	unsigned int (*hashfromkey)(void *key),int (*equalbykey)(void *key1,void *key2))
{
	long lsize;
	unsigned int index,size;
	hashtable *dh;
	lsize = minsize/factor;
	if(lsize > (1u << 31)) return NULL;//1u == (unsigned int)1 1u << 31 = 4294967296
	for(index = 0; index < 32; index++)
	{
		if((1u << index ) >= lsize) 
		{
			lsize = 1u << index;
			break;
		}
	}
	size = (unsigned int)lsize;
	dh = MALLOC(hashtable,1);
	if(!dh) return NULL;
	dh->node_table = (hashtable_node **)malloc(sizeof(hashtable_node *) * size);
	if(!dh->node_table) return NULL;
	memset(dh->node_table,0,sizeof(hashtable_node *) * size);
	dh->tablelength = size;
	dh->tablelengthindex = index;
	dh->entrycount = 0;
	dh->entrylimit = (unsigned int)(size*factor);
	dh->checkkeymutex = checkkeymutex;
	dh->hashfromkey = hashfromkey;
	dh->equalbykey = equalbykey;
	return dh;
}

DS_RESULT hashtable_insert(void *key,void *data,hashtable *dh)
{
	hashtable_node *dh_node,*dh_newnode;
	unsigned int t_index;
	DS_RESULT r;
	assert(dh);
	if((dh->entrycount + 1) > dh->entrylimit) 
	{
		r = hashtable_expand(dh);
		if(r != DS_SUCCESS) return r;
	}
	if(dh->checkkeymutex)
	{
		if(hashtable_search_bykey(key,dh) != NULL) return DS_DUPLICATE_KEY;
	}
	dh_newnode = MALLOC(hashtable_node,1);
	if(!dh_newnode) return DS_MEMORY_ERROR;
	dh_newnode->key = key;
	dh_newnode->data = data;
	dh_newnode->hashvalue = dh->hashfromkey(key);
	t_index = gettableindex(dh_newnode->hashvalue,dh->tablelengthindex);
	dh_newnode->next = *(dh->node_table+t_index);
    *(dh->node_table+t_index) = dh_newnode;
	dh->entrycount++;
	return DS_SUCCESS;
}

void *hashtable_search_bykey(void *key,hashtable *dh)
{
	hashtable_node *dh_node;
	unsigned int t_index;
	unsigned long hv;
	assert(dh);
	hv = dh->hashfromkey(key);
	t_index = gettableindex(hv,dh->tablelengthindex);
    dh_node = *(dh->node_table+t_index);
	while(dh_node) 
	{
		if(dh_node->hashvalue == hv && dh->equalbykey(key,dh_node->key) == 0) return dh_node->data;
		dh_node = dh_node->next;
	}
	return NULL;
}
void *hashtable_modify_bykey(void *key,void *newvalue,hashtable *dh)
{
	hashtable_node *dh_node;
	unsigned int t_index;
	unsigned long hv;
	void *oldvalue;
	assert(dh);
	hv = dh->hashfromkey(key);
	t_index = gettableindex(hv,dh->tablelengthindex);
    dh_node = *(dh->node_table+t_index);
	while(dh_node)
	{
		if(dh_node->hashvalue == hv && dh->equalbykey(key,dh_node->key) == 0)
		{
			oldvalue = dh_node->data;
			dh_node->data = newvalue;
			return oldvalue;
		}
		dh_node = dh_node->next;
	}
	return NULL;
}

void *hashtable_remove_bykey(void *key,BOOL freekey,hashtable *dh)
{
	hashtable_node *dh_node,*dh_prenode;
	unsigned int t_index;
	assert(dh);
	t_index = gettableindex(dh->hashfromkey(key),dh->tablelengthindex);
	if(!dh->node_table[t_index]) return NULL;
	else
	{
        dh_prenode = dh->node_table[t_index];
		dh_node = dh_prenode;
		while(dh_node) 
		{
			if(dh->equalbykey(key,dh_node->key) == 0) 
			{
				if(dh_prenode == dh_node) dh_prenode = dh_node->next;
				else dh_prenode->next = dh_node->next;
				if(freekey) free(dh_node->key);
				dh->entrycount--;
				return dh_node->data;
			}
			else 
			{
				dh_prenode = dh_node;
				dh_node = dh_node->next;
			}
		}
		return NULL;
	}
}

void hashtable_free(hashtable *dh,BOOL freekey,BOOL freedata)
{
    hashtable_node *dh_node,*dh_nextnode;
	unsigned int t_index;
	if(!dh) return;
	for(t_index = 0; t_index < dh->tablelength; t_index++)
	{
		if(!dh->node_table[t_index]) continue;
		dh_node = dh->node_table[t_index];
		while(dh_node) 
		{
			dh_nextnode = dh_node->next;
			if(freekey) free(dh_node->key);
			if(freedata) free(dh_node->data);
			free(dh_node);
			dh_node = dh_nextnode;
		}
	}
	free(dh->node_table);
	free(dh);
}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -