title: 数据结构之单链表
copyright: true
date: 2018-09-12 14:34:18
tags: 数据结构
categories: 数据结构
从今天起开始数据结构系列的分享,今天分享的是单链表。单链表大概是大概是每个数据结构
初学者的必经之路,下面结合一个小小的工程深入学习单链表的使用–简易客户管理系统。
ps:如果还不清楚单链表是什么的小伙伴自行百度,在此不在赘述
#项目结构
增删改查,增、删、改这三个部分同时包含了将变动后的信息写入到文件中的操作
#代码编写
##项目基础代码
俗话说得好,“万丈高楼平地起”,先来编写项目的预定义代码部分,主要是头文件
包含、结构体定义、全局变量定义等
###头文件包含
#include<stdio.h> //C程序基础库
#include<stdlib.h> //包含函数exit()
#include<string.h> //包含函数strcmp()
###结构体定义
typedef struct item{ char name[20]; //保存客户姓名 char gender[20]; //保存客户性别 int age; //保存客户年龄 char tel[20]; //保存客户号码 } guest;
结构体定义不要多说了哈,这里typedef...guest
是给结构体item起别名的意思,也就是
struct item
在这个源文件里面等价于guest
typedef struct node { guest data; //数据域 struct node * next; //指针域 }* link;
这里是给指向结构体node的指针起别名
###全局变量定义
link T;//头指针
这个头指针T是整个系统的索引,六个模块共有一个,虽然有尽量少定义全局变量的原则,但这里
的全局变量T可以避免各个函数间复杂的参数传递问题,牺牲了空间,换取了运行时间的减少;
同时要注意我在后面对T的初始化代码
//初始化头指针 T=(link)malloc(sizeof(struct node)); T->next = NULL;
这里并没有给T安排数据域,T不是第一个存储客户信息的节点指针,T->next才是,初始化头指针
时还没有存储客户信息的结点加入,所以T->next=NULL;
,这是一个编程者应该养成的好习惯;为
什么不给T安排数据域呢,这里主要考虑到后面的删除模块的编写,我们知道,删除一个结点,要先
找到这个结点的前驱指针p和后驱指针q,然后p->next = q->next;
,如果给T安排数据域的话,
T的前驱是什么呢?就算不用上面我说的那套删除逻辑,用if...else...
语句和另外一套逻辑
完成对T的删除,代码明显复杂些。
##项目核心代码
###一、加载文件
代码如下
void init() { link p,s; FILE *fp; int i = 0; s = p=(link)malloc(sizeof(struct node)); p->next = NULL; if((fp=fopen("1.txt","r"))==NULL) { printf("load error!"); exit(1); } while(!feof(fp)) { fscanf(fp,"%s\t%s\t%d\t%s\t\n",p->data.name,p->data.gender,&p->data.age,p->data.tel); i++; if(i!=1) { s->next = p; s=p; } else{ T->next = p; } p=(link)malloc(sizeof(struct node)); p->next = NULL; } printf("总人数i=====%d\n",i); if(fclose(fp)) { printf("Can't close the file!\n"); exit(1); } }
介绍下代码逻辑,新开辟内存空间,并使s、p指向它,打开文件,如果文件指针没有到文件尾,将
从文件读取到的一个客户信息赋给p的数据域,如果是读取第一个客户信息,将p指向的结点连在头
指针T后面,否则,将p连在s后面,因为这个时候s是p的前驱指针,连接成功后将p赋值给s,p又
指向一个新开辟的结点…
###二、增加客户
代码如下:
//添加 void create() { link p,s; FILE *fp; int yn; s=T; while(s->next!=NULL) { s=s->next; } do { p=(link)malloc(sizeof(struct node)); printf("请输入客户姓名:\n"); scanf("%s",p->data.name); printf("请输入客户性别:\n"); scanf("%s",p->data.gender); printf("请输入客户年龄:\n"); scanf("%d",&p->data.age); printf("请输入客户联系方式:\n"); scanf("%s",p->data.tel); p->next=NULL; s->next=p; s=p; if((fp=fopen("1.txt","at"))==NULL) { printf("write error!\n"); exit(0); } printf("写了一次\n"); fprintf(fp,"%s\t%s\t%d\t%s\n",p->data.name,p->data.gender,p->data.age,p->data.tel); if(fclose(fp)) { printf("can't close the file!\n"); exit(0); } printf("添加成功!\n"); printf("是否继续添加请输入0或1:"); scanf("%d",&yn); } while(yn); }
代码逻辑很简单,新增结点,并连在尾节点后面,同时写入文件,如果前一片代码看懂了,这不是什么
大问题…
###三、删除客户
代码如下
//删除 int del() { link p,q; FILE *fp; char mod[25]; printf("请输入需要删除的客户名称:\n"); scanf("%s",mod); p=T; while(p->next!=NULL&&strcmp(p->next->data.name,mod)!=0) p=p->next; if(p->next==NULL) { printf("并无此人!\n"); return 0; } q = p; p = p->next; q->next = p->next; delete(p); printf("删除成功!\n"); if((fp=fopen("1.txt","wt"))==NULL) { printf("error!\n"); exit(0); } p=T->next; while(p!=NULL) { printf("%s",p->data.name); fprintf(fp,"%s\t%s\t%d\t%s\t\n",p->data.name,p->data.gender,p->data.age,p->data.tel); p = p->next; } if(fclose(fp)) { printf("can't close the file!\n"); exit(1); } }
模块三、四、五、六道理类似,不再赘述
附上代码地址:
github 欢迎star
如有疑问,欢迎进群讨论: