单词词频统计与单词检索

目录

1 需求分析

1.1 任务

1.2 输入形式

1.3 输出形式

1.4  程序功能

2 概要设计

2.1 抽象数据类型

2.2 主程序流程图

3 详细设计

3.1 功能函数设计

3.2 主函数设计

4 调试分析

4.1 调试过程的问题:

4.2 时空分析

4.3 改进设想

4.4 经验体会

4.5 性能比较

5 测试数据与结果

5.1 基于链式存储上的顺序查找

5.2 基于链地址法的哈希查找

5.3 退出程序


1 需求分析

1.1 任务

        依据“折半查找、链式存储上的顺序查找”中的一种方法建立存储结构,并完成文件中单词的字频统计。完成字频统计后,根据输入的单词输出该单词是否存在于文件中,若存在输出频度,若不存在,输出“查找失败”。依据“基于开放定址法的哈希查找、基于链地址法的哈希查找” 中的一种方法建立存储结构,并完成文件中单词的字频统计。完成字频统计后,根据输入的单词输出该单词是否存在于文件中,若存在输出频度,若不存在,输出“查找失败”。

1.2 输入形式

        本程序共两种输入形式

                (1)第一种:输入A、B、C来选择存储结构

                (2)第二种:输入1、2、3选择操作

1.3 输出形式

        在字频统计功能中会将统计好的信息写入文件中进行保存,在单词检索功能中会将单词的字频输出到控制台。

1.4  程序功能

        (1)“void CreatLink(LinkList *L);”和“void CreatHash(LinkList *L);” 读入文件中的单词,并构建单词节点和链表头节点;

        (2)“void LinkInsert(LinkList *L,LinkList *t);”和“void HashInsert(LinkList *L,LinkList *t);”将构建完成的单词节点进行字频分析和节点插入;

        (3)“void LinkFound(LinkList *L);”和“void HashFound(LinkList *L);”分别为“基于链式存储的顺序查找”和“基于链地址法的哈希查找”。

2 概要设计

2.1 抽象数据类型

typedef struct LN{
	char data[WORDLENGTH];	//存放单词 
	int Frequency;			//存放字频 
	struct LN *next;		//指针 
}LinkNode,*LinkList;

2.2 主程序流程图

3 详细设计

3.1 功能函数设计

//链式存储结构的建立及字频统计
void CreatLink(LinkList *L){	//链式存储结构的建立及字频统计
	FILE *fp1,*fp2;			//文件指针 
	LinkList t,pre,p;
	char s1[WORDLENGTH];		//存放来自文件的一个单词 
	(*L)=(LinkList)malloc(1*sizeof(LinkNode));	 
	(*L)->next=NULL;
	fp1=fopen("InFile.txt","r"); 	
	while(!feof(fp1)){
		fscanf(fp1,"%s",s1);	//读文件 
		t=(LinkList)malloc(1*sizeof(LinkNode));	//为来自文件的单词构建存储节点		
		strcpy(t->data,s1); 				
		t->Frequency=1;
		LinkInsert(L,&t); 	//将节点进行字频分析和插入操作 
	}
	fclose(fp1);
	fp2=fopen("OutFile1.txt","w");
	p=(*L)->next;
	while(p!=NULL){
		fprintf(fp2,"%s			%5d\n",p->data,p->Frequency);	//将每个单词的频度写进文件 
/*		
		fprintf(fp2,"%s",p->data);
		num_Space=25-strlen(p->data);
		for(i=0;i<num_Space;i++) fprintf(fp2," ");
		fprintf(fp2,"%5d\n",p->Frequency);
*/
		p=p->next;
	}
	fclose(fp2);
	printf("字频统计完成!\n\n");	
}

//插入单词信息
void LinkInsert(LinkList *L,LinkList *t){ //插入单词信息
	LinkList p,pre,loc;
	if((*L)->next==NULL){	//当链表为空时,直接将节点插入 
		(*t)->next=(*L)->next;
		(*L)->next=(*t);
	}
	else{
		pre=(*L);
		p=pre->next;
		loc=NULL;
		while(p!=NULL){	//链表不为空,在已有链表中寻找当前单词是否出现过 
			if(strcmp(p->data,(*t)->data)==0) {p->Frequency++; return ;}	//出现过,频度加1 
//			if(stricmp(p->data,(*t)->data)>0) {loc=pre;}
			pre=pre->next;
			p=pre->next;
		}
		(*t)->next=pre->next;	//未出现过,插入节点 
		pre->next=(*t);		
	}
}

//基于链式存储的顺序查找
void LinkFound(LinkList *L){	//基于链式存储的顺序查找
	char word[WORDLENGTH];
	int flag=0;
	LinkList p,pre;
	printf("请输入待查找的单词:");
	scanf("%s",&word);
	pre=(*L);
	p=pre->next;
	while(p!=NULL){	//顺序查找单词 
		if(strcmp(p->data,word)==0) {
			printf("待查找单词的频度:%d\n\n",p->Frequency);
			flag=1;
			break;
		}
		p=p->next;
	}
	if(!flag) printf("查找失败\n\n");
}

//链式哈希存储的构建及字频统计
void CreatHash(LinkList *L){	//链式哈希存储的构建及字频统计
	LinkList t,p;
	int i;
	FILE *fp1,*fp2;
	char s1[WORDLENGTH];	//存放单词 
	for(i=0;i<26;i++){	//生成26个头结点,并初始化 
		L[i]=(LinkList)malloc(sizeof(LinkNode));
		(*L[i]).Frequency=-1;
		(*L[i]).next=NULL;
	}
	fp1=fopen("InFile.txt","r");
	while(!feof(fp1)){
		fscanf(fp1,"%s",s1); 
		t=(LinkList)malloc(sizeof(LinkNode));	//为来自文件的单词构建存储节点		
		strcpy(t->data,s1); 				
		t->Frequency=1;
		HashInsert(L,&t); 	//将节点进行字频分析和插入操作
	}
	fclose(fp1);
	fp2=fopen("OutFile2.txt","w");
	for(i=0;i<26;i++){	//将分析统计结构写入文件 
		p=(*L[i]).next;
		while(p!=NULL){
			fprintf(fp2,"%s			%5d\n",p->data,p->Frequency);
			p=p->next;
		}
	}
	fclose(fp2);
	printf("字频统计完成!\n\n");	
}

//插入单词信息 
void HashInsert(LinkList *L,LinkList *t){	//插入单词信息 
		LinkList p,pre,loc;
		int number;
		number=(tolower((*t)->data[0]))-'a';	//单词的存储位置为单词首字母的序号(不区分大小写,A字母为0号位置 
		if((*L[number]).next==NULL){	//链表为空直接插入节点 
			(*t)->next=(*L[number]).next;
			(*L[number]).next=(*t);
		}
		else{
			pre=&(*L[number]);
			p=pre->next;
			loc=NULL;
			while(p!=NULL){	//链表不为空,在已有链表中寻找当前单词是否出现过
				if(strcmp(p->data,(*t)->data)==0) {p->Frequency++; return ;}//出现过,频度加1
				pre=pre->next;
				p=pre->next;
			}
			(*t)->next=pre->next;	//未出现过,插入节点 
			pre->next=(*t);
		}
}

//基于链地址法的哈希查找 
void HashFound(LinkList *L){	//基于链地址法的哈希查找
	char word[WORDLENGTH];
	int flag=0,number;
	LinkList p,pre;
	printf("请输入待查找的单词:");
	scanf("%s",&word);
	number=(tolower(word[0]))-'a';//计算单词存储位置的头结点序号 
	pre=&(*L[number]);
	p=pre->next;
	while(p!=NULL){
		if(strcmp(p->data,word)==0) {
			printf("待查找单词的频度:%d\n\n",p->Frequency);
			flag=1;
			break;
		}
		p=p->next;
	}
	if(!flag) printf("查找失败\n\n");
}

//操作提示 
void Tips(int flag){	//操作提示 
	if(flag==0){
		printf("\n+---------------Word_Frequency_Statistics_And_Retrieval---------------+\n");
		printf("+	A:链式存储的顺序查找		B:基于链地址法的哈希查找               +\n");
		printf("+	C:退出程序                                                    +\n");
		printf("+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++\n");
	}
	if(flag==-1){
		printf("+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++\n");
		printf("+         1:字频统计         2:顺序查找         3.退出当前结构        +\n");
		printf("+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++\n");
	}
	if(flag==1){
		printf("+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++\n");
		printf("+         1:字频统计         2:哈希查找         3.退出当前结构        +\n");
		printf("+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++\n");
	} 
}

3.2 主函数设计

int main(){
	char OP;
	int function,EXIT=1,flag_exit;
	LinkList LinkStruct,LinkHash;
	while(1){	
		Tips(0);
		printf("请选择存储结构:");
		scanf("%c",&OP);
		if(OP=='A'){
			do{
				flag_exit=0;
				Tips(-1);
				printf("现存储结构为“链式存储的顺序查找”。请输出您的下一步操作:");
				scanf("%d",&function);
				switch(function) {
					case 1:CreatLink(&LinkStruct);getchar();break;
					case 2:LinkFound(&LinkStruct);getchar();break;
					case 3:flag_exit=1;break;
					default :printf("抱歉,输入不合法。请重新输入!\n\n");
				}
				if(flag_exit==1) printf("已退出当前结构!\n\n");
			}while(function!=3);	
		}
		
		if(OP=='B'){
			do{
				flag_exit=0;
				Tips(1);
				printf("现存储结构为“基于链地址法的哈希查找”。请输出您的下一步操作:");
				scanf("%d",&function);
				switch(function){
					case 1:CreatHash(&LinkHash);getchar();break;
					case 2:HashFound(&LinkHash);getchar();break;
					case 3:flag_exit=1;break;
					default :printf("抱歉,输入不合法。请重新输入!\n\n");
				}
				if(flag_exit==1) printf("已退出当前结构!\n\n");
			}while(function!=3);
		}
		if(OP=='C') break;	
	}
	printf("即将退出程序,欢迎下次使用^_^\n");
	return 0;
}

4 调试分析

4.1 调试过程的问题:

        (1)问题1:写入文件的结果在文件中位置凌乱,不统一。

                解决1:将写入文件语句中的“空格”换成“制表符”。

        (2)问题2:类似“while(p!=NULL){}”的循环无法使用。

                解决2:检查过后发现是因为粗心,忘记在循环体中加入“p=p->next”的移位语句。

        (3)问题3:在判断两个单词是否相同时,无法正确判断。

                解决3:因为单词是以字符串的形式存储的,不能直接使用“=”进行比较,而应该使用特定的函数或者自定义函数。

4.2 时空分析

函数

时间复杂度

空间复杂度

void CreatLink(LinkList *L);

O(n)

O(1)

void LinkInsert(LinkList *L,LinkList *t);

O(n)

O(1)

void LinkFound(LinkList *L);

O(n)

O(1)

void CreatHash(LinkList *L);

O(n)

O(1)

void HashInsert(LinkList *L,LinkList *t);

O(n)

O(1)

void HashFound(LinkList *L);

O(n)

O(1)

4.3 改进设想

        在链表节点的插入过程中可以对单词进行字符串大小比较确定位置,使节点按字典序进行存储。

4.4 经验体会

        要按时对以前的知识进行复习回顾或者在平时多写多练,尽量避免自己生疏,造成代码编写过程中浪费大量时间在修改代码上。

4.5 性能比较

        (1)基于链式存储上的顺序查找:ASL=(n+1)/2;

        (2)基于链地址法的哈希查找:ASL=∑piai/num;(pi为相同首字母的单词的相对于其头结点的偏移,ai为相同pi的个数,num为使用的头结点的个数)

5 测试数据与结果

5.1 基于链式存储上的顺序查找

5.2 基于链地址法的哈希查找

5.3 退出程序

  • 30
    点赞
  • 19
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

SouthDreamYaoJia

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值