哈希表是一种用于查找的数据结构,主要原理是通过数据的关键值进行查找和访问,最简单的不如在字符串中查找指定字符的问题,就是利用字符的ASCII码这个关键之进行的查找与访问。比如一个数字可以通过其个位数这个key值来散列,一个字符串可以用他的每个字符的ASCII码值之和(再取余)来散列,电话号码可以用他的后四位来散列,汉字可以用它的笔画数来散列等等。当然,散列还有散列函数的设计,碰撞问题等,这里先不谈,直接先写一个简单的散列表:
a)定义hash表和基本数据节点
- typedef
struct _NODE - {
-
int data; -
struct _NODE* next; - }NODE;
-
- typedef
struct _HASH_TABLE - {
-
NODE* value[10]; - }HASH_TABLE;
首先建立一个链表的基本节点的结构体,然后建立一个哈希表的结构体,结构体内是一个指向链表节点结构体的指针数组,这个数组就是hash表
b)创建hash表
- HASH_TABLE*
create_hash_table() - {
-
HASH_TABLE* pHashTbl = (HASH_TABLE*)malloc(sizeof(HASH_TABLE)); -
memset(pHashTbl, 0, sizeof(HASH_TABLE)); -
return pHashTbl; - }
创建链表函数返回值是hash表指针,函数中申明一个hash表结构体指针,然后用malloc动态创建一个哈希表结构体大小的空间,因为malloc的返回值为void*,所以要强制转换成哈希表结构体的指针,然后再赋值给刚声明的结构体指针,然后将该结构体清零,返回这个指针。
c)在hash表当中寻找数据
- NODE*
find_data_in_hash(HASH_TABLE* pHashTbl, int data) - {
-
NODE* pNode; -
if(NULL == pHashTbl) -
return NULL; -
-
if(NULL == (pNode = pHashTbl->value[data % 10])) -
return NULL; -
-
while(pNode){ -
if(data == pNode->data) -
return pNode; -
pNode = pNode->next; -
} -
return NULL; - }
在哈希表中寻找数据的函数返回值为链表节点结构体指针,函数参数为一个哈希表结构体的指针,和所查找数据的值。
函数中,先声明一个链表节点结构体指针,先判断哈希表是否为空,若为空,返回NULL。
通过哈希函数查找数值应在哈希表中的位置(这里的哈希函数是对10取模的函数),并将此位置赋值给之前声明的节点指针,若此位置为空,则同样返回NULL。
若不为空,通过这个指针开始遍历以哈希数组中此位置开始的链表,依次判断他们的data是否与查找值相等,若相等,则返回此此时的指针,若不相等,则继续使用pNode=pNode->next,检测下一个节点。
d)在hash表当中插入数据
- STATUS
insert_data_into_hash(HASH_TABLE* pHashTbl, int data) - {
-
NODE* pNode; -
if(NULL == pHashTbl) -
return FALSE; -
-
if(NULL == pHashTbl->value[data % 10]){ -
pNode = (NODE*)malloc(sizeof(NODE)); -
memset(pNode, 0, sizeof(NODE)); -
pNode->data = data; -
pHashTbl->value[data % 10] = pNode; -
return TRUE; -
} -
-
if(NULL != find_data_in_hash(pHashTbl, data)) -
return FALSE; -
-
pNode = pHashTbl->value[data % 10]; -
while(NULL != pNode->next) -
pNode = pNode->next; -
-
pNode->next = (NODE*)malloc(sizeof(NODE)); -
memset(pNode->next, 0, sizeof(NODE)); -
pNode->next->data = data; -
return TRUE; - }
插入函数的参数为一个哈希表结构体的指针和一个删除数据值。函数中首先声明一个链表节点结构体指针。同样的先判断哈希表指针是否为空,若为空,则返回false。
然后通过哈希函数找到数值应该插入的位置并判断数值应该插入的位置是否为空,若为空,则开始进行数值插入,步骤如下:(1)先在动态创建一个链表节点结构体大小的内存空间并将类型强行转化成链表结构体指针类型,然后赋值给之前声明的节点指针(2)将此结构体内存清零(3)将插入的数值赋给结构体中的data(4)然后将此结构体指针赋给哈希表中应该储存的位置的元素。(5)返回true。
调用查找函数查找要插入的值,若返回值不为空,则证明要插入的值在哈希表中已经存在。返回FALSE。
还有的情况就是,哈希表中数值应该插入的位置不为空,而数值也不再表中需要插入,则先找到数值应该插入的哈希表中的位置,将此位置的值赋给声明的节点指针,若指针指向的位置不为空,则循环使用pNode=pNode->next赋值语句遍历链表,直到指针为空即找到链表的尾部为止。
然后像之前一样,创建结构体空间,清零,赋值,最后返回true。
e)从hash表中删除数据
- STATUS
delete_data_from_hash(HASH_TABLE* pHashTbl, int data) - {
-
NODE* pHead; -
NODE* pNode; -
if(NULL == pHashTbl || NULL == pHashTbl->value[data % 10]) -
return FALSE; -
-
if(NULL == (pNode = find_data_in_hash(pHashTbl, data))) -
return FALSE; -
-
if(pNode == pHashTbl->value[data % 10]){ -
pHashTbl->value[data % 10] = pNode->next; -
goto final; -
} -
-
pHead = pHashTbl->value[data % 10]; -
while(pNode != pHead ->next) -
pHead = pHead->next; -
pHead->next = pNode->next; -
- final:
-
free(pNode); -
return TRUE; - }
删除数据函数参数为哈希表结构体的指针和需要删除的数据。先声明两个节点指针,pHead和pNode。
判断一下若哈希表为空或者需要删除的元素所应该在的位置为空,都返回FALSE。
使用查找函数查找需要删除的元素并将返回值赋值给pNode,若返回值为NULL,也返回FALSE。
此时有两种情况,一是此时pNode所指向的值正是索要删除的值,这直接将此节点的next指针赋值给哈希数组中的元素即此链表的头结点,然后goto final,用free(pNode)释放此指针,返回true。
二若不是,则我们需要找到pNode的前一个节点,将pHead从该链表头开始遍历,直到pHead->next==pNode,然后将pNode的后一个节点赋值给pHead的next指针,然后执行final。