1. 程式人生 > >雙向循環鏈表(C語言描述)(四)

雙向循環鏈表(C語言描述)(四)

雙向循環鏈表 還要 ons 函數 保存 hat 加載 dir dict

  下面以一個電子英漢詞典程序(以下簡稱電子詞典)為例,應用雙向循環鏈表。分離數據結構,可以使邏輯代碼獨立於數據結構操作代碼,程序結構更清晰,代碼更簡潔;電子詞典的增、刪、查、改操作分別對應於鏈表的插入、刪除、查找、查找和獲取鏈表元素操作。

  在程序初始化時,除了初始化鏈表,還要將保存在文件中的詞庫加載到鏈表中:

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 }

  最後,編寫主函數,電子詞典就大功告成了!

雙向循環鏈表(C語言描述)(四)