下面以一个电子英汉词典程序(以下简称电子词典)为例,应用双向循环链表。分离数据结构,可以使逻辑代码独立于数据结构操作代码,程序结构更清晰,代码更简洁;电子词典的增、删、查、改操作分别对应于链表的插入、删除、查找、查找和获取链表元素操作。
在程序初始化时,除了初始化链表,还要将保存在文件中的词库加载到链表中:
void dict_init() {
list = linkedlist_new(); dict_load();
printf("Welcome.");
}
函数dict_load()实现如下:
static void dict_load() {
FILE * fp;
struct Word word; while (!(fp = fopen(PATH, "rb"))) {
fp = fopen(PATH, "wb");
fclose(fp);
}
assert(fp); fread(&word, sizeof(struct Word), , fp);
while (!feof(fp)) {
linkedlist_insert(list, TRAVELDIR_BACKWARD, , word);
fread(&word, sizeof(struct Word), , fp);
} fclose(fp);
}
函数feof()应先读后判断,所以在进入循环之前应先读一次。
当然,在程序结束前,也要将链表中的词组保存到文件中,函数dict_store()实现如下:
static void dict_store() {
FILE * fp;
const int count = linkedlist_length(list); assert(fp = fopen(PATH, "wb"));
for (int i = ; i < count; i++) {
fwrite(linkedlist_get(list, TRAVELDIR_FORWARD, i + ),
sizeof(struct Word), , fp);
} fclose(fp);
}
一个英汉词组包含一个英文,一个中文,可以把它定义为一个结构体,并让它作为链表节点数据域的数据类型;修改linkedlist.h中LinkedlistData的相关定义:
typedef struct Word {
string eng;
string chn;
} LinkedListData;
C语言中没有string类型,可以使用定长的字符数组来定义它;再定义一个函数mygets()用来代替scanf()函数,以确保输入的内容不会超过定义的字符串长度:
#define MAX_STR_LEN 8
typedef char string[MAX_STR_LEN]; void mygets(char * s)
{
__fpurge(stdin);
fgets(s, MAX_STR_LEN, stdin);
while (*s++) {
*s = *s == '\n' ? : *s;
}
}
在Linux下,使用__fpurge()函数来代替Windows下的fflush()函数清空输入流。
接下来就是电子词典的增、删、查、改操作:
void dict_add(const char * eng) {
struct Word word;
strcpy(word.eng, eng); printf("The word does not exist, add it?\ny/n>");
if (__fpurge(stdin), getchar() == 'y') {
printf("Ok, what does it mean?\n>");
mygets(word.chn); linkedlist_insert(list, TRAVELDIR_BACKWARD, , word);
printf("The word is existed now.\n");
}
} void dict_delete() {
int location;
struct Word word; printf("What word do you wanna delete?\n>");
mygets(word.eng); if ((location = linkedlist_locate(list, TRAVELDIR_FORWARD, word, dict_cmp))
!= -) { // found
struct Word * pWord = linkedlist_get(list, TRAVELDIR_FORWARD, location); printf("Delete: %s %s\nAre you sure?\ny/n>", pWord->eng, pWord->chn);
if (__fpurge(stdin), getchar() == 'y') {
linkedlist_delete(list, TRAVELDIR_FORWARD, location);
printf("The word is deleted now.\n");
}
} else { // not found
printf("The word does not exist.\n");
}
} void dict_search(const char * eng) {
int location;
struct Word word;
strcpy(word.eng, eng); if ((location = linkedlist_locate(list, TRAVELDIR_FORWARD, word, dict_cmp))
== -) { // not found
dict_add(eng);
} else { // found
printf("%s\n", linkedlist_get(list, TRAVELDIR_FORWARD, location)->chn);
}
} void dict_modify() {
int location;
struct Word word; printf("What word do you wanna modify?\n>");
mygets(word.eng); if ((location = linkedlist_locate(list, TRAVELDIR_FORWARD, word, dict_cmp))
!= -) { // found
struct Word * pWord = linkedlist_get(list, TRAVELDIR_FORWARD, location); printf("Ok, what does it mean?\n>");
mygets(pWord->chn);
printf("The word is modified now.\n");
} else { // not found
printf("The word does not exist.\n");
}
}
dict_cmp()函数作为参数传递给linkedlist_locate()函数,用以比较词组是否相同,相同则返回0,它的实现如下:
int dict_cmp(const void * s1, const void * s2) {
return strcmp(((LinkedListData *) s1)->eng, ((LinkedListData *) s2)->eng);
}
还需要一个函数来组织这些子函数的调用:
void dict_show() {
while () {
string str;
printf("\n>");
mygets(str); if (!strcmp(str, "quit;")) {
dict_store();
linkedlist_destory(&list);
printf("Bye.\n");
return;
} else if (!strcmp(str, "delete;")) {
dict_delete();
} else if (!strcmp(str, "modify;")) {
dict_modify();
} else {
dict_search(str);
}
}
}
最后,编写主函数,电子词典就大功告成了!