散列是一种用于以常数平均时间执行插入、删除和查找的技术。理想的散列表数据结构是一个包含有关键字的具有固定大小的数组,基本思想是在记录的存储地址和他的关键字之间建立一个确定的对应关系,这个关系是通过哈希函数来确定的。
哈希函数:哈希函数通过某种规则,将要存储数据的关键字解析出一个int型的数据a,将数据存储到数组的第n个位置。规则可以自己设定,最简单的就是取字符的ASCII码,除以表长取余。
通过哈希函数来确定存储位置其实仔细想想就会发现问题,不同的关键字有可能解析出来是一个地址,但是一个地址只能放一个数据啊,这就是所谓的冲突。解决冲突的方法主要有两种:1.再哈希法 2.开放地址法 3.链地址法
再哈希法:设定若干个哈希函数,如果冲突了就用备用函数计算。多个哈希函数计算出来的还是同一个地址的概率就很低了
开放地址法:当发生冲突时,形成一个探查序列,从冲突的那个地址开始,沿着序列逐个探查,常用的探测再散列有线性再散列和二次再散列。以二次再散列来说,加如地址5冲突,则依次探测5+11=6,5+22=9。。。。。挺好理解的
链地址法:链地址就是在数组上插入链表,发生冲突后就插在链表头上。所以不管有多少冲突都没有问题
前面两种因为不涉及链表所以程序都比较好写,我们写一下链地址法的程序,写之前思考几个问题:
1.需要几个结构体,结构体成员有什么:
首先要建立一个链表结构体,链表结构体放有两个信息:数据、指向其他链表的指针
然后还要建立一个数组结构体,数组结构体中也需要两个信息:数组指针、数组大小是多少。数组大小没什么说的,int型就可以了。数组指针是什么呢?他要指向数组的第一个位置。那么数组中放的又是什么呢?数组中要指向链表,所以数组中放的是链表结构体指针,所以数组指针是一个指向链表结构体指针的指针。这里可能有点绕,那大家想一下,整数数组,是int a[5],那么a是什么,a是一个指向int的指针int*。类比,整型指针数组是int a[5],那么a是什么,a是指向int的指针,也就是int**.
2.数组中放不放数据。正常一个链表结构体指针是可以放数据的,但是要想个问题,插入链表时是要插在最前面,也就是说数组里放的那个结构体指针会变成插入的链表的地址,那就无法通过数组的头找到了,所以默认数组里面不放数据,只放指针。如果有人非要放,然后插入的时候从第二个查,也行,但就没什么意义了,还比较乱
3.如果插入的数据在散列表中已经有了怎么办,那就不插了,所以每次插入前必须先查找一下,确认没有了再插
上代码了
#include<stdio.h>//printf函数
#include<stdlib.h>//malloc函数
typedef struct ListNode *Position;
typedef struct Hash *Hashtable;
struct ListNode//散列表指针
{
int elem;
Position next;
};
typedef Position List;
struct Hash
{
char tableSize;
List *head;//结构体指针数组,指向结构体指针的指针
};
Hashtable InitHash(int size)
{
int i=0;
Hashtable h = (Hashtable)malloc(sizeof(struct Hash));
h->tableSize = size;
h->head = (Position*)malloc(h->tableSize*sizeof(List));
for(i=0;i<h->tableSize;i++)
{
h->head[i] = (List)malloc(sizeof(struct ListNode));
h->head[i]->next = NULL;
h->head[i]->elem = NULL;
}
return h;
}
int Hash(int key,int size)//计算哈希值
{
return key%size;
}
Position Find(int elem,Hashtable h)
{
Position p = NULL;
List l = h->head[Hash(elem,h->tableSize)];
p = l->next;
while(p!=NULL && p->elem!=elem)
p=p->next;
return p;
}
void Insert(int elem,Hashtable h)
{
Position p1 = Find(elem,h);
Position p2 = NULL;
if(p1==NULL)
{
p2 = (Position)malloc(sizeof(struct ListNode));
p2->next = h->head[Hash(elem,h->tableSize)]->next;
h->head[Hash(elem,h->tableSize)]->next = p2;
}
}
void main()
{
int i =0;
Hashtable h = InitHash(5);
Insert(5,h);
}