【数据结构】简单哈希表的实现(开散列)
2018-03-03 18:37
555 查看
数据结构之哈希表的实现(开散列)
开散列的方法是,在哈希表中,把数组的每个元素都设置成一个单链表的头节点指针,也可以是不带头节点的单链表
如果出现哈希冲突,就把元素插入那个元素位置的单链表
哈希表结构体的代码如下:
哈希表的初始化:
把size设置为0,把哈希函数初始化,再把数组里面的每个元素都设置为NULL指针
代码如下:
哈希表的插入:
方法是,找到要插入的数组下标,判断该元素是否存在,如果存在(不包含元素相同的值),
就插入失败,否则,就是往单链表里插入一个元素(建议头插,比较方便)
代码如下:
哈希表的查找:
这个比较叫简单,用的函数还是上面插入时候查找函数
代码如下:
哈希表的删除:
删除是,找到该元素,然后删除单链表上的一个节点,这里用的主要是单链表那块的知识,也比较简单
代码如下:
剩下的几个都是简单的操作,全部代码在下面
我这里实现的是一个简单的哈希表,哈希表这块还需要认真学习,需要拓展一下,比如,如何存储字符串之类的问题
全部代码如下:
HashTable.h
HashTable.c
test.c
开散列的方法是,在哈希表中,把数组的每个元素都设置成一个单链表的头节点指针,也可以是不带头节点的单链表
如果出现哈希冲突,就把元素插入那个元素位置的单链表
哈希表结构体的代码如下:
#define HASHMAXSIZE 1000 typedef int HashType; typedef int ValueType; typedef size_t(*HashFunc)(HashType); typedef struct HashElem{ HashType key; ValueType value; struct HashElem* _next; }HashElem; typedef struct HashTable{ HashElem* data[HASHMAXSIZE]; size_t size; HashFunc hash_func; }HashTable;
哈希表的初始化:
把size设置为0,把哈希函数初始化,再把数组里面的每个元素都设置为NULL指针
代码如下:
/*初始化*/ void HashTableInit(HashTable* ht, HashFunc hash_func) { if (ht == NULL) { return; } int i = 0; for (; i < HASHMAXSIZE; i++) { ht->data[i] = NULL; } ht->size = 0; ht->hash_func = hash_func; }
哈希表的插入:
方法是,找到要插入的数组下标,判断该元素是否存在,如果存在(不包含元素相同的值),
就插入失败,否则,就是往单链表里插入一个元素(建议头插,比较方便)
代码如下:
HashElem* HashTableBucketFind(HashElem* head, HashType key) { if (head == NULL) { return NULL; } HashElem* cur = head; while (cur) { if (cur->key == key) { return cur; } cur = cur->_next; } return NULL; } HashElem* CreateNewNode(HashType key, ValueType value) { HashElem* new_node = (HashElem*)malloc(sizeof(HashElem)); if (new_node != NULL) { new_node->key = key; new_node->value = value; new_node->_next = NULL; } return new_node; } /*插入*/ int HashTableInsert(HashTable* ht, HashType key, ValueType value) { if (ht == NULL) { return; } size_t offset = ht->hash_func(key); /* **找到该元素的存放位置 **遍历链表,判断有没有相同的元素 **如果没有,就头插然后返回1, 如果有,就退出,返回0 */ HashElem* cur = HashTableBucketFind(ht->data[offset], key); if (cur == NULL) { /*表示可以直接插入*/ HashElem* to_insert = CreateNewNode(key, value); to_insert->_next = ht->data[offset]; ht->data[offset] = to_insert; ++ht->size; } else { /*表示在当前位置有相同的元素,则不能插入*/ return 0; } }
哈希表的查找:
这个比较叫简单,用的函数还是上面插入时候查找函数
代码如下:
/*查找*/ int HashTableFind(HashTable* ht, HashType key, ValueType* value) { if (ht == NULL || value == NULL) { return 0; } size_t offset = ht->hash_func(key); HashElem* cur = HashTableBucketFind(ht->data[offset], key); if (cur == NULL) { /*没找到*/ return 0; } else { *value = cur->value; return 1; } }
哈希表的删除:
删除是,找到该元素,然后删除单链表上的一个节点,这里用的主要是单链表那块的知识,也比较简单
代码如下:
int HashBucketCur_Pre(HashElem* head, HashElem** cur, HashElem** pre, HashType key) { if (head == NULL) { return 0; } if (cur == NULL || pre == NULL) { return 0; } *cur = head; while (*cur) { if ((*cur)->key == key) { return 1; } *pre = *cur; *cur = (*cur)->_next; } return 0; } void DestoryHashElem(HashElem* node) { if (node == NULL) { return; } free(node); } /*删除*/ int HashTableRemove(HashTable* ht, HashType key) { if (ht == NULL) { return; } size_t offset = ht->hash_func(key); HashElem* pre = NULL; HashElem* cur = NULL; int ret = HashBucketCur_Pre(ht->data[offset], &cur, &pre, key); if (ret == 0) { /*没有找到*/ printf("该元素不在哈希表中!\n"); return 0; } else { /*找到了*/ if (cur == ht->data[offset]) { /*要删除的是头节点*/ ht->data[offset] = cur->_next; DestoryHashElem(cur); cur = NULL; --ht->size; return 1; } else { pre->_next = cur->_next; DestoryHashElem(cur); cur = NULL; --ht->size; return 1; }// cur != ht->data[offset] }//ret != 0 }//函数结束
剩下的几个都是简单的操作,全部代码在下面
我这里实现的是一个简单的哈希表,哈希表这块还需要认真学习,需要拓展一下,比如,如何存储字符串之类的问题
全部代码如下:
HashTable.h
#pragma once
#include<stdio.h>
#include<stddef.h>
#define HASHMAXSIZE 1000 typedef int HashType; typedef int ValueType; typedef size_t(*HashFunc)(HashType); typedef struct HashElem{ HashType key; ValueType value; struct HashElem* _next; }HashElem; typedef struct HashTable{ HashElem* data[HASHMAXSIZE]; size_t size; HashFunc hash_func; }HashTable;
/*初始化*/
void HashTableInit(HashTable* ht, HashFunc hash_func);
/*插入*/
int HashTableInsert(HashTable* ht, HashType key, ValueType value);
/*查找*/
int HashTableFind(HashTable* ht, HashType key, ValueType* value);
/*删除*/
int HashTableRemove(HashTable* ht, HashType key);
/*哈希表中的数据数量*/
size_t HashTableSize(HashTable* ht);
/*哈希表判空*/
int HashTableEmpty(HashTable* ht);
/*销毁哈希表*/
void HashTableDestory(HashTable* ht);
HashTable.c
#define _CRT_SECURE_NO_WARNINGS 1
#include"HashTable(open).h"
#include<stdio.h>
#include<stdlib.h>
/*初始化*/ void HashTableInit(HashTable* ht, HashFunc hash_func) { if (ht == NULL) { return; } int i = 0; for (; i < HASHMAXSIZE; i++) { ht->data[i] = NULL; } ht->size = 0; ht->hash_func = hash_func; }
HashElem* HashTableBucketFind(HashElem* head, HashType key) {
if (head == NULL) {
return NULL;
}
HashElem* cur = head;
while (cur) {
if (cur->key == key) {
return cur;
}
cur = cur->_next;
}
return NULL;
}
HashElem* CreateNewNode(HashType key, ValueType value) {
HashElem* new_node = (HashElem*)malloc(sizeof(HashElem));
if (new_node != NULL) {
new_node->key = key;
new_node->value = value;
new_node->_next = NULL;
}
return new_node;
}
/*插入*/
int HashTableInsert(HashTable* ht, HashType key, ValueType value) {
if (ht == NULL) {
cbff
return;
}
size_t offset = ht->hash_func(key);
/*
**找到该元素的存放位置
**遍历链表,判断有没有相同的元素
**如果没有,就头插然后返回1, 如果有,就退出,返回0
*/
HashElem* cur = HashTableBucketFind(ht->data[offset], key);
if (cur == NULL) {
/*表示可以直接插入*/
HashElem* to_insert = CreateNewNode(key, value);
to_insert->_next = ht->data[offset];
ht->data[offset] = to_insert;
++ht->size;
}
else {
/*表示在当前位置有相同的元素,则不能插入*/
return 0;
}
}
/*查找*/ int HashTableFind(HashTable* ht, HashType key, ValueType* value) { if (ht == NULL || value == NULL) { return 0; } size_t offset = ht->hash_func(key); HashElem* cur = HashTableBucketFind(ht->data[offset], key); if (cur == NULL) { /*没找到*/ return 0; } else { *value = cur->value; return 1; } }
int HashBucketCur_Pre(HashElem* head, HashElem** cur, HashElem** pre, HashType key) { if (head == NULL) { return 0; } if (cur == NULL || pre == NULL) { return 0; } *cur = head; while (*cur) { if ((*cur)->key == key) { return 1; } *pre = *cur; *cur = (*cur)->_next; } return 0; } void DestoryHashElem(HashElem* node) { if (node == NULL) { return; } free(node); } /*删除*/ int HashTableRemove(HashTable* ht, HashType key) { if (ht == NULL) { return; } size_t offset = ht->hash_func(key); HashElem* pre = NULL; HashElem* cur = NULL; int ret = HashBucketCur_Pre(ht->data[offset], &cur, &pre, key); if (ret == 0) { /*没有找到*/ printf("该元素不在哈希表中!\n"); return 0; } else { /*找到了*/ if (cur == ht->data[offset]) { /*要删除的是头节点*/ ht->data[offset] = cur->_next; DestoryHashElem(cur); cur = NULL; --ht->size; return 1; } else { pre->_next = cur->_next; DestoryHashElem(cur); cur = NULL; --ht->size; return 1; }// cur != ht->data[offset] }//ret != 0 }//函数结束
/*哈希表中的数据数量*/
size_t HashTableSize(HashTable* ht) {
if (ht == NULL) {
return 0;
}
return ht->size;
}
/*哈希表判空*/
int HashTableEmpty(HashTable* ht) {
if (ht == NULL) {
return 1;
}
int i = 0;
for (; i < HASHMAXSIZE; i++) {
if (ht->data[i] != NULL) {
return 0;
}
}
return 1;
}
/*销毁哈希表*/
void HashTableDestory(HashTable* ht) {
if (ht == NULL) {
return;
}
int i = 0;
for (; i < HASHMAXSIZE; ++i) {
if (ht->data[i] != NULL) {
/*表示该位置有元素,遍历然后删除*/
HashElem* cur = ht->data[i];
HashElem* to_delte = NULL;
while (cur) {
to_delte = cur;
cur = cur->_next;
DestoryHashElem(to_delte);
to_delte = NULL;
ht->data[i] = NULL;
}//cur == NULL
}//ht->data[i] == NULL
}//i >= HASHMAXSIZE
ht->size = 0;
ht->hash_func = NULL;
}
test.c
#define _CRT_SECURE_NO_WARNINGS 1 #include"HashTable(open).h" #include<stdio.h> #include<stdlib.h> size_t hash_func(HashType key) { return key % HASHMAXSIZE; } #define TESTHEAD printf("------------%s------------\n",__FUNCTION__) void HashTablePrint(HashTable* ht) { if (ht == NULL) { return; } int i = 0; for (; i < HASHMAXSIZE; ++i) { if (ht->data[i] != NULL) { HashElem* cur = ht->data[i]; while (cur) { printf("[%d]: key = %4d, value = %5d, _next-> ", i, cur->key, cur->value); cur = cur->_next; } printf("NULL\n"); } } } void TestInit() { HashTable ht; TESTHEAD; HashTableInit(&ht, hash_func); int i = 0; for (; i < HASHMAXSIZE; ++i) { if (ht.data[i] != NULL) { printf("index = %d 的位置未被初始化\n", i); } } printf("expect 0, actual:%d\n", ht.size); printf("expect %p, actual:%p\n", hash_func, ht.hash_func); } void TestInsert() { HashTable ht; TESTHEAD; HashTableInit(&ht, hash_func); HashTableInsert(&ht, 101, 100); HashTableInsert(&ht, 102, 200); HashTableInsert(&ht, 1001, 300); HashTableInsert(&ht, 1001, 400); HashTableInsert(&ht, 1002, 500); HashTableInsert(&ht, 1, 100); HashTableInsert(&ht, 2, 200); HashTablePrint(&ht); } void TestFind() { HashTable ht; TESTHEAD; HashTableInit(&ht, hash_func); HashTableInsert(&ht, 101, 100); HashTableInsert(&ht, 102, 200); HashTableInsert(&ht, 1001, 300); HashTableInsert(&ht, 1001, 400); HashTableInsert(&ht, 1002, 500); HashTableInsert(&ht, 1, 600); HashTableInsert(&ht, 2, 700); HashTablePrint(&ht); ValueType value = -1; int ret = HashTableFind(&ht, 101, &value); printf("expect 1, actual:%d\n", ret); printf("expect 100, actual:%d\n", value); int ret2 = HashTableFind(&ht, 103, &value); printf("expect 0, actual:%d\n", ret2); int ret3 = HashTableFind(&ht, 1002, &value); printf("expect 1, actual:%d\n", ret3); printf("expect 500, actual:%d\n", value); } void TestRemove() { HashTable ht; TESTHEAD; HashTableInit(&ht, hash_func); HashTableInsert(&ht, 1001, 300); HashTableInsert(&ht, 1001, 400); HashTableInsert(&ht, 1002, 500); HashTableInsert(&ht, 1, 600); HashTableInsert(&ht, 2, 700); printf("删除前:\n"); HashTablePrint(&ht); /*测试删除一个头节点元素*/ printf("删除后:\n"); HashTableRemove(&ht, 1); HashTablePrint(&ht); /*测试删除不存在的元素*/ printf("测试删除哈希表中不存在的元素:\n"); HashTableRemove(&ht, 1); HashTablePrint(&ht); /*测试删除正常元素*/ printf("测试删除正常元素:\n"); HashTableRemove(&ht, 1001); HashTableRemove(&ht, 1002); HashTablePrint(&ht); } void TestHash_Size_Empty() { HashTable ht; TESTHEAD; HashTableInit(&ht, hash_func); int ret = HashTableEmpty(&ht); printf("expect 1, actual:%d\n", ret); HashTableInsert(&ht, 1001, 300); HashTableInsert(&ht, 1001, 400); HashTableInsert(&ht, 1002, 500); HashTableInsert(&ht, 1, 600); HashTableInsert(&ht, 2, 700); printf("删除前:\n"); HashTablePrint(&ht); ret = HashTableEmpty(&ht); printf("expect 0, actual:%d\n", ret); size_t sz = HashTableSize(&ht); printf("expect 4, actual:%d\n", sz); } void TestDestory() { HashTable ht; TESTHEAD; HashTableInit(&ht, hash_func); HashTableInsert(&ht, 1001, 100); HashTableInsert(&ht, 1001, 200); HashTableInsert(&ht, 1002, 300); HashTableInsert(&ht, 1, 400); HashTableInsert(&ht, 2, 500); HashTableInsert(&ht, 3, 600); HashTableInsert(&ht, 4, 700); HashTableInsert(&ht, 5, 800); HashTableInsert(&ht, 6, 900); HashTableInsert(&ht, 7, 1000); HashTablePrint(&ht); HashTableDestory(&ht); } int main() { TestInit(); TestInsert(); TestFind(); TestRemove(); TestHash_Size_Empty(); TestDestory(); system("pause"); return 0; }
相关文章推荐
- 【数据结构】通讯录查询系统的设计与实现(散列表(哈希表))
- 数据结构(java语言描述)-- 表的简单数组实现
- Java实现简单图数据结构
- 数据结构(Java语言)——BinaryHeap简单实现
- 编程中常用的重要的数据结构实现(一)之哈希表
- c语言实现最简单的哈希表(开放地址线性探测法)
- 散列表(哈希表)的实现
- javascript 哈希表(hashtable)的简单实现
- C++,数据结构,单向链表的实现及简单运用,运用模板
- 简单数据结构之队列(C++模板库实现)
- 哈希表一个简单的实现
- Java基础课程学习总结,使用LinkedList简单模拟队列数据结构和堆栈数据结构的实现
- 数据结构(Java语言)——ArrayList简单实现
- 数据结构-顺序表Java简单实现
- Pyhont基础:简单数据结构的实现
- JAVA 数据结构 --散列表的实现
- 简单数据结构之循环链表(C++实现)
- (一)数据结构之线性表的简单实现:链表
- 简单数据结构----链栈的C++实现
- [C++]数据结构:散列表(哈希表)、散列函数构造、处理散列冲突