hash之开放定址法解决冲突



(一)步骤:

(0)构造一个HashTable数据结构;

1.定义一个hashTable的大小数组,里面存储的每个元素为素数,

包含一个元素指针,当前数组大小count,size_index(hashTable的大小索引,通过查表可以得到相应的hash表的大小)


(1)初始化hashTable,初始化count=0,根据size_index查表,开辟一个相应大小的数组,然后数组的每个元素 的值为空;

(2)定义一个hash函数:输入为key,输出为hash(key)即地址;

(3)解决冲突的 方法:

开放定址法:void collision(int *p, int d);

根据Hi=(H(key)+d)%M;M已知,输入为H(k),以及偏移量d,输出为新的H,这里相当于更新P;


(4) hashSearch,  如int hashSearch(HashTable H, KeyType key , int *p , int d){

//在hash表H中,查找关键字key,如果找到,则返回1,否则0,如果找到p为key的hash地址,

//如果没有找到,根据p,d解决冲突的方法,可以得到p待插入的地址;

p=hash(key);

       while (如果p处的值非空 &&  p处的值不等于 key ){

        根据再散列 collision(p,d)得到新的p;

       更新d;

         }

   if(p处的值==key) 则返回1;

  else 返回0;

}


(5)  hashInsert(HashTable H ,KeyType key){

      先调用hashSearch(),看看是否可以查找到key;

     如果查不到,则插入;

}


----------------------


/*hash表之开放定址法处理冲突:*/
方法一:
/*
根据提示输入学生信息,然后输入查找学生的学号,如果有的话,输出学生姓名和位置,如果没有的话,提示没有该学生的信息。
*/
#import <Foundation/Foundation.h>
#define MAX 20

typedef struct
{
    int num;
    char name[20];
} ElemType;   //定义查找的节点元素


typedef struct
{
    ElemType *elem;
    int count;
    int sizeindex;
} HashTable;   //定义哈希表

/*
HashTable中elem数组的下标就是hash地址。
elem数组元素的值就是关键字。
*/

int hash(int num)  //定义哈希函数
{
    int p;
    p = num % 5;
    return p;
}

void InitHash(HashTable *H)
{
    int i;
    H -> elem = (ElemType *)malloc(MAX * sizeof(ElemType));
    H -> count = 0;
    H -> sizeindex = MAX;
    for (int i = 0; i < MAX; i++) {
        H -> elem[i].num = 0;           //初始化
    }
}


/*从hashTable H中查找 关键字 key, 如果找到,则返回1,没有找到则返回0.

p为key的hash值,如果p已经被其他关键字占用,则根据解决冲突的方法,重新设置p;

最终p为存放key的地址;

 */

int hashSearch(HashTable H, int key, int *p)
{
    int c = 0;
    *p = hash(key);
    while (H.elem[*p].num!=key && H.elem[*p].num!=0) { // p位置  被其他的不等于key的关键字占用

 //通过二次探测再散列解决冲突
        c = c + 1;
        if (c%2 == 1) {
            *p = *p + (c+1)*(c+1)/4;
        }
        else
        {
            *p = *p - (c*c)/4;
        }
    }
    if (H.elem[*p].num == key) {
        return 1;
    }
    else
    {
        return 0;
    }
}

void insertHash(HashTable *H, ElemType e) //如果查找不到就插入元素
{
    int p;
    hashSearch(*H, e.num, &p);
    H -> elem[p] = e;
    ++H -> count;
}

int main(int argc, const char * argv[])
{

    @autoreleasepool {
       
        HashTable H;
        int p, key;
        ElemType e;
        InitHash(&H);
        for (int i = 0; i < 3; i++)
        {
            loop:printf("请输入第%d个学生的学号\n", i+1);
            scanf("%d", &e.num);
           
            if (!hashSearch(H, e.num, &p)) {
                printf("输入第%d个学生名字\n", i+1);
                scanf("%s", e.name);
                insertHash(&H, e);
            }
            else
            {
                printf("该学号已经存在");
                goto loop;
            }
           
        }
       
        printf("请输入您要查找的学生学号:\n");
        scanf("%d", &key);
        if (hashSearch(H, key, &p)) {
            printf("查找成功!学生的姓名是%s\n",H.elem[p].name);
            printf("学生所在表中的位置是%d\n", p);
        }
        else
        {
            printf("您要查找的学生不存在!\n");
        }
       
    }
    return 0;
}


----------------------------------
方法二:
/*
*哈希表
*/
#include<stdio.h>
#include<stdlib.h>

#define NULLKEY 0//0为无记录标志
#define N 10//数据元素个数

typedef int KeyType;//设关键字域为整型
typedef struct
{
 KeyType key;
 int ord;
}ElemType;//数据元素类型

#define EQ(a,b) ((a)==(b))

int hashsize[]={11,19,29,37};//哈希表容量递增表 一个合适的素数序列
int m=0;//哈希表表长 全局变量

typedef struct
{
 ElemType *elem;//数据元素存储基址 动态分配数组
 int count;//当前数据元素个数
 int size_index;//hashsize[size_index]为当前容量
}HashTable;


#define SUCCESS 1
#define UNSUCCESS 0
#define DUPLICATE -1

/* 操作结果: 构造一个空的哈希表 */
int initHashTable(HashTable *H)
{
 int i;

 (*H).count=0;//当前元素个数为0
 (*H).size_index=0;//初始存储容量为hashsize[0]
 m=hashsize[0];
 (*H).elem=(ElemType *)malloc(m*sizeof(ElemType));
 if(!(*H).elem)
  exit(0);//存储分配失败
 for(i=0;i<m;i++)
  (*H).elem[i].key=NULLKEY;//未填记录的标记

 return 1;
}

/* 初始条件:哈希表H存在*/
/* 操作结果:销毁哈希表H*/
void destroyHashTable(HashTable *H)
{
 free((*H).elem);
 (*H).elem=NULL;
 (*H).count=0;
 (*H).size_index=0;
}

/* 一个简单的哈希函数(m为表长 全局变量)*/
unsigned Hash(KeyType K)
{
 return K%m;
}

/*线性探测再散列*/
void collision(int *p,int d)
{
 *p=(*p+d)%m;//开放定址法处理冲突
}

/* 在开放定址哈希表H中查找关键码为K的元素,若查找成功,以p指示待查数据 */
/* 元素在表中位置,并返回SUCCESS;否则,以p指示插入位置,并返回UNSUCCESS */
/* c用以计冲突次数,其初值置零,供建表插入时参考 */
int searchHash(HashTable H,KeyType K,int *p,int *c)
{
 *p=Hash(K);//求得哈希地址
 while(H.elem[*p].key!=NULLKEY&&!EQ(K,H.elem[*p].key))//该位置中填有记录 并且关键字不相等
 {
  (*c)++;
  if(*c<m)
   collision(p,*c);//求得下一探查地址p
  else
   break;
 }
 if EQ(K,H.elem[*p].key)
  return SUCCESS;//查找成功 p返回待查数据元素位置
 else
  return UNSUCCESS;//查找不成功(H.elem[p].key==NULLKEY p返回的是插入的位置)
}

int insertHash(HashTable *,ElemType);//对函数的声明

void recreateHashTable(HashTable *H)//重建哈希表
{
 int i,count=(*H).count;

 ElemType *p,*elem=(ElemType *)malloc(count*sizeof(ElemType));

 p=elem;

 printf("重建哈希表\n");
 for(i=0;i<m;i++)//保存原有的数据到elem中
  if(((*H).elem+i)->key!=NULLKEY)//该单元有数据
   *p++=*((*H).elem+i);
 (*H).count=0;
 (*H).size_index++;//增大存储容量
 m=hashsize[(*H).size_index];
 p=(ElemType *)realloc((*H).elem,m*sizeof(ElemType));
 if(!p)
  exit(0);//存储分配失败
 (*H).elem=p;

 for(i=0;i<m;i++)
  (*H).elem[i].key=NULLKEY;//未填记录买的标志(初始化)
 for(p=elem;p<elem+count;p++)//将原有的数据按照新的表长插入到重建的哈希表中
  insertHash(H,*p);
}

/* 查找不成功时插入数据元素e到开放定址哈希表H中,并返回1 */
/* 若冲突次数过大,则重建哈希表 */
int insertHash(HashTable *H,ElemType e)
{
 int c,p;

 c=0;
 if(searchHash(*H,e.key,&p,&c))//表中已有与e有相同关键字的元素
  return DUPLICATE;
 else if(c<hashsize[(*H).size_index]/2)//冲突次数c未达到上线 c的阀值可调
 {
  (*H).elem[p]=e;//插入e
  ++(*H).count;

  return 1;
 }
 else
  recreateHashTable(H);//重建哈希表

 return 0;
}

/* 按哈希地址的顺序遍历哈希表 */
void traverseHash(HashTable H,void(*Vi)(int ,ElemType))
{
 int i;

 printf("哈希地址0~%d\n",m-1);
 for(i=0;i<m;i++)
 {
  if(H.elem[i].key!=NULLKEY)//有数据
   Vi(i,H.elem[i]);
 }
}

/* 在开放定址哈希表H中查找关键码为K的元素,若查找成功,以p指示待查数据 */
/* 元素在表中位置,并返回SUCCESS;否则,返回UNSUCCESS */
int find(HashTable H,KeyType K,int *p)
{
 int c=0;

 *p=Hash(K);//求得哈希地址
 while(H.elem[*p].key!=NULLKEY&&!EQ(K,H.elem[*p].key))//该位置中填有记录.并且关键字不相等
  {
  c++;
  if(c<m)
    collision(p,c); //求得下一探查地址p
  else
    return UNSUCCESS; // 查找不成功(H.elem[p].key==NULLKEY)
  }
  if EQ(K,H.elem[*p].key)
  return SUCCESS; //查找成功,p返回待查数据元素位置
  else
  return UNSUCCESS; // 查找不成功(H.elem[p].key==NULLKEY)

}

void printHash(int p,ElemType r)
{
 printf("address=%d (%d %d)\n",p,r.key,r.ord);
}
int main()
{
  ElemType r[N]={{17,1},{60,2},{29,3},{38,4},{1,5},{2,6},{3,7},{4,8},{60,9},{13,10}};
  HashTable h;
  int i,p;
  int j;
  KeyType k;

  initHashTable(&h);
  for(i=0;i<N-1;i++)//插入前N-1个记录
  {
   j=insertHash(&h,r[i]);
   if(j==DUPLICATE)
    printf("表中已有关键字尾%d的记录 无法再插入记录(%d %d)\n",r[i].key,r[i].key,r[i].ord);
  }

  printf("按哈希地址的顺序遍历哈希表\n");
  traverseHash(h,printHash);
  printf("\n\n");

  printf("请输入带查找记录的关键字:");
  scanf("%d",&k);
  j=find(h,k,&p);
  if(j==SUCCESS)
   printHash(p,h.elem[p]);
  else
   printf("没找到\n");
 printf("\n\n");

  j=insertHash(&h,r[i]);//插入第N个记录
  if(j==0)//j==ERROR 重建哈希表
   j=insertHash(&h,r[i]);//重建哈希表后重新插入第N个记录

  printf("按哈希地址的顺序遍历重建后的哈希表\n");
  traverseHash(h,printHash);
  printf("\n\n");

  printf("请输入带查找记录的关键字:");
  scanf("%d",&k);
  j=find(h,k,&p);
  if(j==SUCCESS)
   printHash(p,h.elem[p]);
  else
   printf("没找到\n");
 printf("\n\n");

  destroyHashTable(&h);
  printf("哈希表销毁成功!");
  printf("\n\n");

  return 0;
}

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值