今天我来分享一下有关哈希的基本算法。
1.首先哈希就相当于分类。这种存储机构通过某种函数时元素的存储位置与它的关键词之前能够建立一一映射的关系,那么在查找时通过该函数可以快速找到该元素。
2.同时在哈希中,会出现一种哈希冲突的情况。处理哈希冲突有线性探测、二次探测。
3.闭散列代码:
//闭散列。
#pragma once
#include<stdio.h>
#include<assert.h>
#include<Windows.h>
typedef int Key;
typedef int(*HashFunc)(Key,int); //哈希函数。
typedef enum{ //哈希表里每个值得状态类型。
EMPTY, //空状态
EXIST, //存在状态
DELETED //假删状态
}State;
typedef struct Element{ //每个元素的结构。
Key key;
State state;
}Element;
typedef struct HashTable{ //哈希表的结构。
Element *array;
int capacity;
int size;
HashFunc hashfunc;
}HashTable;
int hashfunc(Key key,int capacity) //哈希的除留余数函数。
{
return key % capacity;
}
void HashTableInit(HashTable *pHT,int capacity,HashFunc hashfunc) //初始化哈希。
{
int i;
assert(pHT);
pHT->array=(Element *)malloc(sizeof(Element)*capacity); //创建空间。
pHT->size=0;
pHT->capacity=capacity;
pHT->hashfunc=hashfunc;
for(i=0;i<capacity;i++) //将所有值得状态设为空。
{
pHT->array[i].state=EMPTY;
}
}
//查找,并返回查找次数。失败返回-1.
int search(HashTable *pHT,Key key)
{
int n=pHT->hashfunc(key,pHT->capacity); //用哈希函数得到查找值应该在的下标。
int count=1;
assert(pHT);
while(pHT->array[n].state!=EMPTY) //循环每个状态不为空的值。
{
if(pHT->array[n].key==key && pHT->array[n].state==EXIST) //如果值相等并且状态为存在,证明找到了。
{
return count;
}
n=(n+1)%(pHT->capacity); //否则向后走一位,次数加1,继续循环。
count++;
}
return -1; //退出循环表示没找到。
}
int Insert(HashTable *pHT,Key key);
//扩容。
void ExpandIfRequired(HashTable *pHT)
{
HashTable newHT;
int i;
if(pHT->size*10/pHT->capacity<7) //负载因子。
{
return;
}
HashTableInit(&newHT,pHT->capacity*2,pHT->hashfunc); //初始化新的空间。
for(i=0;i<pHT->capacity;i++)
{
if(pHT->array[i].state==EXIST)
{
Insert(&newHT,pHT->array[i].key); //将原数组里的复制过来。
}
}
free(pHT->array); //释放旧空间。
pHT->array=newHT.array;
pHT->capacity=newHT.capacity;
}
//哈希表的插入。
int Insert(HashTable *pHT,Key key)
{
int count=1;
int n=pHT->hashfunc(key,pHT->capacity); //确定这个值应该在的下标。
ExpandIfRequired(pHT); //进行扩容,保证能插入进去。
assert(pHT);
while(pHT->array[n].state==EXIST){ //循环状态为存在的值。
if(pHT->array[n].key==key) //若值存在则插入失败。
{
return -1;
}
n=(n+1) % (pHT->capacity); //否则向后移位。
count++;
}
pHT->array[n].key=key; //此时直接插入即可。
pHT->array[n].state=EXIST;
pHT->size++; //记得要给size++。
return 0;
}
//删除
int Remove(HashTable *pHT,Key key)
{
int n=pHT->hashfunc(key,pHT->capacity); //确定位置。
while(pHT->array[n].state!=EMPTY)
{
if(pHT->array[n].key==key && pHT->array[n].state==EXIST) //若相等并状态为存在。
{
pHT->array[n].state=DELETED; //将它置成假删,size--.
pHT->size--;
return 0;
}
n=(n+1)% (pHT->capacity); //往后移。
}
return -1;
}
//销毁。
void HashTableDestroy(HashTable *pHT)
{
free(pHT->array);
}
//打印
void Print(HashTable *pHT)
{
int i=0;
for(i=0;i<pHT->capacity;i++)
{
if(pHT->array[i].state==EXIST){
printf("%d ",pHT->array[i].key);
}
}
printf("\n");
}
void test()
{
HashTable ht;
HashTableInit(&ht, 13, hashfunc);
Insert(&ht, 3);
Insert(&ht, 7);
Print(&ht);
Insert(&ht, 19);
Insert(&ht, 25);
Insert(&ht, 26);
Print(&ht);
Insert(&ht, 6);
Insert(&ht, 12);
Print(&ht);
Insert(&ht, 39);
Insert(&ht, 41);
Insert(&ht, 32);
Insert(&ht, 45);
Print(&ht);
Insert(&ht, 2);
Insert(&ht, 1);
Print(&ht);
Insert(&ht, 38);
Insert(&ht, 49);
Print(&ht);
printf("等待\n");
}
开散列:
//开散列。
#pragma once
#include<stdio.h>
#include<assert.h>
#include<string.h>
#include<Windows.h>
typedef int Key;
typedef struct ListNode{ //链表结构
Key key;
struct ListNode *pNext;
}ListNode;
typedef struct Element{ //数组元素结构。
ListNode *pFirst;
}Element;
typedef int(*Hashfunc)(Key,int); //哈希函数
typedef struct HashBuck{ //哈希桶结构。
int size;
int capacity;
Element *array;
Hashfunc hashfunc;
}HashBuck;
int hashfunc(Key key,int capacity) //除留余数。
{
return (key % capacity);
}
void HBInit(HashBuck *pHB,int capacity,Hashfunc hashfunc) //初始化。
{
pHB->array=(Element *)malloc(sizeof(Element)*capacity); //开辟空间。
assert(pHB->array);
pHB->size=0;
pHB->capacity=capacity;
pHB->hashfunc=hashfunc;
memset(pHB->array,0x0,sizeof(Element)*capacity); //清空数组。
}
int find(HashBuck *pHB,Key key) //查找。
{
int n=pHB->hashfunc(key,pHB->capacity); //求该值应该在的位置下标。
ListNode *p=pHB->array[n].pFirst; //取出头结点。
ListNode *q;
for(q=p;q!=NULL;q=q->pNext) //循环寻找。
{
if(q->key==key)
{
return 1;
}
}
return 0;
}
void Expend(HashBuck *pHB) //扩容
{
int i;
ListNode *p;
ListNode *q;
int Newcapacity=pHB->capacity*2; //将容量扩大两倍。
HashBuck NewHB; //定义新的哈希桶。
if(pHB->size<pHB->capacity)
{ //如果没超容量则退出。
return;
}
HBInit(&NewHB,Newcapacity,pHB->hashfunc); //初始化新哈希桶。
for(i=0;i<pHB->capacity;i++)
{
p=pHB->array[i].pFirst;
q=p;
for (q=p; q!=NULL; q= q->pNext) { //将原元素复制到新哈希桶里。
// 真正要插入的
Insert(&NewHB, q->key);
}
}
pHB->array = NewHB.array;
pHB->capacity = Newcapacity;
}
void ListInsert(ListNode **pFirst,Key key) //头插入。
{
ListNode *pNew = (ListNode *)malloc(sizeof(ListNode));
assert(pNew);
pNew->key = key;
pNew->pNext = (*pFirst);
*pFirst = pNew;
}
int Insert(HashBuck *pHB,Key key) //插入。
{
int n=pHB->hashfunc(key,pHB->capacity);
ListNode *p=pHB->array[n].pFirst;
ListNode *pNode;
Expend(pHB);
for(pNode=p;pNode!=NULL;pNode=pNode->pNext) //寻找若存在退出。
{
if(pNode->key==key)
{
return -1;
}
}
ListInsert(&(pHB->array[n].pFirst), key); //否则进行头插。
pHB->size++;
return 0;
}
int Remove(HashBuck *pHB,Key key) //删除。
{
int n=pHB->hashfunc(key,pHB->capacity);
ListNode *p=pHB->array[n].pFirst;
ListNode *q,*m;
for(q=p;q!=NULL;q=q->pNext)
{
if(q->key==key) //当找到要删除的值时。
{
pHB->size--;
if(q=p) //若为头结点,直接头删。
{
pHB->array[n].pFirst=q->pNext;
free(p);
return 1;
}
m->pNext=q->pNext; //否则普通删除。
free(q);
return 1;
}
m=q;
}
return 0;
}
void test3()
{
HashBuck p;
HBInit(&p,10,hashfunc);
Insert(&p,1);
Insert(&p,3);
Insert(&p,5);
printf("%d\n ",find(&p,5));
printf("%d\n",find(&p,4));
Remove(&p,3);
printf("%d\n ",find(&p,3));
printf("\n");
}
以上就是有关哈希的开闭散列。