题目3:文本文件单词的检索与计数(实验准备)

数据结构课程实践系列

题目1:学生成绩档案管理系统(实验准备)

题目2:隐式图的搜索问题(A*算法解决八数码)

题目3:文本文件单词的检索与计数(实验准备)

声明

实验任务

  • 建立一个文本文件,统计给定单词在文本文件中出现的总次数及位置;

实验要求

  • 文本文件中每个单词不包含空格且不跨行,单词由字符序列构成且区分大小写,统计给定单词在文本文件中出现的总次数,检索输出的某个单词出现在文本中的行号、在该行中出现的位置
  • 设计数据量大的文本,进行子串的查询处理,分析算法运行的时间效率,对所有输出的匹配位置结果进行验证,以证明算法设计和实现的正确性。
  • 用朴素模式匹配算法或KMP算法实现字符串定位;
  • 可正确读取,保存文本;

所需知识

IO流文件读取(或者API对文本文件的读取也行),外加KMP算法的实现

导出所需知识

API对文本文件的读取

一个ReadFileAPI即可解决,至于它的详细用法,我已在核心编程模块中用过,并且做下笔记,如下超链接:
ReadFile API的介绍外加实际操作

KMP算法的详解

这个算法我也已经在博客中进行实际的讲述并且记录(毕竟KMP算法还是得分情况,种类挺多的,得需要几万字讲述,这里就不一一讲述):
彻底理解KMP,其实最主要的也就是理解NEXT数组,只要找到前缀后缀最长公共元素长度,然后构成NEXT数组,紧接着就是利用NEXT数组来进行相应跳转比较即可

NEXT数组具体过程

直接移动模式串,使得公共前后缀的前缀直接移动到了后缀所在的位置
在这里插入图片描述
再求next数组时只需要看模式串即可,模式串中对应的位置与主串不匹配时,找出对应位置之前的串中的公共前后缀(找最长的公共前后缀,且要小于对应位置之前的串长度),然后往前移动前后串。(一般我们的字符串都存在一个字符数组中,数组在内存中是不可能移动的,所以移动这说法只是一个形象化过程,要把它转化为下面这种处理方式)

在这里插入图片描述

1号位(注意,以下讲解中,指针是不移动的,只有字符串在移动)

假设模式串存在一个以下标为1开始的数组中,而且假设这个字符串会与任何一个字符串去比较(进行KMP算法),那么任何一个位置都可能不匹配,如下图

在这里插入图片描述

那么接下来只需要把模式串前移一位,(也就是说把模式串中1号下标的字符与主串下一个下标的字符进行比较)
在这里插入图片描述

处理方法:1号位与主串下一位比较

扫描二维码关注公众号,回复: 12641282 查看本文章

2号位

假如2号位不匹配呢?如下图
在这里插入图片描述
提醒:主串中第一个是A,打错了
那么接下来该怎么移动呢?这里的公共前后缀为0,所以的话,只需要进行如下操作(移动后,指针左边的长度就是公共前后缀的长度
处理方法:1号位与主串当前位置比较
在这里插入图片描述

3号位

在这里插入图片描述

那么这下直接看模式串喽,最长公共前后缀为0,所以处理方法和2号位一样哦
处理方法:1号位与主串当前位置比较

4号位

在这里插入图片描述

最长公共前后缀为1,
在这里插入图片描述

也就是要如下移动操作
在这里插入图片描述

处理方法:2号位与主串当前位置比较

5号位

最长公共前后缀为2,
在这里插入图片描述
也就是要如下移动操作
在这里插入图片描述

6号位

最长公共前后缀为2,
在这里插入图片描述
也就是要如下移动操作
在这里插入图片描述
也就是4号位于当前主串进行比较(总结:每次开始比较的编号=最大公共前后缀长度+1

总结:

每次开始比较的编号=最大公共前后缀长度+1(除了第一句话,也就是0)

在这里插入图片描述
转化为数组之后,如下:
在这里插入图片描述
然后放在一个数组中,
在这里插入图片描述

实现代码

#define _CRT_SECURE_NO_WARNINGS
#include<stdio.h>
#include<string.h>
#define BUF_SIZE 256
typedef struct seqstring {
    
    
	char string[100];
	int length;
}seqstring;
 
void getnext(seqstring p, int next[]) {
    
    
	int i, j;
	i = 0;//指向字符串每个字符的下标
	j = -1;
	next[i] = j;//next[0]放上-1 
	while (i < p.length) {
    
    //没有到达结尾的话 
		if (j == -1 || p.string[i] == p.string[j]) {
    
    //如果是第一个字符或遇到相同的字符
			next[++i] = ++j;
		}
		else {
    
    
			j = next[j];
		}
	}
	for (i = 0;i < p.length;i++) {
    
    //输出next[]值 
		printf("%d ", next[i]);
	}
}
 
int kmp(seqstring t, seqstring p, int next[]) {
    
    
	int i, j;
	i = j = 0;
	while (i < t.length && j < p.length) {
    
    
		if (j == -1 || t.string[i] == p.string[j]) {
    
    
			i++;j++;
		}
		else {
    
    
			j = next[j];
		}
	}
	if (j == p.length) return i - p.length;
	else return -1;
}
int  main() {
    
    
	seqstring t, p;
	int next[50];
	
	
	DWORD	nIn;
    char buffer[BUF_SIZE] = "";
   HANDLE handle = CreateFile("test.txt",
		GENERIC_READ,
		FILE_SHARE_READ,
		NULL,
		OPEN_EXISTING,
		FILE_ATTRIBUTE_NORMAL,
		NULL);
	if (handle == INVALID_HANDLE_VALUE) {
    
    
		printf("%d", GetLastError());
		return -1;
	}
	ReadFile(handle, buffer, BUF_SIZE, &nIn, NULL) ;
	

	strcpy(t.string, buffer);
	printf("%s\n", t.string);
	t.length = strlen(t.string);
 
	printf("please input string p:");
	scanf("%s", p.string);
	printf("%s\n", p.string);
	p.length = strlen(p.string);
	printf("next:");
	getnext(p, next);
	printf("\n%d\n", kmp(t, p, next));
}

在这里插入图片描述

在这里插入图片描述
基本功能实现了,接下来也就差点添油加醋喽,随便改改就行了

猜你喜欢

转载自blog.csdn.net/CSNN2019/article/details/114273635