• 双向循环链表(C语言描述)(四)


      下面以一个电子英汉词典程序(以下简称电子词典)为例,应用双向循环链表。分离数据结构,可以使逻辑代码独立于数据结构操作代码,程序结构更清晰,代码更简洁;电子词典的增、删、查、改操作分别对应于链表的插入、删除、查找、查找和获取链表元素操作。

      在程序初始化时,除了初始化链表,还要将保存在文件中的词库加载到链表中:

    1 void dict_init() {
    2     list = linkedlist_new();
    3 
    4     dict_load();
    5     printf("Welcome.");
    6 }

    函数dict_load()实现如下:

     1 static void dict_load() {
     2     FILE * fp;
     3     struct Word word;
     4 
     5     while (!(fp = fopen(PATH, "rb"))) {
     6         fp = fopen(PATH, "wb");
     7         fclose(fp);
     8     }
     9     assert(fp);
    10 
    11     fread(&word, sizeof(struct Word), 1, fp);
    12     while (!feof(fp)) {
    13         linkedlist_insert(list, TRAVELDIR_BACKWARD, 1, word);
    14         fread(&word, sizeof(struct Word), 1, fp);
    15     }
    16 
    17     fclose(fp);
    18 }

    函数feof()应先读后判断,所以在进入循环之前应先读一次。

      当然,在程序结束前,也要将链表中的词组保存到文件中,函数dict_store()实现如下:

     1 static void dict_store() {
     2     FILE * fp;
     3     const int count = linkedlist_length(list);
     4 
     5     assert(fp = fopen(PATH, "wb"));
     6     for (int i = 0; i < count; i++) {
     7         fwrite(linkedlist_get(list, TRAVELDIR_FORWARD, i + 1),
     8                 sizeof(struct Word), 1, fp);
     9     }
    10 
    11     fclose(fp);
    12 }

       一个英汉词组包含一个英文,一个中文,可以把它定义为一个结构体,并让它作为链表节点数据域的数据类型;修改linkedlist.h中LinkedlistData的相关定义:

    1 typedef struct Word {
    2     string eng;
    3     string chn;
    4 } LinkedListData;

    C语言中没有string类型,可以使用定长的字符数组来定义它;再定义一个函数mygets()用来代替scanf()函数,以确保输入的内容不会超过定义的字符串长度:

     1 #define MAX_STR_LEN 8
     2 typedef char string[MAX_STR_LEN];
     3 
     4 void mygets(char * s)
     5 {
     6     __fpurge(stdin);
     7     fgets(s, MAX_STR_LEN, stdin);
     8     while (*s++) {
     9         *s = *s == '
    ' ? 0 : *s;
    10     }
    11 }

    在Linux下,使用__fpurge()函数来代替Windows下的fflush()函数清空输入流。

       接下来就是电子词典的增、删、查、改操作:

     1 void dict_add(const char * eng) {
     2     struct Word word;
     3     strcpy(word.eng, eng);
     4 
     5     printf("The word does not exist, add it?
    y/n>");
     6     if (__fpurge(stdin), getchar() == 'y') {
     7         printf("Ok, what does it mean?
    >");
     8         mygets(word.chn);
     9 
    10         linkedlist_insert(list, TRAVELDIR_BACKWARD, 1, word);
    11         printf("The word is existed now.
    ");
    12     }
    13 }
    14 
    15 void dict_delete() {
    16     int location;
    17     struct Word word;
    18 
    19     printf("What word do you wanna delete?
    >");
    20     mygets(word.eng);
    21 
    22     if ((location = linkedlist_locate(list, TRAVELDIR_FORWARD, word, dict_cmp))
    23             != -1) {    // found
    24         struct Word * pWord = linkedlist_get(list, TRAVELDIR_FORWARD, location);
    25 
    26         printf("Delete: %s %s
    Are you sure?
    y/n>", pWord->eng, pWord->chn);
    27         if (__fpurge(stdin), getchar() == 'y') {
    28             linkedlist_delete(list, TRAVELDIR_FORWARD, location);
    29             printf("The word is deleted now.
    ");
    30         }
    31     } else {            // not found
    32         printf("The word does not exist.
    ");
    33     }
    34 }
    35 
    36 void dict_search(const char * eng) {
    37     int location;
    38     struct Word word;
    39     strcpy(word.eng, eng);
    40 
    41     if ((location = linkedlist_locate(list, TRAVELDIR_FORWARD, word, dict_cmp))
    42             == -1) {    // not found
    43         dict_add(eng);
    44     } else {            // found
    45         printf("%s
    ", linkedlist_get(list, TRAVELDIR_FORWARD, location)->chn);
    46     }
    47 }
    48 
    49 void dict_modify() {
    50     int location;
    51     struct Word word;
    52 
    53     printf("What word do you wanna modify?
    >");
    54     mygets(word.eng);
    55 
    56     if ((location = linkedlist_locate(list, TRAVELDIR_FORWARD, word, dict_cmp))
    57             != -1) {    // found
    58         struct Word * pWord = linkedlist_get(list, TRAVELDIR_FORWARD, location);
    59 
    60         printf("Ok, what does it mean?
    >");
    61         mygets(pWord->chn);
    62         printf("The word is modified now.
    ");
    63     } else {            // not found
    64         printf("The word does not exist.
    ");
    65     }
    66 }

    dict_cmp()函数作为参数传递给linkedlist_locate()函数,用以比较词组是否相同,相同则返回0,它的实现如下:

    1 int dict_cmp(const void * s1, const void * s2) {
    2     return strcmp(((LinkedListData *) s1)->eng, ((LinkedListData *) s2)->eng);
    3 }

    还需要一个函数来组织这些子函数的调用:

     1 void dict_show() {
     2     while (1) {
     3         string str;
     4         printf("
    >");
     5         mygets(str);
     6 
     7         if (!strcmp(str, "quit;")) {
     8             dict_store();
     9             linkedlist_destory(&list);
    10             printf("Bye.
    ");
    11             return;
    12         } else if (!strcmp(str, "delete;")) {
    13             dict_delete();
    14         } else if (!strcmp(str, "modify;")) {
    15             dict_modify();
    16         } else {
    17             dict_search(str);
    18         }
    19     }
    20 }

      最后,编写主函数,电子词典就大功告成了!

  • 相关阅读:
    背景透明的static控件
    MFC应用程序配置不正确解决方案
    #pragma once与 #ifndef的区别
    一种新颖的流程控制方式
    DbgView.exe的应用和使用类
    内存对齐的一点个人理解
    MFC下实现透明位图
    结束已知应用程序名的进程
    基本线程编程
    Linux下PCI设备驱动程序开发的经典文章
  • 原文地址:https://www.cnblogs.com/lets-blu/p/7213662.html
Copyright © 2020-2023  润新知