[原创]空间换速度,c实现自连接Hashtable实现高性能数据存储

 在实现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 */

如果遇到问题望指正。
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值