在实现web服务器系统的过程公有几个地方要用到特殊的hashtabke,以前发表的c实现的hashtable有个重要的缺点就是必须动态的为每一项
分配数据容器,这样就会导致在内存分配上浪费大量时间,今天在网上再次参阅了.net
java的设计理念,发现java2。0中推出了新的Dictionary容器,但是java实现的方法是两个独立的容器,这还是会增加一次内存分配,对
于c,我们有更好的方法。
c是不会检查数组越界的,这既是缺点也是优点,当你确信分配的内存足够大时就可以在结构体中定一个1个长度的项数组,实际使用中照常按照常规数据就可以了。所以可以将两个数组合并到一个结构体中,我的hashtable定义是这样的:
typedef struct _HashNode HashNode;
typedef struct _hashTable HashTable;
struct _HashNode{ //散列表结点类型
char * key;
void * value; //此类依赖于应用
HashNode *next;//第一个表的连表指针
HashNode *pt;//单独的第二个hashindex项
};
struct _hashTable
{
unsigned int size;
unsigned int current;
HashNode items[1];
};
这样在分配hash结构题的过程中就可以malloc一次,比如:
HashTable *hs=(HashTable
*)calloc(1,HashDefaultlength*(sizeof(HashNode))+sizeof(HashTable));从而实现动
态长度的分配,数组的组织是在hashNode线此性增加的,HashNode *next;//第一个表的连表指针 HashNode
*pt;//单独的第二个hashindex项指针,这样就可以用一个结构体实现HashTable,pt记录第一个hashcode值,遇到冲突就将
pt指向实体 HashNode
items[1]的index,多次冲突就记录在next指针中,也就是说pt充当冲突的head指针地址,后面是一个链表(以前就是每次需要项的时候增
加一个连表内存分配),连表以next指针维护,实际上pt完全可以看作一个新的数组列,他跟主HashNode数组长度完全一致。
当然,在java中Dictionary的Load Factor = 1,但我实现的是一个Hashtable,原理大致一致,但是还是采用0。75作为Load Factor,这样才会减少链表的长度,增加寻址速度。
以下是我的实现代码,经过简单的压力测试,500万次增加读取时间空间在1秒以内,性能还算满意:
/*
* File:
hashtable.c 哈希表的实现
* Author: netpet
* Flower net server
* 关于本程序:为了避免堆栈内存的释放不可区分导致的错误,这里要求所有name和key都必须是堆内存
* 该hash表的hash函数是java的hash函数,所以增长因子也是hash的0.75
* 本程序是为一体化web server产品专用设计,具有部分代码为具体产品优化而不代表普遍通用性的特性
* 程序在linux 2.46下调试通过,编辑工具netbeans 6.1 for c
* 联系方式:Email:netpetboy@163.com QQ:51977431
* Created on 2008年6月3日, 下午4:14
*/
#include "hashtable.h"
#include <stdio.h>
unsigned int GethashValue(char *key)
{
unsigned int hash;
unsigned char *p;
for(hash=0, p = (unsigned char *)key; *p ; p++)
hash = 31 * hash + *p;
hash=hash & 0x7FFFFFFF;
return hash;
}
/*
*功能:指定大小的新哈希表
*参数:length:用给定的长度建立一个hashtable表
*返回:hash表
*/
HashTable * HashTableNew(int length)
{
HashTable *hs=(HashTable *)calloc(1,length*(sizeof(HashNode))+sizeof(HashTable));
hs->size=length;
hs->current=0;
return hs;
}
/*
*功能:固定初始大小的哈希表
*参数:无
*返回:返回系统默认容积的hash表
*/
HashTable * NewHashTable(void)
{
HashTable *hs=(HashTable *)calloc(1,HashDefaultlength*(sizeof(HashNode))+sizeof(HashTable));
hs->size=HashDefaultlength;
hs->current=0;
return hs;
}
/*
*功能:取得给定key的值
*参数: T:hash表指针 key:名称字符串
*返回:如果不存在就返回空
*/
void * HashGet(HashTable *T,char * key)
{
unsigned int hash=GethashValue(key);
int index=hash%T->size;
HashNode *node=T->items[index].pt;
while(node) {
if(!strcmp(key, node->key))
return node->value;
node=node->next;
}
return NULL;
}
/*
*功能:设置一个项,不确定该项是否已经存在,如果存在就将它覆盖
*参数: T:hash表指针地址 key:名称 value:值
*返回:void
*/
void HashSet(HashTable **To,char * key,void *value)
{
HashTable * T=*To;
if((T->size*75)<(T->current*100))/**大于边界0.75就扩展*/ {
HashExpend(To);
T=*To;
}
unsigned int hash=GethashValue(key);
int index=hash%T->size;
HashNode *node=T->items[index].pt;
if(!node)
T->items[index].pt=&T->items[T->current];
else {
while(node){
if(!strcmp(key, node->key)) {
node->value=value;
return;
}
if(node->next)
node=node->next;
else
break;
}
node->next=&T->items[T->current];
node=node->next;
node->next=NULL;
}
T->items[T->current].key=key;
T->items[T->current].value=value;
T->current++;
}
/*
*功能:新增一个项,可能会导致重复,但速度较快
*参数: T:hash表指针地址 key:名称 value:值
*返回:void
*/
void HashAdd(HashTable **To,char * key,void *value)
{
HashTable * T=*To;
if((T->size*75)<(T->current*100))/**大于边界0.75就扩展*/ {
HashExpend(To);
T=*To;
}
unsigned int hash=GethashValue(key);
int index=hash%T->size;
HashNode *node;
T->items[T->current].key=key;
T->items[T->current].value=value;
if(T->items[index].pt)
{
node=T->items[index].pt;
while(node->next)
node=node->next;
node->next=&T->items[T->current];
node=node->next;
node->next=NULL;
}
else
T->items[index].pt=&T->items[T->current];
T->current++;
}
/*
*功能:移出指定项
*参数:T:hash表指针 key:要移出的名称
*返回:void
*/
void HashRemove(HashTable *T, char * key) {
unsigned int hash=GethashValue(key);
int index=hash%T->size;
HashNode *node=T->items[index].pt, *node1;
node1=node;
while(node) {
if(!strcmp(key, node->key)) {
node->key=NULL;
node->value=NULL;
if(node==T->items[index].pt)
T->items[index].pt=NULL;
else
node1->next=node->next;
return;
}
node1=node;
node=node->next;
}
}
/*
*功能:是否包含指定项
*参数:T:hash表指针 key:名称
*返回:void
*/
int HashContainKey(HashTable *T,char * key)
{
unsigned int hash=GethashValue(key);
int index=hash%T->size;
HashNode *node=T->items[index].pt;
while(node) {
if(!strcmp(key, node->key))
return 1;
node=node->next;
}
return 0;
}
/**拷贝两个hash表*/
void HashCopy(HashTable **Tn,HashTable *To)
{
unsigned int i;
HashTable *T=*Tn;
HashNode * node=T->items;
HashNode * nodeT=To->items;
for(i=0;i<To->size;i++)
{
if(nodeT[i].key)
{
HashAdd(Tn,nodeT[i].key,nodeT[i].value);
}
}
}
/*
*功能:扩展现有的表
*参数:T;hash表指针地址
*返回:hash表
*/
HashTable * HashExpend(HashTable ** To)
{
HashTable *T=*To;
unsigned int length =(T->current) * 2 + 1;
HashTable *hs=(HashTable *)calloc(1, length*(sizeof(HashNode))+sizeof(HashTable));
hs->size=length;
hs->current=0;
HashCopy(&hs, T);
free(*To);
*To=hs;
return hs;
}
/*
*功能:打印hash表
*参数:T:hash表指针
*返回:void
*/
void PrintHash(HashTable *T)
{
HashNode *node=T->items,*node1;
int i;
for(i=0;i<T->size;i++) {
//if(node[i].key)
printf("当前引起的循环:%d:________________________\n",i);
printf("%d本项:Key:%sPT:%p,Next:%p,%p\n",i, node[i].key,node[i].value,node[i].pt,node[i].next,node[i]);
node1=node[i].pt;
while(node1)
{
printf("%d含有项:Key:%s \tPT:%p,\tNext:%p,%p\n",i, node1->key,node1->value,node1->pt,node1->next,node1);
node1=node1->next;
}
}
}
/*
*功能:释放一个hash表
*参数:T:hash表指针
*返回:void
*/
void HashFree(HashTable *T)
{
free(T);
}
/*
* File:
hashtable.h 哈希表的定义
* Author: netpet
* Flower net server
* 关于本程序:为了避免堆栈内存的释放不可区分导致的错误,这里要求所有name和key都必须是堆内存
* 该hash表的hash函数是java的hash函数,所以增长因子也是hash的0.75
* 本程序是为一体化web server产品专用设计,具有部分代码为具体产品优化而不代表普遍通用性的特性
* 程序在linux 2.46下调试通过,编辑工具netbeans 6.1 for c
* 联系方式:Email:netpetboy@163.com QQ:51977431
* Created on 2008年6月3日, 下午4:14
*/
#ifndef _HASHTABLE_H
#define _HASHTABLE_H
#ifdef __cplusplus
extern "C" {
#endif
#define NIL -1 //空结点标记依赖于关键字类型,本节假定关键字均为非负整数
#define HashDefaultlength 11 //表长度依赖于应用,但一般应根据。确定m为一素数
#include <stdlib.h>
typedef struct _HashNode HashNode;
typedef struct _hashTable HashTable;
struct _HashNode{ //散列表结点类型
char * key;
void * value; //此类依赖于应用
HashNode *next;//第一个表的连表指针
HashNode *pt;//单独的第二个hashindex项
};
struct _hashTable
{
unsigned int size;
unsigned int current;
HashNode items[1];
};
/*
*功能:Hash函数
*参数:str:要转换的字符串
*返回:经过转换的无符号的int值结果
*/
extern unsigned int GethashValue(char *key);
/*
*功能:取得给定key的值
*参数: T:hash表指针 key:名称字符串
*返回:void
*/
extern void * HashGet(HashTable *T,char * key);//HashSearch
/*
*功能:设置一个项,不确定该项是否已经存在,如果存在就将它覆盖
*参数: T:hash表指针地址 key:名称 value:值
*返回:void
*/
extern void HashSet(HashTable **To,char * key,void *value);
/*
*功能:增加一个确信是新的项,速度比较快,不做检查,可能会导致重复
*参数: T:hash表指针地址 key:名称 value:值
*返回:void
*/
extern void HashAdd(HashTable **To,char * key,void *value);
/*
*功能:移出指定项
*参数:T:hash表指针 key:要移出的名称
*返回:void
*/
void HashRemove(HashTable *T,char * key);
/*
*功能:是否包含指定项
*参数:T:hash表指针 key:名称
*返回:void
*/
int HashContainKey(HashTable *T,char * key);
/*
*功能:指定大小的新哈希表
*参数:length:用给定的长度建立一个hashtable表
*返回:hash表
*/
HashTable * HashTableNew(int length);
/*
*功能:固定初始大小的哈希表
*参数:无
*返回:返回系统默认容积的hash表
*/
HashTable * NewHashTable(void);
/*
*功能:扩展现有的表
*参数:T;hash表指针地址
*返回:hash表
*/
HashTable * HashExpend(HashTable ** T);
/*
*功能:打印hash表
*参数:T:hash表指针
*返回:void
*/
void PrintHash(HashTable *T);
/*
*功能:释放一个hash表
*参数:T:hash表指针
*返回:void
*/
void HashFree(HashTable *T);
#ifdef __cplusplus
}
#endif
#endif /* _HASHTABLE_H */
如果遇到问题望指正。
分享到:
相关推荐
在Java编程语言中,`Hashtable`是一个非常基础且重要的数据结构,它属于集合框架的一部分,提供了键值对(key-value pairs)的存储功能。`Hashtable`类是线程安全的,意味着在多线程环境下,它能确保数据的一致性和...
c语言实现hashtable,一个key可以对应多个data,c语言实现
在Java中,除了`HashTable`,还有其他实现,如`HashMap`,它在单线程环境下提供了更好的性能,而`ConcurrentHashMap`则在多线程环境下提供高性能且线程安全的解决方案。学习和掌握这些不同的实现方式可以帮助开发者...
标题中的"C语言hashtable"指的是使用C语言编写的哈希表实现。在C/C++中,我们通常需要自己设计哈希表的结构并实现相关的哈希函数、冲突解决策略以及插入、删除、查找等操作。这个描述暗示了提供的.c文件包含了一个...
在本篇文章中,我们将深入探讨哈希表的实现,特别是基于C语言的简单实现,参考文件"hashtable.c"和"hashtable.h"。 1. 哈希函数:哈希表的核心是哈希函数,它将输入(键或关键字)转换为数组索引。一个好的哈希函数...
《深入解析HashTable:C语言实现的精髓》 在计算机科学中,哈希表(HashTable)是一种数据结构,它实现了关联数组的抽象数据类型,能够快速地进行查找、插入和删除操作。哈希表通过将键(Key)映射到表中的一个位置...
在IT领域,哈希表(HashTable)是一种常用的数据结构,它通过哈希函数将键(Key)映射到数组的索引位置,从而快速查找、插入和删除数据。本篇文章将详细探讨如何利用C语言实现一个简单的哈希表。 首先,我们需要...
"哈希表_使用C语言实现哈希表数据结构_HashTable"这个压缩包很可能包含了具体的C语言代码示例,通过阅读和理解这些代码,你可以深入学习哈希表的实现细节,包括如何定义结构体、如何定义和应用哈希函数、如何处理...
哈希表(Hash Table)是一种在程序设计中广泛使用的数据结构,它通过散列函数将键(Key)映射到数组的索引位置,从而实现快速查找、插入和删除操作。在C语言中,虽然没有内置的哈希表库,但我们可以自定义实现一个...
哈希表(HashTable)是一种常见的数据结构,它通过哈希函数将键(Key)映射到数组的索引位置,从而实现快速查找、插入和删除操作。在C语言中实现哈希表,需要理解哈希函数的设计、冲突解决策略以及数据结构的组织...
在.NET Framework中,`Hashtable`是`System.Collections`命名空间提供的一种数据结构,用于处理和表示类似键/值(Key/Value)对的数据。其中: - **键**:通常用于快速查找,并且是区分大小写的。 - **值**:用于...
总之,使用Session和Hashtable实现购物车功能是一种常见且实用的方法,它充分利用了Web服务器的存储能力,保证了用户在多个页面间跳转时购物车数据的一致性。通过不断实践和优化,我们可以构建出高效、稳定的购物车...
哈希表(Hashtable)是.NET框架中的一种常用数据结构,主要用作键值对存储,它提供了快速的数据存取方式。在WinForm应用程序中,我们可能会利用Hashtable来管理各种对象,尤其是在需要高效查找和操作数据时。下面将...
在IT行业中,JSON(JavaScript Object Notation)是一种轻量级的数据交换格式,广泛用于Web服务和应用程序之间的数据传输。它以其简洁、易于阅读和编写的特点,成为开发者们首选的序列化方式。与此相关的,`...
易语言 HashTable 数据效验算法,使用内联汇编,数次优化。速度快且稳定
哈希表,又称散列表,是一种非常重要的数据结构,它以高效的方式实现了数据的存储和检索。在C语言中,由于没有内置的哈希表实现,程序员需要自定义数据结构来构建哈希表。本教程将深入探讨如何利用C语言构建和操作...
标题"hashtable存储IP"指出,我们将讨论如何利用哈希表来存储IP地址,以实现高效的数据操作。 IP地址是由32位二进制数组成的,通常被分为四组,每组8位,用点分十进制表示。例如,192.168.1.1。在处理IP地址时,...
2. **文件操作**:管理系统需要持久化存储数据,C语言提供了标准库函数如`fopen`, `fprintf`, `fscanf`等用于读写文件。可以将罚单信息存储到文本文件中,便于后续查询和更新。 3. **输入输出处理**:用户界面通常...
在IT行业中,JSON(JavaScript Object Notation)是一种轻量级的数据交换格式,广泛用于Web服务与客户端之间的数据传输。它以其简洁、易于阅读和编写的特点,成为编程语言间数据交互的首选。本篇文章将深入探讨如何...