增加桶式的动态哈希

哈希值的获取字符串的二进制,再二进制转换为一组数字,这组数字就是用来确定key在哪个桶层中的

代码中  #define tongsize 8 //桶大小是2的n次方,,,,,这里的n=3(2的3次方等于8),那么会把3个二进制转换为一个数字

/*
当重新分配还是分配到一个桶层时候,会出现哈希key不够用,就会出现引用了无效内存的bug,所以使用more_ceng
arr[j]=strtol( bi, NULL, 2);//把二进制字符串bi转换为十进制

测试数据
set 电风 111
set 风
set 赋给 22
set 4风 33
set 4 44
set 5 55
set a 66
set c 77
set x 88
set ww 放了
set qq 撒解放了
set e 解放了
set yy 旦解放了
set ii 撒

get 电风
get 风
get 4风
get 4
get 5
get a
get c
get x
get ww
get qq
get e
get yy
get ii

*/
#include<conio.h>
#include<math.h>
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#define tongsize 8    //桶大小是2的n次方
#define VALUESIZE 3  //值链表的长度

//---------------------------------------------------------------------------//
typedef struct value *value_pointer;  //值的结构体
typedef struct value
{
	char key[10];
    char zhi[20];
    value_pointer link;
}value;  

typedef struct zitong *zitong_pointer;//桶的结构体
typedef struct zitong
{
       int biao_tong;  /*0 is 指向值 , 非0 则是指向一个子桶*/
       int geshu;//值的个数

       value_pointer value_link;
       zitong_pointer zitong_link;
}zitong; 

zitong tong[tongsize];
int ceng=1;//层次深度,分配桶的时候,可能ceng加+1

//---------------------------------------------------------------------------//
zitong_pointer init_tong(int biaoceng);//分配和初始化桶,可以改为内存直接付0
value_pointer init_value();//分配值的空间

int binarystring(char c,char*bite,int j,int bite_len);//返回二进制
int* bitetoarr(char* bite,int bishu,int more_ceng) ;//比特转换为数字
int* hash_key(char *key);//返回哈希key,key转为比特,比特再转为数字数组

void ret_fenpei(value_pointer a,zitong_pointer b,int now_ceng);//a值,b是桶,c是层次
value_pointer set_find(zitong_pointer root_arr,int pre_biao_tong, int*hk,int now_ceng);//hk是key的哈希值
void set(zitong_pointer root_arr,int pre_biao_tong);

value_pointer get_find(zitong_pointer root_arr, int*hk,int now_ceng,char* key);//hk是key的哈希值
void getvalue(zitong_pointer root_arr);

//---------------------------------------------------------------------------//

void main()
{
    zitong root;//根小桶
    root.biao_tong=1;//表示指向的子桶
    root.zitong_link = init_tong(root.biao_tong);
      printf("请输入  set如set key value.   get如get key;quit退出\n");

	char caozuo[10];
	int sel;
     do{
         scanf("%s",&caozuo);
         if (strcmp(caozuo,"set")==0)
            sel=1;
         else if (strcmp(caozuo,"get")==0)
            sel=2;
        else if (strcmp(caozuo,"look")==0)
            sel=3;
        else if (strcmp(caozuo,"quit")==0)
            sel=0;
        else sel=-1;

         switch(sel)
        {
          case 0:printf("\t\t\t^-^再见!^-^ \t\t\t\n");system("pause");break;
          case 1:     set(root.zitong_link,root.biao_tong);break;
          case 2:getvalue(root.zitong_link);printf("\n\n");break;
          //case 3:look();printf("\n");break;
          default: printf("请输入正确的选项号!");printf("\n\n");break;
        }
    }while(sel!=0);
}

zitong_pointer init_tong(int biaoceng) //分配和初始化桶,可以改为内存直接付0
{
   zitong_pointer t;
   t=(zitong_pointer)malloc(sizeof(zitong)*tongsize);
       int i;
       for(i=0;i<tongsize;i++) {
              t[i].biao_tong=0;
              t[i].geshu=0;
              t[i].value_link=NULL;
              t[i].zitong_link=NULL;
            }

  if (biaoceng > ceng)//当这个桶的深度大于当前最大深度时,ceng才+1
 	  ceng++;//

   return t;
}
value_pointer init_value()//分配值的空间
{
	value_pointer v;
	v=(value_pointer)malloc(sizeof(value));
	v->link=NULL;
	return v;
}

int binarystring(char c,char*bite,int j,int bite_len)//获取一个字符的二进制
{
  int i;
  for(i=0;i<8;i++)
  {
  	if(j*8+i >=bite_len)return 1;//二进制足够了

  	if (c & 0x80)
  	 bite[j*8+i]='1';
    else
    	bite[j*8+i]='0'; 

    c <<= 1;
  }
  return 0;
}

int* hash_key(char *key)//返回哈希key,key转为比特,比特再转为数字数组
{
  //字符串key的长度乘以8就得到比特长度

  int more_ceng=ceng+3;//加多越多越安全
  int len =strlen(key);//字符串长度
  int bishu=(int)(log10(tongsize)/log10(2)) ;//使用bishu个比特来确定一个数字
  int bite_len=bishu*more_ceng;//刚开始是3*1=3

  char *bite=(char*)malloc(bite_len);//申请存放01110011的字符串

  for (int i = 0; i < len; ++i)//把字符转换为比特
  		if(binarystring(key[i],bite,i,bite_len) == 1)break;

  	int bite_len_now=strlen(bite);//0011010字符串的长度
	  while(1)//使得二进制足够长
	  {
	  	int k=0;
	  	if (bite_len_now < bite_len){
	  		bite[bite_len_now+k]=bite[k];
	  		++k;
	  	}
	  	else
	  		break;
	  }

  int* arr= bitetoarr(bite,bishu,more_ceng);//比特转换为数字
  free(bite);
  return arr;

}
int* bitetoarr(char* bite,int bishu,int more_ceng) //比特转换为数字
{
  int *arr;
  char bi[10]={0};
  arr=(int *)malloc(sizeof(int)*more_ceng);//刚开始是1
  for (int j = 0; j < more_ceng; ++j)
  {
  	bi[0]=bite[j*bishu+0];//bite数组的中10010110
  	bi[1]=bite[j*bishu+1];
  	bi[2]=bite[j*bishu+2];

  	arr[j]=strtol( bi, NULL, 2);
  }
 return arr;
}

void ret_fenpei(value_pointer a,zitong_pointer b,int now_ceng)//a值,b是桶,c是层次
{
   int* fen_hk=hash_key(a->key);
   a->link=b[ fen_hk[now_ceng] ].value_link;//连接后面的
   b[ fen_hk[now_ceng] ].value_link=a;//连接到头部
   b[ fen_hk[now_ceng] ].geshu++;//个数加+1
   free(fen_hk);
}

value_pointer set_find(zitong_pointer root_arr,int pre_biao_tong, int*hk,int now_ceng)//hk是key的哈希值
{
	//key是否存在
  //在哪个子桶
  //得先判断key是否存在了 分1对应的子桶无值  2.扫描链表
  //不存在   分1添加到链表的头部  2.值满了,申请新的桶再分配
  if (now_ceng>=ceng)
     printf("error now_ceng is over");
  zitong_pointer here=&root_arr[ hk[now_ceng] ];//达到桶的层次节点

  int biaoji;//桶的标记,子桶或是值,非0表示桶的层次
  biaoji=here->biao_tong;
  value_pointer vp;

    if (0==biaoji)//子桶指向链表值
    {
	   if(VALUESIZE > here->geshu)//子桶无值或者子桶有值,并且小于链的长度
	      {
	      	value_pointer vp=init_value();//申请空间
	      	vp->link=here->value_link;//连接后面的
	      	here->value_link=vp;//连接到头部啊

	        here->geshu++;//值的个数加+1
	        return vp;
	      }
	      else//子桶的值达到VALUESIZE
	      {
	      		value_pointer temp2;
	      		value_pointer temp=here->value_link;//把链表拿出来
	      		here->biao_tong=pre_biao_tong+1;//子桶标记

	      		here->zitong_link=init_tong(here->biao_tong);//========分配新的子桶
	      		while(temp != NULL)//循环递归重新在新子桶上分配
	      		{
	      			temp2=temp->link;
	      			ret_fenpei(temp,here->zitong_link,now_ceng+1);//递归重新分配
	      			temp=temp2;
	      		}
	      		vp=set_find(here->zitong_link,here->biao_tong,hk,now_ceng+1);//就在新的子桶中寻找了,由hk[now_ceng+1]子哈希确定新子桶的桶层次
	      		return vp;
	      }
    }
  else//说明子桶指向子桶,//进入子桶中寻找了,由hk[now_ceng+1]子哈希确定子桶的桶层次
    {
		vp=set_find(here->zitong_link,here->biao_tong,hk,now_ceng+1);
		return vp;
    }

}

value_pointer get_find(zitong_pointer root_arr, int*hk,int now_ceng,char* key)//hk是key的哈希值
{
  //在哪个子桶层
  //得先判断key是否存在了 分1对应的子桶无值  2.扫描链表
  //不存在   分1添加到链表的头部  2.值满了,申请新的桶再分配
  if (now_ceng>=ceng)
     printf("error now_ceng is over");
  zitong_pointer here=&root_arr[ hk[now_ceng] ];//达到桶的层次节点

  int biaoji;//桶的标记,子桶或是值,非0表示桶的层次
  biaoji=here->biao_tong;
  value_pointer vp;

  vp=here->value_link;
    if (0==biaoji)//子桶指向链表值
    {
	   while(vp != NULL)
	   {
	   	 if (0 == strcmp(vp->key,key) )
	   		return vp;
	     vp=vp->link;
	   }
	   return NULL;
    }
  else//说明子桶指向子桶,
    {
		vp=get_find(here->zitong_link,hk,now_ceng+1,key);//进入子桶中寻找了,由hk[now_ceng+1]子哈希确定子桶的桶层次
		return vp;
    }

}

void set(zitong_pointer root_arr,int pre_biao_tong)
{
  char key[10],zhi[20];
  int* hk;
  value_pointer p;

  scanf("%s %s",&key,&zhi);
   hk=hash_key(key);

   p=get_find(root_arr,hk,0,key);//是否已经存在相同的key了

	if (p ==NULL)//说明不存在节点
	  p=set_find(root_arr,pre_biao_tong,hk,0);//发现点

  strcpy(p->key,key);
  strcpy(p->zhi,zhi);
  free(hk);
}

void getvalue(zitong_pointer root_arr)
{
  char key[10];
    int* hk;
  value_pointer p;
  scanf("%s",&key);

   hk=hash_key(key);
   p=get_find(root_arr,hk,0,key);//发现点

	if (p==NULL)
		 printf("no key to value");
	else
		printf("%s",p->zhi);
free(hk);
}
时间: 2024-10-19 13:19:02

增加桶式的动态哈希的相关文章

NGINX 加载动态模块(NGINX 1.9.11开始增加加载动态模块支持)

NGINX 1.9.11开始增加加载动态模块支持,从此不再需要替换nginx文件即可增加第三方扩展.目前官方只有几个模块支持动态加载,第三方模块需要升级支持才可编译成模块. [email protected]:~/nginx-1.12.0$ ./configure --help | grep dynamic --with-http_xslt_module=dynamic enable dynamic ngx_http_xslt_module --with-http_image_filter_mo

动态哈希

动态hash方法之一 本文将介绍三种动态hash方法. 散列是一个非常有用的.非常基础的数据结构,在数据的查找方面尤其重要,应用的非常广泛.然而,任何事物都有两面性,散列也存在缺点,即数据的局部集中性会使散列的性能急剧下降,且越集中,性能越低. 数据集中,即搜索键在通过hash函数运算后,得到同一个结果,指向同一个桶,这时便产生了数据冲突. 通常解决数据冲突的方法有:拉链法(open hashing)和开地址法(open addressing).拉链法我们用的非常多,即存在冲突时,简单的将元素链

ZooKeeper动态增加Server(动态增加节点)的研究(待实践)

说明:是动态增加Server,不是动态增加连接到ZK Server的Client. 场景如下(转自外文): 1.在t=t_1->[peer-1(Leader),peer-2],peer-1是主节点,所有客户端连接到该节点. 2.在t=t_2->[peer-1(Leader),peer-2,peer-3],稍后的时候,同行3加入了该组.是否可以“动态地”将动态列表添加到zookeeper服务器列表(即,在对等体1上不重新启动ZooKeeper)? 3.在t=t_3->[peer-3(Lea

哈希函数和哈希表综述 (转)

哈希表及哈希函数研究综述 摘要 随着信息化水平的不断提高,数据已经取代计算成为了信息计算的中心,对存储的需求不断提高信息量呈现爆炸式增长趋势,存储已经成为急需提高的瓶颈.哈希表作为海量信息存储的有效方式,本文详细介绍了哈希表的设计.冲突解决方案以及动态哈希表.另外针对哈希函数在相似性匹配.图片检索.分布式缓存和密码学等领域的应用做了简短得介绍 哈希经过这么多年的发展,出现了大量高性能的哈希函数和哈希表.本文通过介绍各种不同的哈希函数的设计原理以及不同的哈希表实现,旨在帮助读者在实际应用中,根据问

【数据结构】哈希表的线性探测算法

构造哈希表常用的方法是: 除留余数法--取关键值被某个不大于散列表长m的数p除后的所得的余数为散列地址.HashKey= Key % P. 直接定址法--取关键字的某个线性函数为散列地址HashKey= Key 或 HashKey= A*Key + BA.B为常数. 我在这里主要使用一下除留余数法Hash(key) =Key%P,(P这里是哈希表的长度)p最好是素数考虑降低哈希冲突的原因,我并没有在这上面过于追究此处哈希表长度10,见线性探测图. 哈希表经常遇到的一个问题就是哈希冲突. 哈希冲突

OSGI(面向Java的动态模型系统)

基本简介编辑 OSGI服务平台提供在多种网络设备上无需重启的动态改变构造的功能.为了最小化耦合度和促使这些耦合度可管理,OSGi技术提供一种面向服务的架构,它能使这些组件动态地发现对方.OSGi联 OSGI 盟已经开发了为例如象HTTP服务器.配置.日志.安全.用户管理.XML等很多公共功能标准组件接口.这些组件的兼容性插件实现可以从进行了不同优化和使用代价的不同计算机服务提供商得到.然而,服务接口能够基于专有权基础上开发. 因为OSGi技术为集成提供了预建立和预测试的组件子系统,所以OSGi技

Java动态代理机制详解(JDK 和CGLIB,Javassist,ASM)

作者:亦山 推荐:hh375的图书馆 class文件简介及加载 Java编译器编译好Java文件之后,产生.class 文件在磁盘中.这种class文件是二进制文件,内容是只有JVM虚拟机能够识别的机器码.JVM虚拟机读取字节码文件,取出二进制数据,加载到内存中,解析.class 文件内的信息,生成对应的 Class对象: class字节码文件是根据JVM虚拟机规范中规定的字节码组织规则生成的.具体class文件是怎样组织类信息的,可以参考 此博文:深入理解Java Class文件格式系列.或者

Java 动态代理机制详解(JDK 和CGLIB,Javassist,ASM)

class文件简介及加载 Java编译器编译好Java文件之后,产生.class 文件在磁盘中.这种class文件是二进制文件,内容是只有JVM虚拟机能够识别的机器码.JVM虚拟机读取字节码文件,取出二进制数据,加载到内存中,解析.class 文件内的信息,生成对应的 Class对象: class字节码文件是根据JVM虚拟机规范中规定的字节码组织规则生成的.具体class文件是怎样组织类信息的,可以参考 此博文:深入理解Java Class文件格式系列.或者是Java虚拟机规范. 下面通过一段代

用spring aop实现动态代理的例子

下面由我来给大家展示用spring aop实现动态代理的例子(电脑打印) 下面就看一下具体的代码: 先定义一个打印机的接口 1 package aop007_ComPrint; 2 3 public interface Print { 4 5 public void ColorPrint(); //彩色打印 6 public void WhitePrint(); //黑白打印 7 } 然后定义两个实现类,分别实现彩色打印和黑白打印 1 package aop007_ComPrint; 2 3 p