hash冲突Word下载.docx

上传人:b****5 文档编号:19917953 上传时间:2023-01-12 格式:DOCX 页数:24 大小:25.80KB
下载 相关 举报
hash冲突Word下载.docx_第1页
第1页 / 共24页
hash冲突Word下载.docx_第2页
第2页 / 共24页
hash冲突Word下载.docx_第3页
第3页 / 共24页
hash冲突Word下载.docx_第4页
第4页 / 共24页
hash冲突Word下载.docx_第5页
第5页 / 共24页
点击查看更多>>
下载资源
资源描述

hash冲突Word下载.docx

《hash冲突Word下载.docx》由会员分享,可在线阅读,更多相关《hash冲突Word下载.docx(24页珍藏版)》请在冰豆网上搜索。

hash冲突Word下载.docx

}

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)

展开阅读全文
相关资源
猜你喜欢
相关搜索

当前位置:首页 > 人文社科

copyright@ 2008-2022 冰豆网网站版权所有

经营许可证编号:鄂ICP备2022015515号-1