热身赛一级赛题1,实现哈希表
Before Width: | Height: | Size: 75 KiB After Width: | Height: | Size: 156 KiB |
Before Width: | Height: | Size: 102 KiB After Width: | Height: | Size: 111 KiB |
|
@ -1,16 +1,16 @@
|
|||
# 基于cortex-m3-emulator实现哈希表并测试验证##
|
||||
# 基于cortex-m3-emulator实现哈希表并测试验证
|
||||
|
||||
## 1. 简介
|
||||
利用c语言实现了哈希表(HashMap),包括添加键值对(Put),获取键对应的值(Get), 删除健(Delete),清空哈希表(Clear), 迭代遍历哈希表(hashMapIterator)等功能
|
||||
操作。
|
||||
利用 c 语言实现了哈希表(HashMap),包括添加键值对(Put),获取键对应的值(Get), 删除健(Delete),清空哈希表(Clear), 迭代遍历哈希表(hashMapIterator)等功能操作。
|
||||
|
||||
利用数组(Entry)作为存储空间,利用链表(*next)解决冲突。当哈希表的大小超过数组大小后,为避免发生冲突过多的情况,可以对哈希表扩容。
|
||||
利用数组(Entry)作为存储空间,使用 DJB 哈希算法,利用线性探测法解决冲突,对哈希表中的数据进行逻辑删除。当哈希表的大小超过数组大小后,为避免发生冲突过多的情况,可以对哈希表扩容。当哈希表的大小小于数组大小的一半时,会释放一半的内存。
|
||||
|
||||
## 2. 数据结构设计说明
|
||||
键值对结构
|
||||
typedef struct entry {
|
||||
void * key; // 键
|
||||
void * value; // 值
|
||||
Boolean isDelete; // 逻辑删除
|
||||
struct entry * next; // 冲突链表
|
||||
}*Entry;
|
||||
|
||||
|
@ -31,6 +31,7 @@ typedef struct hashMap {
|
|||
|
||||
包括以下函数功能,分别为:
|
||||
`createHashMap`:创建一个哈希结构
|
||||
`defaultHashCode`:生成一个哈希值
|
||||
`defaultPut`:添加键值对
|
||||
`defaultGet`:获取键对应值
|
||||
`defaultRemove`:删除指定键的键值对
|
||||
|
@ -41,7 +42,7 @@ typedef struct hashMap {
|
|||
|
||||
## 3. 测试程序说明
|
||||
测试了哈希表的插入键值对(Put),判断键是否存在(Exist),获取键对应的值(Get), 删除健(Delete),迭代遍历哈希表(hashMapIterator),清空哈希表(Clear)等操作。
|
||||
并展示了利用链地址法解决哈希冲突的示例, 两个不同的人(Bob和Li Ming)的hashcode相同。
|
||||
并展示了利用线性探测法解决哈希冲突的示例, 多个原hashcode相同的人(Bob和Luna;Annie、Daniel和Li Ming)的新hashcode(存放的地址)不同。
|
||||
|
||||
## 4. 运行结果(##需结合运行测试截图按步骤说明##)
|
||||

|
||||
|
|
Before Width: | Height: | Size: 94 KiB After Width: | Height: | Size: 109 KiB |
Before Width: | Height: | Size: 95 KiB After Width: | Height: | Size: 114 KiB |
|
@ -11,21 +11,18 @@
|
|||
#include"test_hash.h"
|
||||
|
||||
int defaultHashCode(HashMap hashMap, let key) {
|
||||
char * k = (char *)key;
|
||||
unsigned long h = 0;
|
||||
while (*k) {
|
||||
h = (h << 4) + *k++;
|
||||
unsigned long g = h & 0xF0000000L;
|
||||
if (g) {
|
||||
h ^= g >> 24;
|
||||
char *k = (char *) key;
|
||||
// DJB哈希算法
|
||||
unsigned long hash = 5381;
|
||||
int c;
|
||||
while (c = *k++) {
|
||||
hash = ((hash << 5) + hash) + c; /* hash * 33 + c */
|
||||
}
|
||||
h &= ~g;
|
||||
}
|
||||
return h % hashMap->listSize;
|
||||
return hash % hashMap->listSize;
|
||||
}
|
||||
|
||||
Boolean defaultEqual(let key1, let key2) {
|
||||
return strcmp((string)key1, (string)key2) ? False : True;
|
||||
return strcmp((string) key1, (string) key2) ? False : True;
|
||||
}
|
||||
|
||||
void resetHashMap(HashMap hashMap, int listSize) {
|
||||
|
@ -38,12 +35,15 @@ void resetHashMap(HashMap hashMap, int listSize) {
|
|||
HashMapIterator iterator = createHashMapIterator(hashMap);
|
||||
int length = hashMap->size;
|
||||
for (int index = 0; hasNextHashMapIterator(iterator); index++) {
|
||||
// 迭代取出所有键值对
|
||||
// 迭代取出所有没有被逻辑删除的键值对
|
||||
iterator = nextHashMapIterator(iterator);
|
||||
if(!iterator->entry->isDelete){
|
||||
tempList[index].key = iterator->entry->key;
|
||||
tempList[index].value = iterator->entry->value;
|
||||
tempList[index].isDelete = False;
|
||||
tempList[index].next = NULL;
|
||||
}
|
||||
}
|
||||
freeHashMapIterator(&iterator);
|
||||
|
||||
// 清除原有键值对数据
|
||||
|
@ -52,6 +52,7 @@ void resetHashMap(HashMap hashMap, int listSize) {
|
|||
Entry current = &hashMap->list[i];
|
||||
current->key = NULL;
|
||||
current->value = NULL;
|
||||
current->isDelete = False;
|
||||
if (current->next != NULL) {
|
||||
while (current->next != NULL) {
|
||||
Entry temp = current->next->next;
|
||||
|
@ -61,59 +62,55 @@ void resetHashMap(HashMap hashMap, int listSize) {
|
|||
}
|
||||
}
|
||||
|
||||
// 更改内存大小
|
||||
// 更改内存大小
|
||||
hashMap->listSize = listSize;
|
||||
Entry relist = (Entry)realloc(hashMap->list, hashMap->listSize * sizeof(struct entry));
|
||||
Entry relist = (Entry) realloc(hashMap->list, hashMap->listSize * sizeof(struct entry));
|
||||
if (relist != NULL) {
|
||||
hashMap->list = relist;
|
||||
relist = NULL;
|
||||
}
|
||||
|
||||
// 初始化数据
|
||||
// 初始化数据
|
||||
for (int i = 0; i < hashMap->listSize; i++) {
|
||||
hashMap->list[i].key = NULL;
|
||||
hashMap->list[i].value = NULL;
|
||||
hashMap->list[i].isDelete = False;
|
||||
hashMap->list[i].next = NULL;
|
||||
}
|
||||
|
||||
// 将所有键值对重新写入内存
|
||||
// 将所有键值对重新写入内存
|
||||
for (int i = 0; i < length; i++) {
|
||||
hashMap->put(hashMap, tempList[i].key, tempList[i].value);
|
||||
}
|
||||
free(tempList);
|
||||
}
|
||||
|
||||
void defaultPut(HashMap hashMap, let key, let value) {
|
||||
Boolean defaultPut(HashMap hashMap, let key, let value) {
|
||||
// 获取哈希值
|
||||
int index = hashMap->hashCode(hashMap, key);
|
||||
|
||||
if (hashMap->list[index].key == NULL) {
|
||||
// 判断线性探测法是否成功插入
|
||||
Boolean result = False;
|
||||
// 如果发生冲突将根据线性探测法探测相邻的下一个单元是否可以存储,直到超出表长
|
||||
for (int indexNext = index; indexNext < hashMap->listSize; ++indexNext) {
|
||||
if (hashMap->list[indexNext].key == NULL) {
|
||||
hashMap->size++;
|
||||
// 该地址为空时直接存储
|
||||
hashMap->list[index].key = key;
|
||||
hashMap->list[index].value = value;
|
||||
}
|
||||
else {
|
||||
|
||||
Entry current = &hashMap->list[index];
|
||||
hashMap->list[indexNext].key = key;
|
||||
hashMap->list[indexNext].value = value;
|
||||
result = True;
|
||||
break;
|
||||
} else {
|
||||
Entry current = &hashMap->list[indexNext];
|
||||
while (current != NULL) {
|
||||
if (hashMap->equal(key, current->key)) {
|
||||
// 对于键值已经存在的直接覆盖
|
||||
current->value = value;
|
||||
return;
|
||||
return True;
|
||||
}
|
||||
current = current->next;
|
||||
};
|
||||
|
||||
// 发生冲突则创建节点挂到相应位置的next上
|
||||
Entry entry = newEntry();
|
||||
entry->key = key;
|
||||
entry->value = value;
|
||||
entry->next = hashMap->list[index].next;
|
||||
hashMap->list[index].next = entry;
|
||||
hashMap->size++;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
if (hashMap->autoAssign && hashMap->size >= hashMap->listSize) {
|
||||
|
||||
// 内存扩充至原来的两倍
|
||||
|
@ -124,30 +121,34 @@ void defaultPut(HashMap hashMap, let key, let value) {
|
|||
// 再次散列,会把冲突的数据再次分散开,加快索引定位速度。
|
||||
resetHashMap(hashMap, hashMap->listSize * 2);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
let defaultGet(HashMap hashMap, let key) {
|
||||
if (hashMap->exists(hashMap, key)) {
|
||||
int index = hashMap->hashCode(hashMap, key);
|
||||
Entry entry = &hashMap->list[index];
|
||||
while (entry != NULL) {
|
||||
if (hashMap->equal(entry->key, key)) {
|
||||
for (int indexNext = index; indexNext < hashMap->listSize; ++indexNext) {
|
||||
Entry entry = &hashMap->list[indexNext];
|
||||
if (entry == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
if (hashMap->equal(entry->key, key) && !entry->isDelete) {
|
||||
return entry->value;
|
||||
}
|
||||
entry = entry->next;
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
let defaultRemove(HashMap hashMap, let key) {
|
||||
Boolean defaultRemove(HashMap hashMap, let key) {
|
||||
int index = hashMap->hashCode(hashMap, key);
|
||||
Entry entry = &hashMap->list[index];
|
||||
if (entry->key == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
let entryKey = entry->key;
|
||||
Boolean result = False;
|
||||
for (int indexNext = index; indexNext < hashMap->listSize; ++indexNext) {
|
||||
Entry entry = &hashMap->list[indexNext];
|
||||
if (entry->key == NULL) {
|
||||
return result;
|
||||
}
|
||||
if (hashMap->equal(entry->key, key)) {
|
||||
hashMap->size--;
|
||||
if (entry->next != NULL) {
|
||||
|
@ -156,51 +157,32 @@ let defaultRemove(HashMap hashMap, let key) {
|
|||
entry->value = temp->value;
|
||||
entry->next = temp->next;
|
||||
free(temp);
|
||||
} else {
|
||||
entry->isDelete = True;
|
||||
}
|
||||
else {
|
||||
entry->key = NULL;
|
||||
entry->value = NULL;
|
||||
}
|
||||
result = True;
|
||||
}
|
||||
else {
|
||||
Entry p = entry;
|
||||
entry = entry->next;
|
||||
while (entry != NULL) {
|
||||
if (hashMap->equal(entry->key, key)) {
|
||||
hashMap->size--;
|
||||
p->next = entry->next;
|
||||
free(entry);
|
||||
result = True;
|
||||
break;
|
||||
}
|
||||
p = entry;
|
||||
entry = entry->next;
|
||||
};
|
||||
}
|
||||
|
||||
// 如果空间占用不足一半,则释放多余内存
|
||||
if (result && hashMap->autoAssign && hashMap->size < hashMap->listSize / 2) {
|
||||
resetHashMap(hashMap, hashMap->listSize / 2);
|
||||
}
|
||||
return entryKey;
|
||||
return result;
|
||||
}
|
||||
|
||||
Boolean defaultExists(HashMap hashMap, let key) {
|
||||
int index = hashMap->hashCode(hashMap, key);
|
||||
Entry entry = &hashMap->list[index];
|
||||
for (int indexNext = index; indexNext < hashMap->listSize; ++indexNext) {
|
||||
Entry entry = &hashMap->list[indexNext];
|
||||
// 判断是否存在关键字并且没有被逻辑删除
|
||||
if (entry->key == NULL) {
|
||||
return False;
|
||||
}
|
||||
else {
|
||||
while (entry != NULL) {
|
||||
if (hashMap->equal(entry->key, key)) {
|
||||
} else if (hashMap->equal(entry->key, key) && !entry->isDelete) {
|
||||
return True;
|
||||
}
|
||||
entry = entry->next;
|
||||
}
|
||||
return False;
|
||||
}
|
||||
}
|
||||
|
||||
void defaultClear(HashMap hashMap) {
|
||||
|
@ -245,6 +227,7 @@ HashMap createHashMap(HashCode hashCode, Equal equal) {
|
|||
Entry p = hashMap->list;
|
||||
for (int i = 0; i < hashMap->listSize; i++) {
|
||||
p[i].key = p[i].value = p[i].next = NULL;
|
||||
p[i].isDelete = False;
|
||||
}
|
||||
return hashMap;
|
||||
}
|
||||
|
@ -284,7 +267,7 @@ HashMapIterator nextHashMapIterator(HashMapIterator iterator) {
|
|||
return iterator;
|
||||
}
|
||||
|
||||
void freeHashMapIterator(HashMapIterator * iterator) {
|
||||
void freeHashMapIterator(HashMapIterator *iterator) {
|
||||
free(*iterator);
|
||||
*iterator = NULL;
|
||||
}
|
||||
|
@ -308,8 +291,9 @@ void TestHash() {
|
|||
HashMapIterator iterator = createHashMapIterator(map);
|
||||
while (hasNextHashMapIterator(iterator)) {
|
||||
iterator = nextHashMapIterator(iterator);
|
||||
printf("{ key: %s, key: %s, hashcode: %d }\n",
|
||||
(char *)iterator->entry->key, (char *)iterator->entry->value, iterator->hashCode);
|
||||
printf("{ key: %s, key: %s, oldHashcode: %d, newHashcode: %d }\n",
|
||||
(char *) iterator->entry->key, (char *) iterator->entry->value,
|
||||
iterator->hashMap->hashCode(iterator->hashMap, iterator->entry->key), iterator->hashCode);
|
||||
}
|
||||
printf("key: 000852, exists: %s\n", Existe(map, "000852") ? "true" : "false");
|
||||
printf("000852: %s\n", Get(map, "000852"));
|
||||
|
|
|
@ -23,7 +23,9 @@
|
|||
#define NEW(type) (type *)malloc(sizeof(type))
|
||||
|
||||
// 布尔类型
|
||||
enum _Boolean { True = 1, False = 0 };
|
||||
enum _Boolean {
|
||||
True = 1, False = 0
|
||||
};
|
||||
typedef enum _Boolean Boolean;
|
||||
|
||||
#define let void *
|
||||
|
@ -31,8 +33,9 @@ typedef enum _Boolean Boolean;
|
|||
typedef struct entry {
|
||||
let key; // 键
|
||||
let value; // 值
|
||||
struct entry * next; // 冲突链表
|
||||
}*Entry;
|
||||
Boolean isDelete; // 逻辑删除
|
||||
struct entry *next; // 冲突链表
|
||||
} *Entry;
|
||||
|
||||
#define newEntry() NEW(struct entry)
|
||||
#define newEntryList(length) (Entry)malloc(length * sizeof(struct entry))
|
||||
|
@ -48,14 +51,14 @@ typedef int(*HashCode)(HashMap, let key);
|
|||
// 判等函数类型
|
||||
typedef Boolean(*Equal)(let key1, let key2);
|
||||
|
||||
// 添加键函数类型
|
||||
typedef void(*Put)(HashMap hashMap, let key, let value);
|
||||
// 添加键函数类型 返回是否成功
|
||||
typedef Boolean(*Put)(HashMap hashMap, let key, let value);
|
||||
|
||||
// 获取键对应值的函数类型
|
||||
typedef let(*Get)(HashMap hashMap, let key);
|
||||
|
||||
// 删除键的函数类型
|
||||
typedef let(*Remove)(HashMap hashMap, let key);
|
||||
typedef Boolean(*Remove)(HashMap hashMap, let key);
|
||||
|
||||
// 清空Map的函数类型
|
||||
typedef void(*Clear)(HashMap hashMap);
|
||||
|
@ -75,7 +78,7 @@ typedef struct hashMap {
|
|||
Clear clear; // 清空Map
|
||||
Exists exists; // 判断键是否存在
|
||||
Boolean autoAssign; // 设定是否根据当前数据量动态调整内存大小,默认开启
|
||||
}*HashMap;
|
||||
} *HashMap;
|
||||
|
||||
// 迭代器结构
|
||||
typedef struct hashMapIterator {
|
||||
|
@ -83,7 +86,7 @@ typedef struct hashMapIterator {
|
|||
int count; // 迭代次数
|
||||
int hashCode; // 键值对的哈希值
|
||||
HashMap hashMap;
|
||||
}*HashMapIterator;
|
||||
} *HashMapIterator;
|
||||
|
||||
#define newHashMapIterator() NEW(struct hashMapIterator)
|
||||
|
||||
|
@ -93,14 +96,14 @@ static int defaultHashCode(HashMap hashMap, let key);
|
|||
// 默认判断键值是否相等
|
||||
static Boolean defaultEqual(let key1, let key2);
|
||||
|
||||
// 默认添加键值对
|
||||
static void defaultPut(HashMap hashMap, let key, let value);
|
||||
// 默认添加键值对 返回是否插入成功
|
||||
static Boolean defaultPut(HashMap hashMap, let key, let value);
|
||||
|
||||
// 默认获取键对应值
|
||||
static let defaultGet(HashMap hashMap, let key);
|
||||
|
||||
// 默认删除键
|
||||
static let defaultRemove(HashMap hashMap, let key);
|
||||
static Boolean defaultRemove(HashMap hashMap, let key);
|
||||
|
||||
// 默认判断键是否存在
|
||||
static Boolean defaultExists(HashMap hashMap, let key);
|
||||
|
@ -124,6 +127,6 @@ Boolean hasNextHashMapIterator(HashMapIterator iterator);
|
|||
HashMapIterator nextHashMapIterator(HashMapIterator iterator);
|
||||
|
||||
// 释放迭代器内存
|
||||
void freeHashMapIterator(HashMapIterator * iterator);
|
||||
void freeHashMapIterator(HashMapIterator *iterator);
|
||||
|
||||
#endif // !__HASHMAP_H__
|