哈希结构

/*
    哈希结构:数据和地址的一种映射关系
    映射关系:数学中的函数关系
    哈希地址:不是指真正意义上的地址(指针),抽象的参照地址。
    举例:数组数组下标就可以充当哈希地址
       第一种:直接定址法
       int   arrayHash[10];   //哈希的内存
       y=x       //构造函数,数据就是直接的地址
       arrayHash[1]=1;  //数字 1 直接存放到 arrayHash[1] 里面
       arrayHash[2]=2;  // 2 就存放到arrayHash[2]里面

       第二种:用得比较多的哈希构造函数是 取余法
       例:
       y = x%p;
       //假设有一堆数据:1       4         19       11         23    存放到哈希结构里去
            y = x%10;   
            //这样子,它只有九个地址,为0-9   
            //构造函数,能确定他能产生几个地址,1取10的余还是 1
       int   arrayHash[10];
             arrayHash[1%10] = 1;
             arrayHash[2%10] = 2;
             arrayHash[4%10] = 4;
             arrayHash[19%10] = 19;
             //哈希冲突:在哈希地址中已经存在了元素
                       arrayHash[11%10] = 11
             //哈希冲突解决方案: 
                  《1》.开放地址法:
                   11%10本为1,但 1 已存在,所以arrayHash[11%10]将会储存在其他空余的内存当中,开放地址法一般情况上,哈希地址个数是大于元素个数
                  《2》.数组链表的方式:
                  当产生冲突的时候,它会以发生冲突的元素(arrayHash[1%10]与arrayHash[11%10]发生冲突)为表头创建一个链表(数据结构的图也是这种方式)
             有时数据不满足数据结构需求时,需要自己构造函数
          以字符为例,数据是字符串
*/

#include<stdio.h>
#include<stdlib.h>

//数组哈希
struct   pair
{
      int    first;              //构造一个关键字,为构建哈希地址做准备
      char   second[];   //数据
};

//哈希表特征
struct     hashTable
{
      /*用二级指针,方便判断初始化没有元素的情况。
      因为用一级指针的话,如果我们为数组赋一个初值,如果我们赋的是0,一般是没有办法和初值区分,因为有可能元素也是0,但指针没有元素,可以用空NULL表示,所以用二级指针可以为每一个一级指针置空*/
      struct    pair **table;
      int   sizeHash;        //记录当前哈希数组的哈希地址个数
      int     divisor;          //y=x%divisor
};

struct     hashTable* createHash(int   divisor)
{
       struct    hashTable* hash = (struct     hashTable*)malloc(sizeof(struct    hashTable));
       hash->sizeHash = 0;
       hash->divisor = divisor;
       hash->table = (struct     pair**)malloc(sizeof(struct   pair)*hash->divisor);
       /*(struct    pair)*hash->divisor是存放除数,是(struct     pair)乘以hash->divisor,然后hash->table就有这么大的内存,所以产生了多个hashi->divisor一级指针*/
       /*都是一级指针,方便初始化*/
       /*二维数组申请了内存,存一级指针,一级指针等于NULL,一级指针变一维数组*/
       for(int    i = 0; i< divisor ; i++)
       {
                 hash->table[i] = NULL;
        }
        return    hash;
}


/*插入,要找到正确的地址,才能正确的插入,通过关键字first去查找*/
int   search(struct   hashTabkle* hash,int   first)
{
       /*本来的地址(即哈希下标)可以通过构造函数求出来*/
       /*找一个可以使用的地址,直接返回*/
       int     pos=first%(hash->divisor);/*但是他不一定是我们要的地址(哈希冲突),所以要判断一下,当前地址是空的才能使用*/
       int    curPos = pos;
       do
       {
           /*判断如果哈希表里面没有元素,或者当前哈希地址正好等于first,意味着当前位置是可以使用的,这时候直接返回当前下标*/
           /*找一个可以使用的地址,直接返回*/
           if(hash->table[curPos] == NULL||hash->table[curPos]->first == first)
           /*这里的first是修改hash->table[curPos]中的second[]*/
           {
               return  curPos; 
           }
           /*(curpos+1)是每次挪动一位去求哈希地址,否则下标不会变动*/
           curPos = (curPos + 1)%(hash->divisor);
       }while(curPos!=pos);/*判断当前下标不等于原来下标,如果是就等于没有位置了*/
       /*curPos会一直往下走,但是它会走一个循环,循环到有元素的时候就会停下来,例   11->19->20->21  停止*/
       return  curPos;      
}


//插入
void    insertHash(struct    hashTable* hash, struct    pair   data)
{ 
	int  pos = search(hash,data,.first);
	if(hash->table[pos] == NULL)
	{
	     /*为table[]一级指针分配内存*/
	     hash->table[pos] =  (struct   pair*)malloc(sizeof(struct  pair));
	     /*因为是结构体类型,数据不能直接拷贝,所以要用memcpy内存拷贝的方式*/
	     memcpy(hash->table[pos],&data,sizeof(struct  pair));
	     hash->sizeHash++;
	} 
	/*另一种情况表示哈希冲突*/
	else
	{
	     if(hash->table[pos]->first == data.first)
	     {
	           /*把原来的值复制成新的值*/
	           strcpy(hash->table[pos]->second, data.second);  
	     }
	     else
	     {
	          printf("表满了,无法插入\n");
	          return; 
	     }
	}
}


void   printList(struct   hashTable* hash)
{
     fof(int   i = 0 ; i < hash->divisor ; i++)
     {
          if(hash->table[i]==NULL)
          {
               printf("NULL"); 
          } 
          else
          (
                printf("%d  %s\n",hash->table[i]->first,hash->table[i]->second); 
          )
     }
}


int   main()
{
       struct    hashTable* hash = createHash(10);
       struct  pair   array[5] = {1,"k",2,"a",3,"b"};
       for(int   i=0;i<5;i++)
       { 
            insertHash(hash,array[i]);
	   }
	   printList(hash);

      system("pause");
      return   0;
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
首先,我们需要确定一下初始状态。因为哈希函数为h(x)=x mod 8,所以我们可以创建一个大小为8的bucket数组。同时,我们需要给每个bucket一个深度,初始状态下每个bucket的深度都为1。 接下来,我们将所有记录按照哈希函数的值分配到bucket中。因为一个bucket可以容纳3条记录,所以当一个bucket已经满了之后,我们需要将它拆分成两个深度为2的bucket。如果拆分之后,相应的记录依然无法放入新的bucket中,我们需要继续拆分,直到所有记录都能被放入为止。 下面是具体的过程: 1. 初始状态 | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | |---|---|---|---|---|---|---|---| | | | | | | | | | 2. 加入记录24,29,2 | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | |---|---|---|---|---|---|---|---| | 2 | | 24| 29| | | | | 3. 加入记录17,5,19 | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | |---|---|---|---|---|---|---|---| | 2 | | 24| 29| 5 | 17| 19| | 4. 加入记录3,18,7 | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | |---|---|---|---|---|---|---|---| | 2 | 3 | 24| 29| 5 | 17| 19| 7 | 5. 加入记录11,37,15 | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | |---|---|---|---|---|---|---|---| | 2 | 3 | 24| 29| 5 | 17| 19| 7 | | 11| 37| 15| | | | | | 6. 加入记录23,31 | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | |---|---|---|---|---|---|---|---| | 2 | 3 | 24| 29| 5 | 17| 19| 7 | | 11| 37| 15|23 |31 | | | | 最终的可扩展哈希结构如上所示。在这个结构中,每个bucket的深度都为2,因为我们进行了一次拆分。如果在未来的操作中,需要再次拆分,我们可以将深度增加1,同时重新分配所有记录。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值