如题。假如我输入一个英文资料文本和一个重点单词文本。两个文本中所有单词的单词间不包括空格和跨行,字母不区分大小写。 英文资料文本就是正常的英文小说段落。重点单词文本是仅由单词构成,单词间由逗号隔开。
程序统计重点单词文本中的单词在英文资料文本中出现的总次数,并按照出现次数由大到小进行单词排序。
按出现次数由大到小输出重点单词。输出格式无所谓。请问这种小程序代码怎么设计。我是一个英专生,自学的C语言。想设计一个高速复习的小程序。但是毫无头绪。
请尽量使用基础的语法,我是一个初学者,高级语法并不能看得太懂
主要是字符串的分割和对比。
(1)先把终点单词提取出来,存到一个数组中(如果学过STL容器,也可以用list或者vector容器),并用一个数组记录重点单词出现的次数。
(2)读取英文资料文本(可以逐行读取,也可以一次性读取,处理方式类似),以逐行读取为例:
(a)读取一行文本,存入char数组中
(b)遍历char数组,用空格,逗号,点,问号,叹号分割字符串,把这一行的所有单词提取出来。
(c)每提取出一个单词,就判断该单词是否在重点单词数组中,如果在,就把对应的单词次数+1
(d)继续读取一行,继续a-c的步骤,直到文件读取完毕。
下面连接里有一个读取文件,并统计单词数量的代码,在它的基础上增加重点单词的统计就可以了。
# include <stdio.h>
# include <stdlib.h>
# include <string.h>
#define MAXSTRLEN 1024
typedef struct node {
int cnt; // 统计各个单词出现的次数 初始化为0
struct node *next[40]; // 数字放在0-9,单词放在10-36
}TrieTreeNode,* TrieTree;
TrieTree createTrieTreeNode(); // 新建并初始化一个节点
int InsertTrieTreeNode(TrieTree *pT, char *str); // 插入一个单词
int DeleteTrieTreeNode(TrieTree *pT, char *str); // 删除一个单词
int SearchTrieTree(TrieTree T, char *str); // 搜索Trie树
void TraverseTrieTree(TrieTree T); // 遍历Trie树
void DestroyTrieTree(TrieTree *pT); // 销毁Trie树
// 新建并初始化一个节点
TrieTree createTrieTreeNode() {
TrieTreeNode *treeNode;
treeNode = (TrieTreeNode*)malloc(sizeof(TrieTreeNode)); if (!treeNode) exit(0);
memset(treeNode->next, 0x00, sizeof(treeNode->next)); //所有的next都赋值为0
treeNode->cnt = 0;
return treeNode;
}
// 插入一个单词
int InsertTrieTreeNode(TrieTree *pT, char *str) {
int i, index;
TrieTreeNode *tempNode = *pT;
if(tempNode==NULL || str == NULL || str[0]=='\0') // Trie树带有一头结点
return 0;
// 遍历字符串,找到Trie中的位置
for(i=0; i<strlen(str) ;i++) {
if (str[i]>='0' && str[i]<='9') //数字
index = str[i] - '0'; //下标放在[0,9]
else if (str[i]>='a' && str[i]<='z') //字母
index = str[i] - 'a' + 10; //下标放在[10,36]
else {
printf("单词错误,有别的类型字符\n");
return 0;
}
// 往下走
if (tempNode->next[index] == NULL) { //还没有这个结点
tempNode->next[index] = createTrieTreeNode();
}
tempNode = tempNode->next[index]; //往下走
}
// 计数
tempNode->cnt = tempNode->cnt + 1;
return 0;
}
/*
* 搜索Trie树
* 存在返回个数
* 不存在返回0
*/
int SearchTrieTree(TrieTree T, char *str) {
int i, index;
TrieTreeNode *tempNode = T;
if(tempNode==NULL || str == NULL)
return 0;
//搜索
for(i=0; i<strlen(str); i++) {
if (str[i]>='0' && str[i]<='9') //数字
index = str[i] - '0'; //下标放在[0,9]
else if (str[i]>='a' && str[i]<='z') //字母
index = str[i] - 'a' + 10; //下标放在[10,36]
else {
printf("单词错误,有别的类型字符\n");
return 0;
}
if(tempNode->next[index] == NULL) { //走不下去了
return 0; //没找到
}
tempNode = tempNode->next[index];
}
return tempNode->cnt;
}
/*
* 删除单词
* 不存在返回0
* 存在返回删除后的个数
*/
int DeleteTrieTreeNode(TrieTree *pT, char *str) {
int i, index;
TrieTreeNode *tempNode = *pT;
if(tempNode==NULL || str == NULL)
return 0;
for(i=0; i<strlen(str); i++) {
if (str[i]>='0' && str[i]<='9') //数字
index = str[i] - '0'; //下标放在[0,9]
else if (str[i]>='a' && str[i]<='z') //字母
index = str[i] - 'a' + 10; //下标放在[10,36]
else {
printf("单词错误,有别的类型字符\n");
return 0;
}
if(tempNode->next[index] == NULL) {
return 0;
}
tempNode = tempNode->next[index];
}
tempNode->cnt = tempNode->cnt-1;
return tempNode->cnt;
}
// 遍历Trie树,使用静态变量,递归时可以记录之前一层上的字符
void TraverseTrieTree(TrieTree T) {
int i;
static char word[MAXSTRLEN+1] = {'\0'};
static int len=0;
if(T==NULL)
return;
for(i=0; i<37; i++) {
if (T->next[i]==NULL) {
continue;
}
// 赋值
if (i>=0 && i<=9) { //数字
word[len++] = i + '0';
} else { //字母
word[len++] = i - 10 + 'a';
}
// 如果这个字符串存在,输出
if(T->next[i]->cnt > 0) {
word[len] = '\0';
printf("%-20s %-8d\n", word, T->next[i]->cnt);
}
// 遍历下一个
TraverseTrieTree(T->next[i]);
len--;
}
}
/*销毁Trie树*/
void DestroyTrieTree(TrieTree *pT) {
int i;
if((*pT)==NULL)
return;
for(i=0; i<40; i++) {
if((*pT)->next[i] != NULL) {
DestroyTrieTree(&(*pT)->next[i]);
}
}
free(*pT); // 子节点全部删除
*pT = NULL;
}
int main() {
char word[1024+1] = {'\0'}; //存放读到的单词
char c;
int len;
TrieTree T = NULL;
FILE *fp;
T = createTrieTreeNode(); //创建Trie树
// 读入文件
fp = fopen("2013-8.txt", "r");
len = 0;
while ( fscanf(fp, "%c", &c)!=EOF ) {
if ( c>='0' && c<='9' ) { //数字
word[len++] = c;
} else if ( c>='a' && c<='z' ) { //小写字母
word[len++] = c;
} else if ( c>='A' && c<='Z') { //大写字母
word[len++] = c - 'A' + 'a'; //转成小写,考虑
} else { //其他字符
if (len==0) { //前面没有单词
continue; //继续
} else { //前面有单词
word[len] = '\0'; //附上结束串
//printf("- %s\n", word); //debug打印读取的字符串
InsertTrieTreeNode(&T, word); //插入Trie树
}
len =0;
}
}
fclose(fp);
// 输出全部单词的次数
TraverseTrieTree(T);
// 销毁
DestroyTrieTree(&T);
return 0;
}
可以参考一下,再加入一个数组存储你的重点单词,只统计重点单词里面的数据
如果是C++,相对比较容易,C的话,初学就算了。
用C++的hashmap存重点单词本,每个单词转小写。
结构是key:单词,value:个数,初始为0。
用file流顺序输入string,和hashmap中的key比较,相同则 value+=1。
完成所有输入后,进行forrange迭代,将所有键值对颠倒存入vector<pair<int,string>>,按大于逻辑sort一下。
forrange迭代输出即可。
C++有个问题,没有split,这个的实现要看具体文本的格式,并不容易。
#include<stdio.h>
main(){
char a[100],word[30];
int i=0,j,na=0,nw=0,count=0,sum=0;
while((a[i] = getchar()) != '\n'){//这里括号必须加,不然赋值优先级低于逻辑符号,数组里存的全是‘\0’
na++;
i++;
}
i=0;
rewind(stdin);
while((word[i] = getchar()) != '\n'){
nw++;
i++;
}
for (i = 0; i < na; i++)
{ count = 0;
if(a[i] == word[0]){//第一个字符匹配上了才继续匹配
for(j=0;j<nw;j++){
if(a[i+j] == word[j]){
count++;
}
}
if(count == nw)sum++;//匹配数=word的字符数那么匹配成功
}
}
printf("%d",sum);
}
类似聊天软件中的敏感词查找,可以使用trie tree
https://www.91dengdeng.cn/2020/07/03/%E6%95%8F%E6%84%9F%E8%AF%8D%E8%BF%87%E6%BB%A4/