一、哈希表是什么?
散列表(Hash table,也叫哈希表),是根据关键码值(Key-Value)而直接进行访问的数据结构。
也就是说,它通过把关键码值映射到表中一个位置来访问记录,以加快查找的速度。这个映射函数叫做散列函数,存放记录的数组叫做散列表。
给定表M,存在函数f(key),对任意给定的关键字值key,代入函数后若能得到包含该关键字的记录在表中的地址,则称表M为哈希(Hash)表,函数f(key)为哈希(Hash) 函数所以我们可以知道:
哈希表的优点在于,查找效率高O(1),但是耗费空间。
思想我个人认为是空间换取时间……
二、哈希函数的构造方法:
1、直接定址法:取关键字或关键字的某个线性函数值为哈希地址。
2、数字分析法:假设关键字是以r为基的数(如:以10为基的十进制数),并且哈希表中可能出现的关键字都是事先知道的,则可取关键字的若干数位组成哈希地址。
3、平方取中法:取关键字平方后的中间几位为哈希地址。
4、斐波那契(Fibonacci)散列法
5、折叠法:将关键字分割成位数相同的几部分(最后一部分的位数可以不同),然后取这几部分的叠加和(舍去进位)作为哈希地址,这方法称为折叠法。
6、除留余数法:取关键字被某个不大于哈希表表长m的数p除后所得余数为哈希地址。即H(key)=key MOD p,(p<=m),这是一种最简单,也是最常用的构造哈希函数的方法。它不仅可以对关键字直接取模(MOD),也可在折叠、平方取中等运算之后取模。
7、随机数法:选择一个随机函数,取关键字的随机函数值为它的哈希地址,即H(key)=random(key),其中random为随机函数。通常,当关键字长度不等时采用此法构造哈希函数较切当。
三、哈希表的缺陷:
哈希表总会不可避免的产生冲突(尤其是在数据量大的时候),这个时候就需要一个方法来解决冲突,以下是几种常用的解决冲突的方法:
1、开放定址法
2、再哈希法
3、链地址法
4、建立一个公共溢出区
四、代码实现:
笔者这次发的代码主要是把一堆数字建成哈希表,然后查找数字。这里使用了链地址法去解决冲突,在这里顺便解释一下链地址法吧。
假设经过哈希函数处理,元素A、B、C、D在哈希表中的位置是一样的,也就是说:A、B、C、D四个元素发生了冲突。这个时候呢,我们不妨让先来的A放在哈希表里,然后让A(一个结构体元素,里边存着有指针)指向B,B指向C,C指向D。后面还有冲突元素过来也是这样连上去。换句话说:我们是用一个链表把这些相似的元素存了起来。
#include <stdio.h> #include <stdlib.h> #define TRUE 1 #define FALSE 0 #define HASH_SIZE 12 typedef struct Hash_Table{ int data; Hash_Table* next; }*Hash_TablePtr; int Hash(int key); int Search(Hash_TablePtr hash, int key); int main(){ Hash_Table hash[HASH_SIZE]; int i, search; int temp[HASH_SIZE] = { 9, 31, 26, 19, 1, 13, 2, 11, 27, 16, 5, 21 }; for (i = 0; i < HASH_SIZE; i++){ hash[i].data = -1; hash[i].next = NULL; } for (i = 0; i < HASH_SIZE; i++){ int x, y; x = temp[i]; y = Hash(x); Hash_TablePtr pre; if (hash[y].data == -1) hash[y].data = x; else{ Hash_TablePtr chain_adress = (Hash_TablePtr)malloc(sizeof(Hash_Table)); chain_adress->data = x; chain_adress->next = NULL; pre = &hash[y]; while (pre->next != NULL) pre = pre->next; pre->next = chain_adress; } } printf("请输入要找的数:"); scanf("%d", &search); if (Search(hash, search)) printf("找到了\n"); else printf("没找到\n"); } int Hash(int key){ return key % 11; } int Search(Hash_TablePtr hash, int key){ int adress = Hash(key); if (hash[adress].data == -1) return FALSE; else if (hash[adress].data == key) return TRUE; else{ Hash_TablePtr temp = &hash[adress]; while (temp != NULL){ temp = temp->next; if (temp == NULL) return FALSE; else if (temp->data == key) return TRUE; } return FALSE; } }