- 给出一个序列:
47 7 29 11 9 84 54 20 30 如何才能对它们进行排序并且要查找它的位置的时候特别方便?
散列表就是找出每一个数据的关键字并且按照关键字存放在特定的位置;
核心思想就是弄一个映射函数H(key),使得key的位置ret=H(key)
除留余数法是找出某个数字p,让位置ret=key%p;
当然很有可能在存放了几个之后就会有重叠位置的情况发生,也就是冲突。
这里解决冲突的方法是平方探测法:让这个重叠的初始位置ret去加Di;
Di是一段序列:1^2,-1^2,2^2,-2^2.... 其中i是发生冲突的次数
例如说p=11.存放数字7的时候没问题(ret=7%11=7),然而存放29的时候(ret=29%11=7)
发生了冲突,那么第一次冲突就加1,也就是前进一格.8这个位置没有别的数据,不会冲突,所以存放在8;冲突解决
如果8这个位置也存放了其他的数字,那就是第二次冲突,这次要加D2也就是ret=(-1)=6;倒退一格
如果6这个位置也冲突那么就加D3也就是加4,前进四格...
循环下去直到找到空位置为止.
这里关键是找到这里的“某个数字p”。除留余数法中的p指的其实是散列表的最大储存空间。一般是比原序列大的素数。取素数是为了减少冲突。
这里的p用Tablesize表示
它的算法是由Nextprime函数解决的;
下面给出完整代码;里面包含了它的创建函数,查找函数(最重要也是调用最多)以及插入函数(需要调用到查找函数)
#include<stdio.h>
#include<stdlib.h>
#include<math.h>
#define Maxtablesize 10010
#define Empty 0
#define nice 1
/*散列查找,除留余数法:平方探测法;*/
typedef struct node{
int data;//整形数据类型
int Info;//单元状态
}Cell;//散列表的一个单元
typedef struct tblnode *Hashtable;//散列表类型
struct tblnode {
int TableSize;//最大长度
Cell *cells;//存放单元数据的数组
};
int Nextprime(int N)//N是数据总个数,寻找tablesize
{
//返回一个大于N,小于maxtablesize的素数;
int i,p=(N%2)?N+2:N+1; //p为N的后一个奇数
while(p<Maxtablesize)
{
for(i=(int)sqrt(p);i>2;i--)
{
if(p%i==0)//p不是素数
break;
}
if(i==2)//跳出while循环的条件
break;
else
p+=2;//否则就继续找
}
return p;
}
Hashtable creat(int N)//创建,初始化散列表
{
int i,n;
Hashtable H;
H=(Hashtable)malloc(sizeof(Hashtable));
n=H->TableSize=Nextprime(N);//获得Tablesize
H->cells=(Cell*)malloc(sizeof(Cell)*n);//申请空间
for(i=0;i<n;i++)
H->cells[i].Info=Empty;//初始化状态为空
return H;
}
int find(Hashtable H,int key)//查找函数,平方探测法 ,返回key的位置
{
int i=1,p=H->TableSize,ret,cnum=0,flag=1,cnt=0,num;
ret=key%p;//精准定位
if(H->cells[ret].data==key)return ret;//找到
int sum=ret;
while(H->cells[sum].Info!=Empty&&H->cells[sum].data!=key)
//照着位置找是另一个数据,有冲突,平方探测
{
flag*=-1;
num=-1*flag*i*i;
sum=ret+num;
if(sum>p)
sum%=p;
if(H->cells[sum].data==key)
{
return sum;
}
if(flag>0) i++;
}
//如果跳出了循环,要么在处理冲突之后找到了,要么就是没找到这个数字的位置,但是找到一个适合它放的地方,也就是一个空位
return sum;
}
int insert(Hashtable H,int key)
{
int p=find(H,key);
if(H->cells[p].Info==Empty)
{
H->cells[p].data=key;
H->cells[p].Info=nice;//标记为nice
return 1;//表示插入成功
}
else
return -1;//插入失败
}
int main()
{
int N,i,x;
Hashtable H;
scanf("%d",&N);
H=creat(N);
for(i=0;i<N;i++)
{
scanf("%d",&x);
insert(H,x);
}
while(1)
{
printf("输入要查找的位置,退出查找输入-1\n");
scanf("%d",&x);
if(x==-1) break;
printf("%d的位置:%d\n",x,find(H,x));
}
return 0;
}