您的位置:首页 > 理论基础 > 数据结构算法

【数据结构】简单哈希表的实现(开散列)

2018-03-03 18:37 555 查看
数据结构之哈希表的实现(开散列)

开散列的方法是,在哈希表中,把数组的每个元素都设置成一个单链表的头节点指针,也可以是不带头节点的单链表

如果出现哈希冲突,就把元素插入那个元素位置的单链表

哈希表结构体的代码如下:

#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;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息