开篇
今天的问题,是在之前变位词程序的基础上,进行了一些拓展。问题来源于《编程珠玑》第2章,课后习题1。
问题概要
考虑查找给定输入单词的所有变位词问题,仅给定单词和字典的情况下,如何解决该问题?如果有一些时间和空间可以在响应任何查询之前预先处理字典,又会如何?
思路分析
我们把上面的问题,分别分为问题1和问题2。其中问题1对应下面思路分析1,以及代码实现:不允许预处理版本。问题2对应下面问题思路2,以及代码实现:可预处理版本。
思路分析1:为了找出给定单词的所有变位词,我们首先计算它的标识。如果不允许预处理,那么我们只能顺序的读取整个字典,计算每个单词的标识并比较两个标识。
思路分析2: 如果允许进行预处理,我们可以在一个预先计算好的结构中执行二分搜索,该结构包含按标识排序的(标识,单词)对。
代码实现
代码实现:不允许预处理版本
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define MAX_WORD_LENGTH 100
// 函数原型声明
void sortString(char *str);
int isAnagram(char *word1, char *word2);
int main() {
char word[MAX_WORD_LENGTH]; // 存储输入的单词
char dictWord[MAX_WORD_LENGTH]; // 用于存储从文件读取的单词
FILE *dictFile, *outputFile;
printf("Enter the word: ");
scanf("%s", word);
sortString(word); // 对输入单词排序,作为后续比较的基准
dictFile = fopen("dictionary.txt", "r");
if (dictFile == NULL) {
perror("Error opening dictionary file");
return 1;
}
outputFile = fopen("word.txt", "w");
if (outputFile == NULL) {
perror("Error opening output file");
fclose(dictFile);
return 1;
}
while (fgets(dictWord, MAX_WORD_LENGTH, dictFile) != NULL) {
// 删除读取的单词末尾的换行符
dictWord[strcspn(dictWord, "\n")] = 0;
if (isAnagram(word, dictWord)) {
fprintf(outputFile, "%s\n", dictWord);
}
}
fclose(dictFile);
fclose(outputFile);
printf("Anagrams have been written to word.txt\n");
return 0;
}
// 字符串排序函数,用于生成单词的标识
void sortString(char *str) {
int length = strlen(str);
int i, j;
for (i = 0; i < length - 1; i++) {
for (j = i + 1; j < length; j++) {
if (str[i] > str[j]) {
char temp = str[i];
str[i] = str[j];
str[j] = temp;
}
}
}
}
// 检查两个单词是否为变位词
int isAnagram(char *word1, char *word2) {
char temp1[MAX_WORD_LENGTH];
char temp2[MAX_WORD_LENGTH];
strcpy(temp1, word1);
strcpy(temp2, word2);
sortString(temp1);
sortString(temp2);
return strcmp(temp1, temp2) == 0;
}
代码实现: 可预处理版本
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define MAX_WORD_LENGTH 100
#define DICTIONARY_SIZE 1000
typedef struct {
char identifier[MAX_WORD_LENGTH];
char word[MAX_WORD_LENGTH];
} WordEntry;
WordEntry dictionary[DICTIONARY_SIZE];
int dictSize = 0;
// 函数原型声明
void sortString(char *str);
int compareWordEntry(const void *a, const void *b);
void loadDictionary(const char *filename);
void findAnagrams(const char *word, const char *outputFilename);
int binarySearchForAnagram(const char *identifier, int low, int high);
int main() {
loadDictionary("dictionary.txt");
qsort(dictionary, dictSize, sizeof(WordEntry), compareWordEntry);
char word[MAX_WORD_LENGTH];
printf("请输入目标单词: ");
scanf("%s", word);
findAnagrams(word, "anagrams.txt");
return 0;
}
// 加载字典文件
void loadDictionary(const char *filename) {
FILE *file = fopen(filename, "r");
if (!file) {
perror("打开字典文件失败!");
exit(1);
}
while (fgets(dictionary[dictSize].word, MAX_WORD_LENGTH, file)) {
dictionary[dictSize].word[strcspn(dictionary[dictSize].word, "\n")] = '\0';
strcpy(dictionary[dictSize].identifier, dictionary[dictSize].word);
sortString(dictionary[dictSize].identifier);
if (++dictSize >= DICTIONARY_SIZE) {
break;
}
}
fclose(file);
}
// 查找变位词
void findAnagrams(const char *word, const char *outputFilename) {
char wordIdentifier[MAX_WORD_LENGTH];
strcpy(wordIdentifier, word);
sortString(wordIdentifier);
FILE *outputFile = fopen(outputFilename, "w");
if (!outputFile) {
perror("打开输出文件失败!");
exit(1);
}
int index = binarySearchForAnagram(wordIdentifier, 0, dictSize - 1);
while (index >= 0 && index < dictSize && strcmp(dictionary[index].identifier, wordIdentifier) == 0) {
fprintf(outputFile, "%s\n", dictionary[index].word);
index++;
}
fclose(outputFile);
}
// 二分查找
int binarySearchForAnagram(const char *identifier, int low, int high) {
while (low <= high) {
int mid = low + (high - low) / 2;
int res = strcmp(identifier, dictionary[mid].identifier);
if (res == 0) {
while (mid > low && strcmp(dictionary[mid - 1].identifier, identifier) == 0) {
mid--;
}
return mid;
} else if (res < 0) {
high = mid - 1;
} else {
low = mid + 1;
}
}
return -1;
}
// 排序,以便给单词增加标识
void sortString(char *str) {
int length = strlen(str);
int i, j;
for (i = 0; i < length - 1; i++) {
for (j = i + 1; j < length; j++) {
if (str[i] > str[j]) {
char temp = str[i];
str[i] = str[j];
str[j] = temp;
}
}
}
}
// 比较
int compareWordEntry(const void *a, const void *b) {
const WordEntry *entryA = (const WordEntry *)a;
const WordEntry *entryB = (const WordEntry *)b;
return strcmp(entryA->identifier, entryB->identifier);
}
注
以上便是变位词程序拓展问题的实现。因个人能力问题,代码若有不合理之处,还请指正。