数据结构之单链表

从今天起开始数据结构系列的分享,今天分享的是单链表。单链表大概是大概是每个数据结构
初学者的必经之路,下面结合一个小小的工程深入学习单链表的使用–简易客户管理系统。
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
如有疑问,欢迎进群讨论:
数据结构之单链表