双向循环链表(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 == '\n' ? 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?\ny/n>");
 6     if (__fpurge(stdin), getchar() == 'y') {
 7         printf("Ok, what does it mean?\n>");
 8         mygets(word.chn);
 9 
10         linkedlist_insert(list, TRAVELDIR_BACKWARD, 1, word);
11         printf("The word is existed now.\n");
12     }
13 }
14 
15 void dict_delete() {
16     int location;
17     struct Word word;
18 
19     printf("What word do you wanna delete?\n>");
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\nAre you sure?\ny/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.\n");
30         }
31     } else {            // not found
32         printf("The word does not exist.\n");
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\n", 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?\n>");
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?\n>");
61         mygets(pWord->chn);
62         printf("The word is modified now.\n");
63     } else {            // not found
64         printf("The word does not exist.\n");
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("\n>");
 5         mygets(str);
 6 
 7         if (!strcmp(str, "quit;")) {
 8             dict_store();
 9             linkedlist_destory(&list);
10             printf("Bye.\n");
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 }

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

优质内容筛选与推荐>>
1、java中的锁
2、设计模式
3、[zt]Apache2.2中配置虚拟子域名(虚拟二级,三级域名等)
4、JS运动效果(包含一套完整的运动框架和一个简单的运动实例,小幻灯片)
5、让editText不自动获得焦点


长按二维码向我转账

受苹果公司新规定影响,微信 iOS 版的赞赏功能被关闭,可通过二维码转账支持公众号。

    阅读
    好看
    已推荐到看一看
    你的朋友可以在“发现”-“看一看”看到你认为好看的文章。
    已取消,“好看”想法已同步删除
    已推荐到看一看 和朋友分享想法
    最多200字,当前共 发送

    已发送

    朋友将在看一看看到

    确定
    分享你的想法...
    取消

    分享想法到看一看

    确定
    最多200字,当前共

    发送中

    网络异常,请稍后重试

    微信扫一扫
    关注该公众号





    联系我们

    欢迎来到TinyMind。

    关于TinyMind的内容或商务合作、网站建议,举报不良信息等均可联系我们。

    TinyMind客服邮箱:support@tinymind.net.cn