1. 程式人生 > >資料結構之單鏈表

資料結構之單鏈表

從今天起開始資料結構系列的分享,今天分享的是單鏈表。單鏈表大概是大概是每個資料結構 初學者的必經之路,下面結合一個小小的工程深入學習單鏈表的使用–簡易客戶管理系統。 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 如有疑問,歡迎進群討論: 資料結構與演算法交流群