文学研究助手
问题描述
文学研究人员需要统计某篇英文小说中某些形容词的出现次数和位置。试写一个实现这一目标的文字统计系统,称为"文学研究助手"。
基本要求
英文小说存于文本文件中。待统计的词汇集合要一次输入完毕,即统计工作必需在程序的一次运行后就全部完成。程序的输出结果是每个词出现次数和出现位置所在行的行号,格式自行设计。
测试数据:以你的C源程序模拟英文小说,C语言的保留字集作为待统计的词汇集。
实现提示
设小说中的词汇一律不跨行。这样每读入一行就统计每个词在这行中的出现次数。出现位置所在行的行号可以用链表存储。若某行中出现不止一次,不必存多个相同的行号。
使用AC自动机解答问题
#include <stdio.h>
#include <malloc.h>
#include <string.h>
#include <stdbool.h>
char s[10005];
struct Trie {
int fail;
int next[26];
int end;
}AC[16275];
int queuee[100005], top = 0, bottom = 0;
void push (int num) {
queuee[top++] = num;
}
void pop () { //弹出队列最上面的元素
for (int i = 0; i < top; ++i) {
queuee[i] = queuee[i + 1];
}
top--;
}
int front() { //取队列最上面的元素
return queuee[bottom];
}
bool empty() { //判断队列是否为空
if (top == bottom) {
return true;
}
return false;
}
char word[155][105];
int a[155][505], cnt = 0, qq = 1;
void Build(int n) { //建立字典树
for (int i = 1; i <= n; ++i) {
int len = strlen(word[i]);
int now = 0;
for (int j = 0; j < len; ++j) {
if (AC[now].next[word[i][j] - 'a'] == 0) {
AC[now].next[word[i][j] - 'a'] = ++cnt;
}
now = AC[now].next[word[i][j] - 'a'];
}
AC[now].end = i;
}
}
void get_fail() { //获取next[]
for (int i = 0; i < 26; ++i) {
if (AC[0].next[i] != 0) {
AC[AC[0].next[i]].fail = 0;
push(AC[0].next[i]);
}
}
while (!empty()) {
int u = front();
pop();
for (int i = 0; i < 26; ++i) {
if (AC[u].next[i] != 0) {
AC[AC[u].next[i]].fail = AC[AC[u].fail].next[i];
push(AC[u].next[i]);
}
else {
AC[u].next[i] = AC[AC[u].fail].next[i];
}
}
}
}
void search() { //匹配字符串
int len = strlen(s);
int now = 0;
for (int i = 0; i < len; ++i) {
if (s[i] >= 'a' && s[i] <= 'z') {
now = AC[now].next[s[i] - 'a'];
for (int j = now; j ; j = AC[j].fail) {
if (AC[j].end != 0 ) {
a[AC[j].end][qq]++;
}
}
}
}
}
int main() {
int n;
printf("Please input the number of words:"); //输入要查的单词数量
scanf("%d", &n);
for (int i = 1; i <= n; ++i) {
printf("Please input words:"); //输入要查的单词
scanf("%s", word[i]);
}
Build(n);
AC[0].fail = 0;
get_fail();
FILE * fp = NULL;
fp = fopen("../text.txt","r"); //存储文章
if (fp == NULL) {
printf("文件错误");
}
else {
while(!feof(fp)) {
memset(s, '\0', sizeof(s));
fgets(s, 10005, fp);
search();
qq++;
}
}
fclose(fp);
for (int i = 1; i <= n; ++i) {
int flag = 0;
printf("%s", word[i]);
for (int j = 1; j < 205; ++j) {
if (a[i][j] != 0) {
flag = 1;
printf("在第%d行出现%d次,",j, a[i][j]);
}
}
if (!flag) {
printf("未出现");
}
printf("\n");
}
return 0;
}