散列表与哈希算法

1 哈希算法

哈希算法是建立元素与对应位置关系的映射
将二叉查找树查找一个元素所需时间复杂度为O(logN)(树高)提高到哈希表O(1)(一一对应映射)
整体是空间换时间

2 哈希函数

主要希望将元素分布均匀,减少冲突
主要有以下4种

2.1 直接地址法

H(key)=a*key+b
如:key=100;
H(key)=key/100+2;
得到映射位置为3;

2.2 除留取余法

这种最常见
H(key)=key%p;
p最好取质数,取质数分布均匀

2.3 数字分析法

如计算机IP地址有x1,x2…xn位值来放数字,分析每一位置上的数字,发现第i位数字分布相对均匀,可以用第i位数字作为地址存放不同序列号的元素

2.4 平方取中法

4731 * 4731 = 22,382,361
取中间两位82

2.5 折叠法

将关键词按长度分组相加
542+242+241=1025

3 冲突解决

3.1 什么叫冲突?

两个关键词被哈希到同一个位置
目前有两种解决大方向:闭散列表,开散列表

3.2 闭散列表

利用本散列表空余之处存放,必须支持插入,查找,删除操作

3.2.1 线性探查法

插入:如果发生冲突,把冲突的结点依次向后探查,直到找到一个空位置放下
查找:先找到哈希到的位置,不断判断是否相等,如果不相等,则向后排查,如果排查到最后一位也没有,则查找失败
删除:先查找到一个元素,给它一个删除标志,不delete(迟删除)
->在建立node时,放一个state,用来表示三种状态,无元素0,有元素1,被删除2

template <class KEY, class OTHER>
class closeHashTable:public dynamicSearchTable<KEY, OTHER> {
private:
struct node { //散列表的结点类
SET <KEY, OTHER> data;
int state; //0 -- empty 1 -- active 2 -- deleted
node() {state = 0;}
};
node *array;
int size;
int (*key)(const KEY &x); //函数指针key,指向将KEY转换成int的函数,可用户定义
static int defaultKey(const int &x) {return x;} //静态成员函数,不依赖于对象即可调用
public:
closeHashTable(int length = 101, int (*f)(const KEY &x) = defaultKey) ;
~closeHashTable() {delete [] array;}
SET<KEY, OTHER> *find(const KEY &x) const;
void insert(const SET<KEY, OTHER> &x);
void remove(const KEY &x) ;
};

此处难以理解的是 int(*key)(const KEY&x);
前面讲述的散列表是默认关键字为整型数,但实际中关键字不一定为整型数,因此调用默认函数将关键字转化成整型数。函数指针。
以下是构造函数:

template<classType>
closeHashTable<Type>::closeHashTable
(intlength,int(*f)(constType &x))
{
size=length;
array=newnode[size];
key=f;
}

insert函数实现

template<classKEY,classOTHER>
voidcloseHashTable<KEY,OTHER>::insert(constSET<KEY,OTHER>&x)
{ intinitPos,pos;
initPos=pos=key(x.key)%size;
do{
if(array[pos].state!=1){ // 0空或者2已删除,找到空单元,则插入
array[pos].data=x;
array[pos].state=1;
return;
}
pos=(pos+1)%size; //非空,继续走到下一位置
}while(pos!=initPos); //直到回到起点
}

pos=(pos+1)%size; 这句话易错,注意除掉的size,形成回环的效果,除以p就不对
中止条件是不要回到原位置while(pos!=initPos)

remove函数实现

remove函数的实现
template<classKEY,classOTHER>
voidcloseHashTable<KEY,OTHER>::remove(constKEY&x)
{ intinitPos,pos;
initPos=pos=key(x)%size;
do{
if(array[pos].state==0)return; // 位置为空,不需要删除
if(array[pos].state==1&&array[pos].data.key==x){
// 找到,删除
array[pos].state=2;
return;
}
pos=(pos+1)%size; // 非空且不等于查找关键字则走到下一位置
}while(pos!=initPos);
}

remove很简单,就是查找到这个元素以后,改成删除标记就可以了

find函数

template<classKEY,classOTHER>
SET<KEY,OTHER>*closeHashTable<KEY,OTHER>::find(constKEY&x)const
{ intinitPos,pos;
initPos=pos=key(x)%size;
do{
if(array[pos].state==0)returnNULL; // 没有找到
if(array[pos].state==1&&array[pos].data.key==x) // 找到
return(SET<KEY,OTHER>*) &array[pos];
pos=(pos+1)%size;
}while(pos!=initPos);
}

注意找到的意思是标记为1,并且元素值相等
线性探查法注意点:存的那一下不算线性探查,冲突后移动位置算一次线性探查

3.2.2 二次探查法

如果散列表大小是个素数,表至少一半空单元,插入时没有元素被探查两遍

3.2.3 再次散列表

地址为H1 (x) + 𝑖 ∗ H2(x) MOD m
一个散列表用于计算步长,一个用于计算起始地址

3.3 开散列表

将散列到同一位置的元素连接成单链表。散列表保存在数组中,数组中每个元素是单链表首地址

template<classKEY,classOTHER>
classopenHashTable:publicdynamicSearchTable<KEY,OTHER>{
private:
structnode{//开散列表中链表的结点类
SET<KEY,OTHER> data;
node *next;
node(constSET<KEY,OTHER>&d,node*n=NULL)
{data=d; next=n;}
node(){next=NULL;}
};
node**array;//指针数组,存储单链表头指针
int size;
int(*key)(constKEY&x);
staticintdefaultKey(constint&x){returnx;}
public:
openHashTable(intlength=101,
int(*f)(constKEY&x)=defaultKey);
~openHashTable();
SET<KEY,OTHER>*find(constKEY&x)const;
voidinsert(constSET<KEY,OTHER>&x);
voidremove(constKEY&x);
};

insert函数
从表头插入新元素,指向下一个元素

template<classKEY,classOTHER>
voidopenHashTable<KEY,OTHER>::insert
(constSET<KEY,OTHER>&x)
{
intpos;
node*p;
pos=key(x.key)%size;
array[pos]=newnode(x,array[pos]);//插入到表头
}

remove函数

template<classKEY,classOTHER>
voidopenHashTable<KEY,OTHER>::remove(constKEY&x)
{ int pos; node*p,
*q;
pos=key(x)%size;
if(array[pos]==NULL)return;
p=array[pos];///************
if(array[pos]->data.key==x){ // 删除第一个结点
array[pos]=p->next; //***************
delete p;
 return; }
while(p->next!=NULL&&!(p->next->data.key==x))//******
p=p->next; // 找到删除结点
if(p->next!=NULL){// 删除结点
q=p->next; p->next=q->next; deleteq; }
}

关键是
1删除单链表头元素怎么做
2 删除单链表中间元素怎么找,删完如何连接

find函数

find函数的实现
template<classKEY,classOTHER>
SET<KEY,OTHER>*openHashTable<KEY,OTHER>::find(constKEY&x)const
{
int pos; node*p;
pos=key(x)%size;
p=array[pos];
while(p!=NULL&&!(p->data.key==x))
p=p->next;
if(p==NULL)returnNULL;
else return(SET<KEY,OTHER>*)p;
}
  • 2
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值