#include <stdio.h>#include <string.h>#include <iomanip.h> //参数化输入\输出#include <stdlib.h>#include <conio.h>//using namespace //名称空间#define TOTAL 40 //39个关键字#define MAXLEN 10 //关键字长度#define HASHLEN 41 //哈希表长度41#define M 40typedef struct //哈希表 结构体 {char keyword[MAXLEN]; //关键字int count; //记录频度int con; //记录冲突次数}HASH;//全局变量int cont=0; //统计关键词个数char KeyWords[TOTAL][MAXLEN]={ "asm","auto","break","case","cdecl","char", "const","continue","default","do","double", "else","enum","extern","far","float","for", "goto","huge","if","int","interrupt","long", "near","pascal","register","return","short", "signed","sizeof","static","struct","switch", "typedef","union","unsigned","void","volatile", "while"}; //C语言中的39个关键字存入二维数组中,排好序的数组HASH HS[HASHLEN]; //建立结构体HS//函数声明void Show(int key);int Read(char *filename); int isLetter(char ch);int isKeyWords(char *word);int FindHX(char *keyword);int CreatHX(char *keyword);int GetFreePos(int key);int GetKey(char *keyword);void main(){char orz; int flag=1,i,count,key,has;char filename[128],word[MAXLEN]; while(flag){printf("\t\tA.读取一个文件\n"); printf("\t\tB.输出Hash表(关键字总数,冲突次数)\n"); printf("\t\tC.查询某关键字在Hash表中的情况\n"); printf("\t\tD.显示Hash表中的冲突关键字\n"); printf("\t\tE.显示C语言关键字的Hash函数值(作为对照)\n"); printf("\t\tF.退出\n\n");printf("\t\t请输入序号(A--F):"); scanf("%c",&orz);switch(orz) //选择 { case 'a':case 'A':system("cls"); //清屏函数 printf("请输入要读取的文件名(文件必须与程序在同一目录下):"); //比如输入:a.cppscanf("%s",&filename);Read(filename); printf("\n按任意键返回..."); getch(); system("cls");break; case 'b':case 'B':getchar();system("cls");printf("每次显示5行,请按回车键继续!\n");for(i=0;i<HASHLEN;i++){ Show(i); if((i+1)%5==0)getchar(); //为了清晰,每次显示5行} printf("关键字总数为: %d\n",cont); printf("\n按任意键返回..."); getch(); system("cls"); break; case 'c':case 'C':system("cls");printf("请输入你想要查找的关键字: "); scanf("%s",&word); printf("\n"); Show(FindHX(word));printf("\n按任意键返回..."); getch(); system("cls"); break; case 'd':case 'D':system("cls"); printf("\t冲突关键字列表\n\n"); count=0; for(i=0;i<HASHLEN;i++){ if(strlen(HS[i].keyword)>0){ key=GetKey(HS[i].keyword); if(key!=i){ count++; printf("\t关键字:%s",HS[i].keyword); printf("\t哈希表当前位置:%d",i); printf("\t冲突次数:%d\n",HS[i].con);}}} if(count==0) printf("没有冲突\n"); else printf("\n\t\t\t冲突关键字共:%d个\n",count);printf("\n按任意键返回..."); getch(); system("cls"); break; case 'e':case 'E':getchar();system("cls");printf(" C语言中的关键字和其在哈希表的位置:\n"); for(i=0;i<TOTAL;i++){has=GetKey(KeyWords[i]);printf("[%-2d]%-11s",has,KeyWords[i]);if((i+1)%5==0) printf("\n");} printf("\n");printf("\n按任意键返回..."); getch(); system("cls");break; case 'f':case 'F':flag=0;break;default: system("cls");}}}int Read(char *filename){char word[MAXLEN],ch,ch1;int i;FILE *read; //建立一个指像FILE类型结构体的指针变量 if((read=fopen(filename,"r"))==NULL) //以只读方式读取文件,如果为空执行下面的语句{printf("\n文件不存在,请确认好再输入!");return -1; //跳出Read函数}while(!feof(read)) //feof()检测文件是否结束,到末尾函数值为“真”即非0{i=0;ch=fgetc(read); //读取一个字符if (ch=='/') //遇到‘/’就再读取一个字符{ch1=fgetc(read);if(ch1=='/') //遇到“//”注释while(ch1!='\n'){ch1=fgetc(read);}else if (ch1=='*') //遇见“/*”注释{ch1=fgetc(read);while(ch1!='*'){ch1=fgetc(read);if(ch1=='*'){ch=fgetc(read);if(ch=='/')break;}}}}while(isLetter(ch)==0&&feof(read)==0)ch=fgetc(read); //如果不是字母就接着读取,关键字都是由字母组成的while(isLetter(ch)==1&&feof(read)==0){if(i==MAXLEN){while(isLetter(ch)==1&&feof(read)==0){ch=fgetc(read); //超过MAXLEN的长度则一定不为关键字,把余下连一起的字母都读取}i=0;break;}else{word[i++]=ch; //把读取到的字母存入word数组中ch=fgetc(read);}}word[i]='\0';if(isKeyWords(word)){CreatHX(word);}}fclose(read);printf("\n读取成功,文件中关键字已经存入hash表,请继续操作");}int isLetter(char ch) //判断是否是字母,因为关键字都是英文单词{//if((ch>='a'&&ch<='z')||(ch>='A'&&ch<='Z'))if((ch>='a'&&ch<='z'))return 1; //是字母就返回1elsereturn 0; //不是字母就返回0}int FindHX(char *keyword) //查找哈希表,分块查找{int key,find,tem=0;if(!isKeyWords(keyword)) //用于查找制定关键字时判断是否为关键字return -1;key=GetKey(keyword);if(strcmp(HS[key].keyword,keyword)==0)return key;for(find=key+1;find<HASHLEN;find++){ //线性探查法顺序查找哈希表中是否已存在关键字tem++; //统计冲突次数if(strcmp(HS[find].keyword,keyword)==0){HS[find].con=tem; //若有相等的就把冲突的次数存入数组的con中return find;}}for(find=0;find<key;find++) //后面的找不到再从前面开始找{tem++;if(strcmp(HS[find].keyword,keyword)==0){HS[find].con=tem;return find;}}return -1;}int CreatHX(char *keyword) //建立哈希表,加个*是因为word是一个数组{int key;if(!isKeyWords(keyword)) //不是关键字跳出此函数return -1; key=GetKey(keyword); //计算哈希值,根据所给哈希函数计算得出的结果if(strlen(HS[key].keyword)>0) //判断关键字表中该位置是否存在关键字,strlen用于计算()内的字符串长度{ //已经存在有关键字if(strcmp(HS[key].keyword,keyword)==0){ //再判断哈希表中该位置的关键字是否相同HS[key].count++; //相同就频度加1return 1; //跳出函数}key=FindHX(keyword); //不相同,继续查找if(key<0) //没有找到相等的keyword{key=GetFreePos(GetKey(keyword));if(key<0) //哈希表满或者计算的哈希值有问题return -1;strcpy(HS[key].keyword,keyword); //将关键字插入哈希表}if(key<0)return -1;HS[key].count++;}else //该位置为空,直接将关键字插入该位置中{strcpy(HS[key].keyword,keyword);HS[key].count++;}return 1;}int GetFreePos(int key) //在哈希表中给关键字找个位置插进去{int find,tem=0;if(key<0||key>=HASHLEN) return -1;for(find=key+1;find<HASHLEN;find++) //先找后面的位置{tem++;if(strlen(HS[find].keyword)==0) //若这个地方为空{ HS[find].con=tem; //把冲突的次数存入con中 return find; }}for(find=0;find<key;find++) //若后面没有地方可以插入,再找前面的位置{tem++;if(strlen(HS[find].keyword)==0){HS[find].con=tem;return find;}}return -1; //哈希表已满}void Show(int key){if(key<0||key>=HASHLEN){printf("关键字不存在!\n");return;}if(strlen(HS[key].keyword)==0){printf("哈希表位置: %d 记录是空的!\n",key);return;}printf("哈希表位置: %d 关键字: %-11s出现次数: %d\n",key,HS[key].keyword,HS[key].count);cont++;}int GetKey(char *keyword) //哈希函数{ //Hash函数为:Hash(Key)=[(Key的首字母序号)*100+(Key的尾字母序号)] Mod 41return ( keyword[0]*100+keyword[strlen(keyword)-1] ) % 41; }int isKeyWords(char *word){ int low,high,mid; low=0;high=M-1; while(low <= high) { mid=(low+high)/2; if(strcmp(word,KeyWords[mid])==0) return(1);if(strcmp(word,KeyWords[mid])==-1) high=mid-1; else low=mid+1; } return(0);}/*int isKeyWords(char *word) //判断是否关键字{int i;for(i=0;i<TOTAL;i++)if(strcmp(word,KeyWords[i])==0)return 1; return 0;}*/