双向循环链表(C语言描述)(四)
下面以一个电子英汉词典程序(以下简称电子词典)为例,应用双向循环链表。分离数据结构,可以使逻辑代码独立于数据结构操作代码,程序结构更清晰,代码更简洁;电子词典的增、删、查、改操作分别对应于链表的插入、删除、查找、查找和获取链表元素操作。
在程序初始化时,除了初始化链表,还要将保存在文件中的词库加载到链表中:
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);
}
}
}
最后,编写主函数,电子词典就大功告成了!
双向循环链表(C语言描述)(四)的更多相关文章
- 一种神奇的双向循环链表C语言实现
最近在看ucore操作系统的实验指导.里面提要一个双向循环链表的数据结构,挺有意思的. 其实这个数据结构本身并不复杂.在普通链表的基础上加一个前向指针,我们就得到了双向链表,再把头尾节点连起来就是双向 ...
- 带头结点的双向循环链表----------C语言
/***************************************************** Author:Simon_Kly Version:0.1 Date: 20170520 D ...
- (C语言版)链表(四)——实现双向循环链表创建、插入、删除、释放内存等简单操作
双向循环链表是基于双向链表的基础上实现的,和双向链表的操作差不多,唯一的区别就是它是个循环的链表,通过每个节点的两个指针把它们扣在一起组成一个环状.所以呢,每个节点都有前驱节点和后继节点(包括头节点和 ...
- 双向循环链表(C语言描述)(一)
双向循环链表是链表的一种,它的每个节点也包含数据域和指针域.为了方便程序维护,可以单独为数据域定义一种数据类型,这里以整型为例: typedef int LinkedListData; 双向循环链表( ...
- C语言通用双向循环链表操作函数集
说明 相比Linux内核链表宿主结构可有多个链表结构的优点,本函数集侧重封装性和易用性,而灵活性和效率有所降低. 可基于该函数集方便地构造栈或队列集. 本函数集暂未考虑并发保护. 一 ...
- 【C语言教程】“双向循环链表”学习总结和C语言代码实现!
双向循环链表 定义 双向循环链表和它名字的表意一样,就是把双向链表的两头连接,使其成为了一个环状链表.只需要将表中最后一个节点的next指针指向头节点,头节点的prior指针指向尾节点,链表就能成环儿 ...
- 1.Go语言copy函数、sort排序、双向链表、list操作和双向循环链表
1.1.copy函数 通过copy函数可以把一个切片内容复制到另一个切片中 (1)把长切片拷贝到短切片中 package main import "fmt" func main() ...
- c语言编程之双向循环链表
双向循环链表就是形成两个环,注意每个环的首尾相连基本就可以了. 程序中采用尾插法进行添加节点. #include<stdio.h> #include<stdlib.h> #de ...
- 双向循环链表涉及双向指针的基本操作(C语言)
链表大概分为有无头指针,有无尾指针,是否循环,单向还是双向, 这些都很简单,前提是你要把指针和单链表理解透彻.这些都是基于单链表 的变形,要根据实际问题,选择链表的类型. 头指针的指针域储存着储存头节 ...
随机推荐
- 当mysql遇上PHP
博客提纲 利用PHP连接mySQL数据库 两套接口:面向对象和面向过程 实现写改删查(CUBD)实例 通过prepare语句处理相同类型的不同SQL语句 通过bind_param()绑定参数,及相关注 ...
- C++ type_traits 原理
一.简单介绍 (1).type_traits 类型萃取,C++11中已结成为了一个核心模块. (2).标准库包括helper classes .type traits.type transformat ...
- TCP连接中time_wait在开发中的影响-搜人以鱼不如授之以渔
根据TCP协议定义的3次握手断开连接规定,发起socket主动关闭的一方socket将进入TIME_WAIT状态,TIME_WAIT状态将持续2个MSL(Max Segment Lifetime),T ...
- 用awk写递归
看到自己很多年前写的一篇帖子,觉得有些意义,转录过来,稍加修改. awk是一种脚本语言,语法接近C语言,我比较喜欢用,gawk甚至可以支持tcp/ip,用起来非常方便. awk也支持递归,只是awk不 ...
- Linux10分钟入门
最近打算考红帽认证,将自己学习到的和工作中常用的一些命令进行总结,供初学者和一定基础的参考. 想系统性学习的话,还是建议看书(鸟哥的Linux私房菜)和看视频(基础版,推荐马哥和老男孩,不推荐**** ...
- org.apache.jasper.JasperException: - Page directive must not have multiple occurrences of pageencoding
最近写jsp遇到一系列的低级错误,记录下来权当前车之鉴吧. 错误提示: SEVERE: Servlet.service() for servlet jsp threw exceptionorg.apa ...
- 虚函数&多态
对于经常被问到的虚函数和多态的问题,发现百度百科回答得十分详细,所以自己在百度百科上的解释进行总结 一.虚函数 (1)虚函数简介:在某基类中声明为virtual并在一个或者多个派生类中被重新定义的成员 ...
- es6知识总结--3
es6知识总结--3 es6对咱们es3,es5的数据类型进行了升级下边说新APIs! js数据类型有Number.String .oject.Boolean.Null.Undefined六种数据类型 ...
- [TYVJ1728/BZOJ3224]普通平衡树-替罪羊树
Problem 普通平衡树 Solution 本题是裸的二叉平衡树.有很多种方法可以实现.这里打的是替罪羊树模板. 此题极其恶心. 前驱后继模块需要利用到rank模块来换一种思路求. 很多细节的地方容 ...
- input输入框自动填充黄色背景解决方案
chrome表单自动填充后,input文本框的背景会变成偏黄色的,这是由于chrome会默认给自动填充的input表单加上input:-webkit-autofill私有属性,然后对其赋予以下样式: ...