C语言实现:变位词程序拓展问题

发布于:2024-03-30 ⋅ 阅读:(56) ⋅ 点赞:(0)

开篇

今天的问题,是在之前变位词程序的基础上,进行了一些拓展。问题来源于《编程珠玑》第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);
}

以上便是变位词程序拓展问题的实现。因个人能力问题,代码若有不合理之处,还请指正。


网站公告

今日签到

点亮在社区的每一天
去签到