69,747
社区成员
发帖
与我相关
我的任务
分享
#ifndef HASHMAP_H_INCLUDED
#define HASHMAP_H_INCLUDED
//HashMap中的链表
typedef struct _entry
{
int hash;
void *key;
void *value;
struct _entry *next; //单向链表
} *Entry;
//主要用于hashmap_keySet()
typedef struct _hashmapset
{
void *key;
struct _hashmapset *next;
} *HashMapSet;
//hashmap 结构
typedef struct _hashmap
{
int K_E; //类似java中的泛型
int V_E; //类似java中的泛型
int size;
int capacity; //当前容量
int threshold; //门槛
float factor; //扩展因子,当空间不够用时
Entry table;
} *HashMap;
#ifndef E_H_INCLUDED
#define E_H_INCLUDED
enum E{E_STRING,E_INT,E_OBJECT}; //枚举类型
#endif // E_H_INCLUDED
void *hashmap_init(int k,int v); //初始化
void *hashmap_put(HashMap this,void *k,void *v); //在此映射中关联指定值与指定键。
void *hashmap_get(HashMap this,void *k); //返回指定键在此标识哈希映射中所映射的值,如果对于此键来说,映射不包含任何映射关系,则返回 null
void *hashmap_remove(HashMap this,void *k); //如果此映射中存在该键的映射关系,则将其删除。
HashMapSet hashmap_keySet(HashMap this); //返回此映射中所包含的键的 set 视图。
void hashmap_clear(HashMap this); //从此映射中移除所有映射关系。
void hashmap_free(HashMap this); //释放内存
#endif // HASHMAP_H_INCLUDED
//返回此映射中所包含的键的 set 视图
//注意在调用该函数的代码段中,处理完HashMapSet后,要free(HashMapSet);
HashMapSet hashmap_keySet(HashMap this)
{
//head 结点
HashMapSet set = malloc(sizeof(struct _hashmapset));
set->key = NULL;
set->next = NULL;
int i;
Entry e;
HashMapSet preSet = set; //上一个Set
int capacity = this->capacity;
for(i=0; i<capacity; i++)
{
for(e = this->table + i,e=e->next; e!=NULL; e=e->next)
{
//添加一个新结点
HashMapSet item = malloc(sizeof(struct _hashmapset));
item->key = e->key;
item->next = NULL;
preSet->next = item;
preSet = item; //
}
}
return set->next;
}
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "hashmap.h"
typedef struct object
{
char *name;
int age;
} *Object;
int main()
{
//初始化
HashMap map = hashmap_init(E_STRING,E_INT);
//检查hash碰撞,比如 'rQ' 和 'qp' 的 hashcode 一样
hashmap_put(map,"rQ",1);
hashmap_put(map,"qp",2);
hashmap_put(map,"a1",1);
hashmap_put(map,"a2",2);
hashmap_put(map,"a3",3);
hashmap_put(map,"b1",1);
hashmap_put(map,"b2",2);
hashmap_put(map,"b3",3);
hashmap_put(map,"b4",4);
hashmap_put(map,"b5",5);
hashmap_put(map,"b6",6);
hashmap_put(map,"b7",7);
hashmap_put(map,"b8",8);
hashmap_put(map,"b9",9);
char *p = malloc(sizeof(char) * 10);
strcpy(p,"a1");
hashmap_put(map,p,1);
hashmap_put(map,"rQrQ",5);
hashmap_put(map,"rQqp",6);
hashmap_put(map,"qprQ",7);
hashmap_put(map,"qpqp",8);
hashmap_put(map,"你1好",11);
hashmap_put(map,"你2好",12);
hashmap_put(map,"你3好",13);
printf("----------------------------put\n");
printf("put(rQqp):%d\n",hashmap_put(map,"rQqp",60));
printf("put(qprQ):%d\n",hashmap_put(map,"qprQ",60));
printf("----------------------------get\n");
char *t = malloc(sizeof(char) * 10);
strcpy(t,"a1");
printf("get(a1):%d\n",hashmap_get(map,t));
printf("get(rQqp):%d\n",hashmap_get(map,"rQqp"));
printf("get(qpqp):%d\n",hashmap_get(map,"qpqp"));
printf("get(你1好):%d\n",hashmap_get(map,"你1好"));
printf("get(你2好):%d\n",hashmap_get(map,"你2好"));
printf("get(你3好):%d\n",hashmap_get(map,"你3好"));
printf("----------------------------remove\n");
printf("remove(你1好):%d\n",hashmap_remove(map,"你1好"));
printf("remove(qpqp):%d\n",hashmap_remove(map,"qpqp"));
printf("\n");
printf("get(rQqp):%d\n",hashmap_get(map,"rQqp"));
printf("get(qpqp):%d\n",hashmap_get(map,"qpqp"));
printf("get(你1好):%d\n",hashmap_get(map,"你1好"));
printf("get(你2好):%d\n",hashmap_get(map,"你2好"));
printf("get(你3好):%d\n",hashmap_get(map,"你3好"));
printf("----------------------------keySet\n");
printf("size:%d\n",map->size);
HashMapSet set;
for(set = hashmap_keySet(map); set!=NULL; set=set->next)
{
printf("%s:%d\n",set->key,hashmap_get(map,set->key));
}
printf("----------------------------clear\n");
hashmap_clear(map);
printf("size:%d\n",map->size);
//HashMapSet set;
for(set = hashmap_keySet(map); set!=NULL; set=set->next)
{
printf("%s:%d\n",set->key,hashmap_get(map,set->key));
}
return 0;
}
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "hashmap.h"
//参考了java的HashMap.java中的hash算法
static int hash(int h)
{
/*
//java
h ^= (h >>> 20) ^ (h >>> 12);
return h ^ (h >>> 7) ^ (h >>> 4);
*/
unsigned int x = h; //由于要无符号右移,左边补0
x ^= (x >> 20) ^ (x >> 12);
return x ^ (x >> 7) ^ (x >> 4);
}
//参考了java的HashMap.java中的indexFor()
static int indexFor(int h, int length)
{
return h & (length-1);
}
//字符串的hashcode,改写java的String.hashCode();
static int stringHashCode(char *pStr)
{
int size = strlen(pStr);
if(size == 0)
{
return 0;
}
else
{
int i,h=0;
for(i=0; i<size; i++)
{
h = 31 * h + *pStr;
pStr++;
}
return h;
}
}
//扩大容量
static void resize(HashMap this,int newCapacity)
{
//printf("resize 前, capacity:%d,threshold:%d\n",this->capacity,this->threshold);
int oldCapacity = this->capacity;
Entry newTable = malloc(sizeof(struct _entry) * newCapacity);
//初始化为NULL;
int i;
for(i=0; i<newCapacity; i++)
{
(newTable + i)->next = NULL;
}
//由src指向地址为起始地址的连续n个字节的数据复制到以dest指向地址为起始地址的空间内。
//由于hash表的容量扩大,indexFor(int hash,int length)由于length改变,返回值也将改变,所以此处不能简单的使用memcpy
//memcpy(newTable,this->table,sizeof(struct _entry) * oldCapacity);
//重新确定新的位置indexFor(....)
//以下实现参照java的HashMap.java中的void transfer(Entry[] newTable)部分
int m,n;
for(m=0; m<oldCapacity; m++)
{
Entry e = (this->table + m)->next;
if(e!=NULL)
{
do
{
Entry next = e->next;
n = indexFor(e->hash,newCapacity);
e->next = (newTable + n)->next;
(newTable + n)->next = e;
e = next;
}
while(e!=NULL);
}
}
this->table = newTable;
this->capacity = newCapacity;
this->threshold = (int)(newCapacity * this->factor);
//printf("resize 后, capacity:%d,threshold:%d\n\n",this->capacity,this->threshold);
}
//添加一个结点到链表中
static void addEntry(HashMap this,void *k,void *v,int hashCode,int i)
{
Entry e = this->table + i; //先定位到一个链表的head 结点
//添加到链表中
do
{
if(e->next == NULL)
{
//新的结点
Entry item = malloc(sizeof(struct _entry));
item->hash = hashCode;
item->key = k;
item->value = v;
item->next = NULL;
e->next = item; //加入链表中
break;
}
}
while((e = e->next) != NULL);
this->size++; //size + 1
if (this->size >= this->threshold)
{
resize(this,2 * this->size); //扩大一倍容量
}
}
//初始化
void *hashmap_init(int k_e,int v_e)
{
HashMap map = malloc(sizeof(struct _hashmap));
map->K_E = k_e;
map->V_E = v_e;
map->size = 0;
map->capacity = 16;
map->factor = 0.75f;
map->threshold = (int)(map->capacity * map->factor);
map->table = malloc(sizeof(struct _entry) * map->capacity);
//初始化为NULL
int i;
int capacity = map->capacity;
for(i=0; i<capacity; i++)
{
(map->table+i)->next = NULL; //初始化
//printf("init %d address:%d\n",i,map->table + i);
}
//printf("capacity address:%d\n",&map->capacity);
return map;
}
//在此映射中关联指定值与指定键。
void *hashmap_put(HashMap this,void *k,void *v)
{
int hashCode;
if(this->K_E == E_STRING)
{
hashCode = hash(stringHashCode(k));
//printf("-----------%s:%d\n",k,hashCode);
}
else if(this->K_E == E_INT)
{
hashCode = hash(k);
}
else
{
hashCode = hash(k);
}
int i = indexFor(hashCode,this->capacity);
Entry e;
if(this->K_E == E_STRING || this->K_E == E_INT)
{
for(e = this->table + i,e=e->next; e!=NULL; e=e->next)
{
if((e->hash == hashCode) && (e->key == k || strcmp(e->key,k) == 0))
{
void *oldValue = e->value; //取原来的旧的值
e->value = v; //设置新值
return oldValue; //返回旧值
}
}
}
else
{
//这里不太完善,有待改进
for(e = this->table + i,e=e->next; e!=NULL; e=e->next)
{
if((e->hash == hashCode) && e->key == k)
{
void *oldValue = e->value; //取原来的旧的值
e->value = v; //设置新值
return oldValue; //返回旧值
}
}
}
//新的
addEntry(this,k,v,hashCode,i);
return NULL;
}
//返回指定键在此标识哈希映射中所映射的值,如果对于此键来说,映射不包含任何映射关系,则返回 null。
void *hashmap_get(HashMap this,void *k)
{
int hashCode;
if(this->K_E == E_STRING)
{
hashCode = hash(stringHashCode(k));
}
else if(this->K_E == E_INT)
{
hashCode = hash(k);
}
else
{
hashCode = hash(k);
}
int i = indexFor(hashCode,this->capacity);
Entry e;
if(this->K_E == E_STRING || this->K_E == E_INT)
{
for(e=this->table + i,e=e->next; e!=NULL; e=e->next)
{
if(e->hash == hashCode && (e->key == k || strcmp(e->key,k) == 0))
{
return e->value;
}
}
return NULL;
}
else
{
//这里不太完善,有待改进
for(e=this->table + i,e=e->next; e!=NULL; e=e->next)
{
if(e->hash == hashCode && e->key == k)
{
return e->value;
}
}
return NULL;
}
return NULL;
}
//如果此映射中存在该键的映射关系,则将其删除。
//注意在返回处理完成后,free();
void *hashmap_remove(HashMap this,void *k)
{
int hashCode;
if(this->K_E == E_STRING)
{
hashCode = hash(stringHashCode(k));
}
else if(this->K_E == E_INT)
{
hashCode = hash(k);
}
else
{
hashCode = hash(k);
}
int i = indexFor(hashCode,this->capacity);
Entry e;
Entry preE=NULL; //上一个
for(e=this->table+i,preE=e,e=e->next; e!=NULL; preE=e,e=e->next)
{
if(e->hash == hashCode && (e->key == k || strcmp(e->key,k) == 0))
{
if(e->next == NULL)
{
preE->next = NULL;
}
else
{
preE->next = e->next; //将此结点删除
}
e->next = NULL; //设置为NULL
this->size--; //size - 1
//free(e); //这里释放内存后,为什么下面还能正常返回值?
return e->value;
}
}
return NULL;
}
//返回此映射中所包含的键的 set 视图
//注意在返回处理完成后,free();
HashMapSet hashmap_keySet(HashMap this)
{
int size = this->size;
if(size == 0)
{
return NULL;
}
else
{
HashMapSet set = malloc(sizeof(struct _hashmapset));
set->key = NULL;
set->next = NULL;
int i;
Entry e;
HashMapSet preSet = set; //上一个Set
int capacity = this->capacity;
for(i=0; i<capacity; i++)
{
for(e = this->table + i,e=e->next; e!=NULL; e=e->next)
{
if(preSet->key == NULL)
{
//第一次赋值
preSet->key = e->key;
preSet->next = NULL;
}
else
{
//添加一个新结点
HashMapSet item = malloc(sizeof(struct _hashmapset));
item->key = e->key;
item->next = NULL;
preSet->next = item;
preSet = item; //
}
}
}
return set;
}
}
//从此映射中移除所有映射关系。
void hashmap_clear(HashMap this)
{
int capacity = this->capacity;
int i;
Entry e,item;
for(i=0; i<capacity; i++)
{
for(e = this->table + i,e=e->next; e!=NULL; item = e,e=e->next,free(item))
{
}
(this->table + i)->next = NULL; //重置为NULL
}
//free(this->table);
this->size = 0;
}
//释放内存
void hashmap_free(HashMap this)
{
int capacity = this->capacity;
Entry e,item;
int i;
for(i=0; i<capacity; i++)
{
for(e=this->table + i, e=e->next; e!=NULL; item=e,e=e->next,free(item))
{
}
}
this->capacity = 0;
this->size = 0;
free(this->table);
free(this);
}