当前位置: 首页 > 知识库问答 >
问题:

c - 做一个建议的汉字输入法,在候选词数组中加入一个j指针记录在哈希表中的位置对汉字使用次数进行加权如何实现?

邹山
2023-06-10

#define MAX_PINYIN_LENGTH 20
#define MAX_RESULT_LENGTH 100
#define MAX_CANDIDATES 5

/*
这些是预处理指令,用于定义常量。
MAX_PINYIN_LENGTH 定义了拼音的最大长度,
MAX_RESULT_LENGTH 定义了汉字的最大长度,
MAX_CANDIDATES 定义了候选汉字的最大个数。
这样可以方便地在程序中使用这些常量,而不需要硬编码数字。
*/

typedef struct PinyinEntryNode {
    char pinyin[MAX_PINYIN_LENGTH];      // 存储拼音
    char hanzi[MAX_RESULT_LENGTH];       // 存储汉字
    int weight;                            //权代表输出次数 
    struct PinyinEntryNode* next;         // 下一个节点的指针
    struct PinyinEntryNode*prior;       
} PinyinEntryNode;

/* 这里定义了一个结构体 PinyinEntryNode,表示词库中的一个条目。
每个条目包含拼音和对应的汉字,以及一个指向下一个条目的指针。23.06.05*/

typedef struct {
    PinyinEntryNode* buckets[26];        // 拼音字母索引的哈希桶
} PinyinDictionary;

/*这里定义了一个结构体 PinyinDictionary,表示整个词库。
词库使用哈希表实现,包含了 26 个桶,每个桶存储一组具有相同首字母的拼音条目。
pinyinDict 是一个全局变量,表示实际的词库。23.06.05*/

PinyinDictionary pinyinDict;             // 拼音词典
PinyinEntryNode* candidate;
typedef struct candnode
{
    PinyinEntryNode* candidate;
    PinyinEntryNode**j;
}candnode;
candnode candidates[MAX_CANDIDATES];



// 插入词库条目
void insertEntry(PinyinDictionary* dict, const char* pinyin, const char* hanzi) {
    int index = pinyin[0] - 'a';         // 根据拼音首字母确定桶的索引
    PinyinEntryNode* newNode = (PinyinEntryNode*)malloc(sizeof(PinyinEntryNode));    // 创建新节点
    strncpy(newNode->pinyin, pinyin, MAX_PINYIN_LENGTH);     // 拷贝拼音字符串到节点
    strncpy(newNode->hanzi, hanzi, MAX_RESULT_LENGTH);       // 拷贝汉字字符串到节点
    newNode->next = dict->buckets[index];                    // 将新节点插入到桶的头部
    dict->buckets[index] = newNode;
}

/* insertEntry 函数用于向词库中插入一个新的拼音和汉字对应关系。
它接受词典指针 dict,以及要插入的拼音和汉字作为参数。
首先,根据拼音的首字母确定要插入的桶的索引。
然后,创建一个新的节点,并将拼音和汉字复制到节点中。
接下来,将新节点插入到桶的头部。 */

// 初始化词库
void initializeDictionary(PinyinDictionary* dict, const char* filename) {
    for (int i = 0; i < 26; i++) {
        dict->buckets[i] = NULL;         // 初始化所有桶为空
    }

    // 打开词库文件
    FILE* file = fopen(filename, "r");
    if (file == NULL) {
        printf("无法打开词库文件: %s\n", filename);
        return;
    }

/*此处,文件操作是至关重要的,请详细查阅C语言最后一章文件操作的主要方法,答辩会用。*/
 
    char line[MAX_PINYIN_LENGTH + MAX_RESULT_LENGTH];
    while (fgets(line, sizeof(line), file))
    {
        // 提取拼音和汉字
        char pinyin[MAX_PINYIN_LENGTH];
        char hanzi[MAX_RESULT_LENGTH];
        scanf(line, "%s %s", pinyin, hanzi);

        // 插入拼音和汉字对应关系到词典
        insertEntry(dict, pinyin, hanzi);
    }

    fclose(file);
}

/*  initializeDictionary 函数用于初始化词库。
它接受一个词典指针 dict 和词库文件名作为参数。
首先,将所有桶初始化为空指针。然后,打开词库文件。
如果文件无法打开,将输出错误信息并返回。
接下来,读取文件的每一行,提取拼音和汉字,
并调用 insertEntry 函数将其插入词库。最后,关闭文件。 */




// 保存词库到文件
void saveDictionary(const PinyinDictionary* dict, const char* filename) {
    FILE* file = fopen(filename, "w");
    if (file == NULL) {
        printf("无法打开词库文件: %s\n", filename);
        return;
    }

    // 遍历词典中的桶和节点,并将拼音和汉字写入文件
    for (int i = 0; i < 26; i++) {
        PinyinEntryNode* current = dict->buckets[i];
        while (current != NULL) {
            fprintf(file, "%s %s\n", current->pinyin, current->hanzi);
            current = current->next;
        }
    }

    fclose(file);
}
/*  saveDictionary 函数用于将词库保存到文件中。
它接受一个词典指针 dict 和文件名作为参数。
首先,打开文件以便写入。
如果文件无法打开,将输出错误信息并返回。
然后,遍历词库的所有桶和链表,
将每个条目的拼音和汉字写入文件中。最后,关闭文件。*/


// 查找与输入拼音匹配的候选汉字
candnode* findCandidates(const char* input, candnode*candidates, int* count) {
    int index = input[0] - 'a';             // 根据输入拼音的首字母确定桶的索引
    PinyinEntryNode* current = pinyinDict.buckets[index];     // 获取对应的桶头节点
    *count = 0;                             // 初始化候选汉字计数器为0

    // 遍历桶中的节点,查找匹配的拼音
    while (current != NULL && *count < MAX_CANDIDATES) {
        if (strncmp(input, current->pinyin, strlen(input)) == 0) 
        {
            candidates[*count].candidate= current;       // 找到匹配的拼音,将节点添加到候选汉字数组中
            candidates[*count].j=&current;
            (*count)++;                         // 候选汉字计数器加1
        }
        current = current->next;                // 移动到下一个节点
    }
    return candidates;
}

/*  findCandidates 函数用于查找与输入拼音匹配的候选汉字。
它接受一个输入拼音字符串 input,
一个指向候选节点指针数组的指针 candidates,
以及一个指向候选节点数量的指针 count。
首先,根据拼音的首字母确定要搜索的桶的索引。
然后,遍历该桶的链表,将与输入拼音匹配的节点添加到候选数组中,
同时更新候选节点数量。最多添加 MAX_CANDIDATES 个候选节点。  */


// 打印菜单选项
void printMenu() 
{
    printf("\n");
    printf("1. 输入拼音查找汉字(按选择次数优先显示)\n");
    printf("2. 添加新的拼音和汉字对应关系\n");
    printf("3. 保存词库到文件\n");
    printf("4. 退出程序\n");
    printf("请选择操作: ");
}

/*printMenu 函数用于打印菜单选项,这没啥好说的,比较简单。*/ 

/*以下函数是main部分,请慢慢看!不理解的发消息问我*/
 
int main()
{

    char input[MAX_PINYIN_LENGTH];
    int choice;

    // 初始化词库
    initializeDictionary(&pinyinDict, "dictionary.txt");

    do {
        printMenu();
        scanf("%d", &choice);

        switch (choice) 
        {
            case 1: {
                printf("请输入拼音: ");
                scanf("%s", input);

                int count = 0;//记录候选字的序号 

                // 查找候选汉字
                findCandidates(input, candidates, &count);  

                if (count == 0)
                 {
                    printf("找不到与输入拼音 '%s' 对应的汉字\n", input);
                } 
                else 
                {
                    printf("输入的拼音 '%s' 对应的候选汉字如下:\n", input);
                    for (int i = 0; i < count; i++) 
                    {
                        printf("%d. %s\n", i + 1, candidates[i].candidate->hanzi);
                    }

                    printf("请选择候选词的序号: ");
                    int choice;
                    scanf("%d", &choice);

                    if (choice >= 1 && choice <= count) {
                        printf("选择的候选汉字为: %s\n", candidates[choice - 1].candidate->hanzi);
                        (*candidates[choice-1].j)->weight++;
                        printf("%o",(**candidates[choice-1].j).weight);
                        // 在这里进行汉字的输出操作,可以是将选中的汉字插入到正在编辑的文本中
                    } else
                    {
                        printf("无效的选择\n");
                    }
                }

                break;
            }
            /*
            这里用了5层嵌套循环,会有点复杂,但多看看,不是很难。
            在这个分支case1中,首先提示用户输入拼音。然后,声明一个数组 candidates,
            用于存储候选汉字的指针,并初始化候选汉字的数量 count 为 0。
            接下来,调用 findCandidates 函数来查找与输入拼音匹配的候选汉字。
            这个函数的作用已在之前的解释中详细说明过。
            如果找不到与输入拼音匹配的候选汉字,输出提示信息。
            否则,打印出输入拼音对应的候选汉字列表。
            通过循环遍历 candidates 数组,并打印每个候选汉字的序号和汉字内容。
            然后,提示用户选择候选词的序号,并接收用户的输入。
            如果用户输入的选择序号有效,
            即大于等于 1 且小于等于候选汉字的数量 count,则输出选择的候选汉字。
            在注释的最后,提示在这里可以进行汉字的输出操作,
            例如将选中的汉字插入到正在编辑的文本中。这部分的具体实现将根据具体的应用场景来确定。
            最后,在 case 1 分支的末尾使用 break 语句来跳出 switch 语句的当前分支。
            */
             
            case 2: {
                char newPinyin[MAX_PINYIN_LENGTH];
                char newHanzi[MAX_RESULT_LENGTH];

                printf("请输入新的拼音: ");
                scanf("%s", newPinyin);
                printf("请输入新的汉字: ");
                scanf("%s", newHanzi);

                // 添加新的拼音和汉字对应关系
                insertEntry(&pinyinDict, newPinyin, newHanzi);

                printf("成功添加新的拼音和汉字对应关系\n");
                break;
            }
            
            /*
            在这个分支case2中,首先声明两个字符数组 newPinyin 和 newHanzi,
            分别用于存储用户输入的新拼音和汉字。
            然后,通过 printf 提示用户输入新的拼音,
            并使用 scanf 接收用户输入并存储到 newPinyin 数组中。
            接着,通过 printf 提示用户输入新的汉字,
            并使用 scanf 接收用户输入并存储到 newHanzi 数组中。
            最后,调用 insertEntry 函数,将新的拼音和汉字对应关系插入到词库中。
            这个函数的作用是在词库中创建一个新的节点,并将新拼音和汉字存储到节点中。
            完成插入操作后,输出成功添加新的拼音和汉字对应关系的提示信息。
            在注释的最后,使用 break 语句来跳出 switch 语句的当前分支。
            */
            
            case 3: {
                // 保存词库到文件
                saveDictionary(&pinyinDict, "dictionary.txt");
                printf("成功保存词库到文件\n");
                break;
            }
            case 4:
                printf("程序已退出\n");
                break;

            
        }
    } while (choice != 4);

    return 0;
}

共有1个答案

贺刚毅
2023-06-10

这个加权功能可以改 findCandidates 来实现。先找到所有与输入拼音匹配的候选汉字,然后根据这些候选汉字的权重进行排序,最后返回排序后的候选汉字。

 类似资料: