hash冲突Word下载.docx
- 文档编号:19917953
- 上传时间:2023-01-12
- 格式:DOCX
- 页数:24
- 大小:25.80KB
hash冲突Word下载.docx
《hash冲突Word下载.docx》由会员分享,可在线阅读,更多相关《hash冲突Word下载.docx(24页珍藏版)》请在冰豆网上搜索。
}
next_prime(intN)
inti;
if(N%2==
0)
N++;
for(;
;
N+=2){
for(i=3;
i*i<
=N;
i+=2){
if(N%i==0)
gotocont_outer;
returnN;
cont_outer:
;
staticIndex
hash(element_typekey,inttable_size)
returnkey%table_size;
statichash_table
initialize_table(inttable_size)
hash_tableh;
if(table_size<
MIN_TABLE_SIZE)
Error("
Tablesizetoosmall!
"
);
h=malloc(sizeof(structhash_tbl));
if(h==NULL)
Outofspace!
h->
table_size=next_prime(table_size);
cells=malloc(sizeof(cell)*h->
table_size);
if(h->
cells==NULL){
free(h);
for(i=0;
i<
table_size;
i++){
cells[i].info=empty;
entry_cnt=0;
returnh;
staticPos
find(element_typekey,hash_tableh)
Pos
cur_pos;
int
collision_num;
collision_num=0;
cur_pos=hash(key,h->
当hash表大部分被占满,这个过程可能很慢。
也有可能进入死循环!
需要在适当的时候进行rehash!
while(h->
cells[cur_pos].info!
=empty
&
cells[cur_pos].element!
=key){
cur_pos+=2*++collision_num-1;
if(cur_pos>
=h->
table_size)
cur_pos-=h->
returncur_pos;
staticvoid
insert(element_typekey,hash_tableh)
p;
p=find(key,h);
cells[p].info!
=legitimate){
cells[p].info=legitimate;
cells[p].element=key;
entry_cnt++;
rehash(hash_tableh)
inti,old_size;
cell*old_cells;
old_cells=h->
cells;
old_size=h->
/*创建一个新的doublesize的空表*/
h=initialize_table(2*old_size);
/*拷贝旧表的数据到新表*/
old_size;
i++){
if(old_cells[i].info==legitimate)
insert(old_cells[i].element,h);
free(old_cells);
/************
Thenextistestfunctions
***************/
#defineget_array_size(array)
(sizeof(array)/sizeof(array[0]))
void
test_hashquad(void)
element_typedatas[100];
get_array_size(datas);
datas[i]=rand()%1000;
h=initialize_table(13);
Initializeerror!
insert(datas[i],h);
/*在每次插入操作后检查是否需要rehash*/
if(need_rehash(h))
h=rehash(h);
p=find(67,h);
cells[p].info!
printf("
\n\tkeyvalue67notinhashtable!
\n"
}else{
\n\tkeyvalue67inhashtable!
p=find(datas[31],h);
\n\tkeyvalue%dnotinhashtable!
datas[31]);
\n\tkeyvalue%dinhashtable!
i=i;
return;
/*********************************************************************************************************/
/*hashquad.h*/
#ifndef_HASHQUAD_H_
#define_HASHQUAD_H_
typedefint
element_type;
typedefunsignedintIndex;
typedefIndex
Pos;
structhash_tbl;
typedefstructhash_tbl*hash_table;
#endif
这是一个将整数的质因数分解算法:
#include<
#include<
math.h>
conio.h>
voidf(intnum)
boolflag;
for(inti=int(sqrt((double)num));
i>
1;
i--)
{
if((num%i)==0)
flag=false;
}
if(!
flag)
for(inti=int(sqrt(num));
if((num%i)==0)
f(i);
num=num/i;
f(num);
break;
}
else
%d\t"
num);
}intmain()
intnum;
pleaseinputanumber:
scanf("
%d"
&
num);
return0;
加颜色的部分为核心算法的C语言表述。
1、选择合适的算法和数据结构
应该熟悉算法语言,知道各种算法的优缺点,具体资料请参见相应的参考资料,有很多计算机书籍上都有介绍。
将比较慢的顺序查找法用较快的二分查找或乱序查找法代替,插入排序或冒泡排序法用快速排序、合并排序或根排序代替,都可以大大提高程序执行的效率。
.选择一种合适的数据结构也很重要,比如你在一堆随机存放的数中使用了大量的插入和删除指令,那使用链表要快得多。
数组与指针语句具有十分紧密的关系,一般来说,指针比较灵活简洁,而数组则比较直观,容易理解。
对于大部分的编译器,使用指针比使用数组生成的代码更短,执行效率更高。
但是在Keil中则相反,使用数组比使用的指针生成的代码更短。
。
2、使用尽量小的数据类型
能够使用字符型(char)定义的变量,就不要使用整型(int)变量来定义;
能够使用整型变量定义的变量就不要用长整型(longint),能不使用浮点型(float)变量就不要使用浮点型变量。
当然,在定义变量后不要超过变量的作用范围,如果超过变量的范围赋值,C编译器并不报错,但程序运行结果却错了,而且这样的错误很难发现。
在ICCAVR中,可以在Options中设定使用printf参数,尽量使用基本型参数(%c、%d、%x、%X、%u和%s格式说明符),少用长整型参数(%ld、%lu、%lx和%lX格式说明符),至于浮点型的参数(%f)则尽量不要使用,其它C编译器也一样。
在其它条件不变的情况下,使用%f参数,会使生成的代码的数量增加很多,执行速度降低。
3、使用自加、自减指令
通常使用自加、自减指令和复合赋值表达式(如a-=1及a+=1等)都能够生成高质量的程序代码,编译器通常都能够生成inc和dec之类的指令,而使用a=a+1或a=a-1之类的指令,有很多C编译器都会生成二到三个字节的指令。
在AVR单片适用的ICCAVR、GCCAVR、IAR等C编译器以上几种书写方式生成的代码是一样的,也能够生成高质量的inc和dec之类的的代码。
4、减少运算的强度
可以使用运算量小但功能相同的表达式替换原来复杂的的表达式。
如下:
(1)、求余运算。
a=a%8;
可以改为:
a=a&
7;
说明:
位操作只需一个指令周期即可完成,而大部分的C编译器的“%”运算均是调用子程序来完成,代码长、执行速度慢。
通常,只要求是求2n方的余数,均可使用位操作的方法来代替。
(2)、平方运算
a=pow(a,2.0);
a=a*a;
在有内置硬件乘法器的单片机中(如51系列),乘法运算比求平方运算快得多,因为浮点数的求平方是通过调用子程序来实现的,在自带硬件乘法器的AVR单片机中,如ATMega163中,乘法运算只需2个时钟周期就可以完成。
既使是在没有内置硬件乘法器的AVR单片机中,乘法运算的子程序比平方运算的子程序代码短,执行速度快。
如果是求3次方,如:
a=pow(a,3.0);
更改为:
a=a*a*a;
则效率的改善更明显。
(3)、用移位实现乘除法运算
a=a*4;
b=b/4;
a=a<
<
2;
b=b>
>
通常如果需要乘以或除以2n,都可以用移位的方法代替。
在ICCAVR中,如果乘以2n,都可以生成左移的代码,而乘以其它的整数或除以任何数,均调用乘除法子程序。
用移位的方法得到代码比调用乘除法子程序生成的代码效率高。
实际上,只要是乘以或除以一个整数,均可以用移位的方法得到结果,如:
a=a*9
a=(a<
3)+a
5、循环
(1)、循环语
对于一些不需要循环变量参加运算的任务可以把它们放到循环外面,这里的任务包括表达式、函数的调用、指针运算、数组访问等,应该将没有必要执行多次的操作全部集合在一起,放到一个init的初始化程序中进行。
(2)、延时函数:
通常使用的延时函数均采用自加的形式:
voiddelay(void)
{
unsignedinti;
for(i=0;
i<
1000;
i++)
}
将其改为自减延时函数:
for(i=1000;
0;
i--)
两个函数的延时效果相似,但几乎所有的C编译对后一种函数生成的代码均比前一种代码少1~3个字节,因为几乎所有的MCU均有为0转移的指令,采用后一种方式能够生成这类指令。
在使用while循环时也一样,使用自减指令控制循环会比使用自加指令控制循环生成的代码更少1~3个字母。
但是在循环中有通过循环变量“i”读写数组的指令时,使用预减循环时有可能使数组超界,要引起注意。
(3)while循环和do…while循环
用while循环时有以下两种循环形式:
i=0;
while(i<
1000)
i++;
//用户程序
或:
i=1000;
do
i--;
while(i>
0);
在这两种循环中,使用do…while循环编译后生成的代码的长度短于while循环。
6、查表
在程序中一般不进行非常复杂的运算,如浮点数的乘除及开方等,以及一些复杂的数学模型的插补运算,对这些即消耗时间又消费资源的运算,应尽量使用查表的方式,并且将数据表置于程序存储区。
如果直接生成所需的表比较困难,也尽量在启了,减少了程序执行过程中重复计算的工作量。
7、其它
比如使用在线汇编及将字符串和一些常量保存在程序存储器中,均有利于优化。
enum类型的本质
至从C语言开始enum类型就被作为用户自定义分类有限集合常量的方法被引入到了语言
当中,而且一度成为C++中定义编译期常量的唯一方法(后来在类中引入了静态整型常量)。
根据上面对enum类型的描述,到底enum所定义出来的类型是一个什么样的类型呢?
作为
一个用户自定义的类型其所占用的内存空间是多少呢?
使用enum类型是否真的能够起到有限
集合常量的边界约束呢?
大家可能都知道enum类型和int类型具有隐示(自动)转换的规则,
那么是否真的在任何地方都可以使用enum类型的变量来代替int类型的变量呢?
下面会逐一
回答这些问题。
1.到底enum所定义出来的类型是一个什么样的类型呢?
在C++中大家都知道仅仅有两种大的类型分类:
POD类型和类类型(不清楚的可以参
见我的其他文章)。
enum所定义的类型其实属于POD类型,也就是说它会参与到POD
类型的隐示转换规则当中去,所以才会出现enum类型与int类型之间的隐示转换现象。
那么也就是说enum所定义的类型不具备名字空间限定能力(因为不属于类类型),
其所定义的常量子具备和enum类型所在名字空间相同的可见性,由于自身没有名字
限定能力,所以会出现名字冲突现象。
如:
structCEType
enumEType1{e1,e2};
enumEType2{e1,e2};
};
上面的例子会出现e1、e2名字冲突编译时错误,原因就在于枚举子(e1、e2)是
CEType名字空间中的名字,同样在引用该CEType中的枚举子时必须采用CEType:
:
e1
这样的方式进行,而不是CEType:
EType1:
e1来进行引用。
2.作为一个用户自定义的类型其所占用的内存空间是多少呢?
该问题就是sizeof(EType1)等于多少的问题,是不是每一个用户自定义的枚举类
型都具有相同的尺寸呢?
在大多数的32位编译器下(如:
VC++、gcc等)一个枚举类
型的尺寸其实就是一个sizeof(int)的大小,难道枚举类型的尺寸真的就应该是int
类型的尺寸吗?
其实不是这样的,在C++标准文档(ISO14882)中并没有这样来定义,
标准中是这样说明的:
“枚举类型的尺寸是以能够容纳最大枚举子的值的整数的尺寸”,
同时标准中也说名了:
“枚举类型中的枚举子的值必须要能够用一个int类型表述”,
也就是说,枚举类型的尺寸不能够超过int类型的尺寸,但是是不是必须和int类型
具有相同的尺寸呢?
上面的标准已经说得很清楚了,只要能够容纳最大的枚举子的
值的整数就可以了,那么就是说可以是char、short和int。
例如:
enumEType1{e1=CHAR_MAX};
enumEType2{e2=SHRT_MAX};
enumEType3{e3=INT_MAX
上面的三个枚举类型分别可以用char、short、int的内存空间进行表示,也就是:
sizeof(EType1)==sizeof(char
);
sizeof(EType2)==sizeof(short);
sizeof(EType3)==sizeof(int
那为什么在32位的编译器下都会将上面三个枚举类型的尺寸编译成int类型的尺寸呢?
主要是从32位数据内存对其方面的要求进行考虑的,在某些计算机硬件环境下具有对
齐的强制性要求(如:
sunSPARC),有些则是因为采用一个完整的32位字长CPU处理
效率非常高的原因(如:
IA32)。
所以不可以简单的假设枚举类型的尺寸就是int类
型的尺寸,说不定会遇到一个编译器为了节约内存而采用上面的处理策略。
3.使用enum类型是否真的能够起到有限集合常量的边界约束呢?
首先看一下下面这个例子:
enumEType{e1=0,e2};
voidfunc1(ETypee)
if(e==e1)
//dosomething
//dosomethingbecausee!
=e1muste==e2
voidfunc2(ETypee)
elseif(e==e2)
- 配套讲稿:
如PPT文件的首页显示word图标,表示该PPT已包含配套word讲稿。双击word图标可打开word文档。
- 特殊限制:
部分文档作品中含有的国旗、国徽等图片,仅作为作品整体效果示例展示,禁止商用。设计者仅对作品中独创性部分享有著作权。
- 关 键 词:
- hash 冲突