基於單連結串列的班級通訊錄

_liyong發表於2020-12-17

需求分析
將全班同學的通訊資訊存入一個順序表。元素中的通訊資訊包括每一位同學的:學號、姓名、性別、宿舍、聯絡電話等。要求能夠利用姓名和序號進行有關查詢、插入、刪除、更新等操作。
(1)以順序表作為儲存班級通訊錄的儲存結構,首先需要定義一個順序表資料結構,其中每個元素是一條同學通訊資訊,包括學號、姓名、性別、宿舍、聯絡電話等欄位。
(2)將本班的通訊資訊輸入文字檔案“通訊錄.txt”中,需要實現檔案讀寫功能。當程式啟動時,需要將檔案中的資訊讀入順序表中,當程式結束時,需要將記憶體中的通訊錄順序表中的資訊重新寫入檔案。
(3)需要實現向順序表中追加一條通訊錄記錄的功能,即順序表的插入功能。通過提示資訊,讓使用者將一條通訊錄記錄的各個欄位資訊輸入記憶體,構成一個順序表元素,然後將其作為一個整體插入順序表最後一條記錄之後,該功能在讀取檔案資訊,建立順序表是也需要用到。
(4)需要實現查詢功能,包括通過姓名查詢:給定一個姓名,返回其通訊資訊和在表中的位置;通過序號查詢:給定一個姓名,返回其通訊資訊和在表中的位置。
(5)需要實現在給定位置增加一條記錄的功能,該位置可以直接設定,也可以通過查詢得到,比如先查到姓名為“XXX”的學生的通訊資訊在表中的位置,然後在該記錄的後面插入一條新的記錄。
(6)需要實現刪除給定位置記錄的功能,該位置可以直接設定,也可以通過查詢得到,比如先查到姓名為“XXX”的學生的通訊資訊在表中的位置,然後將該記錄刪除之。

詳細設計

#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#define OK     1
#define ERROR  0
#define MAX    100
typedef int Status;
typedef char ElemType;
//結點定義
typedef struct telebook    //通訊錄結點資料域
{
    char num[MAX];         //學號
    char name[MAX];        //姓名
    char sex[MAX];         //性別
    char hostel[MAX];      //宿舍
    char telephone[MAX];   //電話號碼
}telebook;

typedef struct LNode      //連結串列結點
{
    telebook data; //結點資料域
    struct LNode* next;  //結點指標域
}LNode, * LinkList;

void readFile(LinkList& L);//讀取文字資訊
Status  InitList_L(LinkList& L);//單連結串列的初始化
void Find_Name(LinkList& L); //按姓名查詢
void Find_Num(LinkList& L); //按姓名查詢
Status  CreateFromTail(LinkList& L);     //採用尾插法在尾部插入元素
Status ListInsert_L(LinkList& L);//在單鏈線性表L的第i個元素之前插入元素
Status ListInsert_LName(LinkList& L);//在單鏈線性表L的姓名元素之前插入元素
Status Fund_LName(LinkList& L);  //尋找該姓名的位置
Status ListDelete_L(LinkList& L);//刪除第i個元素
Status ListDelete_LName(LinkList& L);   //刪除姓名為“XXX”的學生記錄
void saveFile(LinkList& L);  //儲存通訊錄到檔案
void PrintElem(LinkList L);//列印出所有元素
void List_free(LinkList L);  //銷燬連結串列

Status  InitList_L(LinkList& L)//單連結串列的初始化
{
    L = (LNode*)malloc(sizeof(LNode));   //申請結點空間
    if (L == NULL)                       //判斷是否有足夠的記憶體空間
        printf("申請記憶體空間失敗\n");
    L->next = NULL;                  //將next設定為NULL,初始長度為0的單連結串列
    return OK;
}

void readFile(LinkList& L)          //讀取檔案資訊
{
    LinkList q, p;
    FILE* fp;
    p = L;
    q = (LNode*)malloc(sizeof(LNode));
    char name[20] = "通訊錄.txt";
    if ((fp = fopen(name, "r")) == NULL)
    {
        printf("error\n");
        exit(0);
    }
    while (p->next != NULL)
    {
        p = p->next;
    }
    while (fscanf(fp, "%s%s%s%s%s\n", q->data.num, q->data.name, q->data.sex, q->data.hostel, q->data.telephone) != EOF)
    {
        q->next = NULL;
        p->next = q;
        p = q;
        q = (LNode*)malloc(sizeof(LNode));
    }
    printf("          檔案讀取成功!       \n");
    fclose(fp);
}

void Find_Name(LinkList& L) //按姓名查詢
{
    LinkList q, p;
    q = L->next;
    printf("輸入要查詢的姓名:\n");
    p = (LNode*)malloc(sizeof(LNode));
    scanf("%s", p->data.name);
    while (q != NULL && strcmp(q->data.name, p->data.name) != 0)
    {
        q = q->next;
    }
    if (q == NULL)
    {
        printf("通訊錄中沒有這個姓名!\n");
    }
    else
    {
        printf("已經找到此聯絡人!\n");
        printf("學號\t\t姓名\t\t性別\t\t宿舍\t\t電話號碼 \n");
        printf("%s\t\t%s\t\t%s\t\t%s\t\t%s\n", q->data.num, q->data.name, q->data.sex, q->data.hostel, q->data.telephone);
    }
}

void Find_Num(LinkList& L) //按學號查詢
{
    LinkList q, p;
    q = L->next;
    printf("輸入要查詢的編號:\n");
    p = (LNode*)malloc(sizeof(LNode));
    scanf("%s", p->data.num);
    while (q != NULL && strcmp(q->data.num, p->data.num) != 0)
    {
        q = q->next;
    }
    if (q == NULL)
    {
        printf("通訊錄中沒有這個編號!\n");
    }
    else
    {
        printf("已經找到此聯絡人!\n");
        printf("學號\t\t姓名\t\t性別\t\t宿舍\t\t電話號碼 \n");
        printf("%s\t\t%s\t\t%s\t\t%s\t\t%s\n", q->data.num, q->data.name, q->data.sex, q->data.hostel, q->data.telephone);
    }
}


Status  CreateFromTail(LinkList& L)     //採用尾插法在尾部插入元素
{
    LinkList r, s;
    r = L;   //r指標始終動態指向連結串列的當前表尾
    while (r->next)
    {//尾插法,直接把指標移位到尾部
        r = r->next;
    }
    s = (LinkList)malloc(sizeof(LNode));
    printf("在尾部插入的聯絡人資訊為:\n");
    printf("學號\t\t姓名\t\t性別\t\t宿舍\t\t電話號碼 \n");
    scanf("%s%s%s%s%s", s->data.num, s->data.name, s->data.sex, s->data.hostel, s->data.telephone);
    s->next = NULL;
    r->next = s;
    return OK;
}

Status ListInsert_L(LinkList& L)//在單鏈線性表L的第i個元素之前插入元素
{
    LinkList s, p = L;
    int  j = 0, i;
    printf("輸入要插入的位置:");
    scanf("%d", &i);
    while (p && j < i)
    {  // 尋找第i個結點
        p = p->next;
        ++j;
    }
    if (!p || j > i) { printf("----無此位置新增失敗-----\n"); return ERROR; }      // i小於1或者大於表長
    s = (LinkList)malloc(sizeof(LNode));  // 生成新結點
    printf("插入的聯絡人資訊為:\n");
    printf("學號\t\t姓名\t\t性別\t\t宿舍\t\t電話號碼 \n");
    scanf("%s%s%s%s%s", s->data.num, s->data.name, s->data.sex, s->data.hostel, s->data.telephone);
    s->next = p->next;      // 插入L中
    p->next = s;
    return OK;
} // LinstInsert_L


Status Fund_LName(LinkList& L)  //尋找該姓名的位置
{
    LinkList s, p = L->next;
    int  i = 0;
    s = (LNode*)malloc(sizeof(LNode));
    scanf("%s", s->data.name);
    while (p != NULL && strcmp(p->data.name, s->data.name) != 0)
    {
        p = p->next;
        ++i;
    }
    return i + 1;
}

Status ListInsert_LName(LinkList& L)//在單鏈線性表L的姓名元素之前插入元素
{
    LinkList s, q = L, p = L->next;
    printf("輸入要在誰的姓名之前新增資訊:");
    int i = Fund_LName(L);
    int j = 0;
    while (q && j < i - 1)
    {  // 尋找第i-1個結點
        q = q->next;
        ++j;
    }
    if (p == NULL) { printf("----查無此人新增失敗-----\n"); return ERROR; }      // 如果沒有找到
    s = (LinkList)malloc(sizeof(LNode));  // 生成新結點
    printf("插入的聯絡人資訊為:\n");
    printf("學號\t\t姓名\t\t性別\t\t宿舍\t\t電話號碼 \n");
    scanf("%s%s%s%s%s", s->data.num, s->data.name, s->data.sex, s->data.hostel, s->data.telephone);
    s->next = q->next;      // 插入L中
    q->next = s;
    return OK;
}

Status ListDelete_L(LinkList& L)//刪除第i個元素
{
    LinkList p = L, q;
    int  j = 0, i;
    printf("輸入要刪除的位置:");
    scanf("%d", &i);
    while (p->next && j < i)
    {  // 尋找第i個結點,並令p指向其前趨
        p = p->next;    ++j;
    }
    if (!(p->next) || j > i) { printf("----查無此人刪除失敗-----\n"); return ERROR; }  // 刪除位置不合理
    q = p->next;
    p->next = q->next;           // 刪除並釋放結點
    free(q);
    printf("----刪除成功-----\n");
    return OK;
} // ListDelete_L

Status ListDelete_LName(LinkList& L)   //刪除姓名為“XXX”的學生記錄
{
    LinkList p = L, q;
    printf("輸入要刪除的學生的姓名:");
    int  j = 0, i = Fund_LName(L);
    while (p->next && j < i - 1)
    {  // 尋找第i個結點,並令p指向其前趨
        p = p->next;    ++j;
    }
    if (!(p->next) || j > i - 1) { printf("----查無此人刪除失敗-----\n"); return ERROR; }  // 刪除位置不合理
    q = p->next;
    p->next = q->next;           // 刪除並釋放結點
    free(q);
    printf("----刪除成功-----\n");
    return OK;
}

void PrintElem(LinkList L)//列印出所有元素
{
    LinkList p = L->next;
    printf("當前的資訊為:\n");
    while (p != NULL)
    {
        printf("%s\t\t%s\t\t%s\t\t%s\t\t%s\n", p->data.num, p->data.name, p->data.sex, p->data.hostel, p->data.telephone);
        p = p->next;
    }
    printf("\n");
}

void saveFile(LinkList& L)  //儲存通訊錄到檔案
{
    FILE* fp;
    LinkList p;
    p = L;
    if ((fp = fopen("通訊錄.txt", "wt")) == NULL)   exit(0);   // "wt"方式開啟檔案時,如果原始檔中有內容,追加
    if (p == NULL || p->next == NULL) //連結串列為空
        printf("您的操作有誤,請確保您的通訊錄不為空!\n");
    else
    {
        p = p->next;
        while (p != NULL)
        {
            fprintf(fp, "%s\t\t%s\t\t%s\t\t%s\t\t%s", p->data.num, p->data.name, p->data.sex, p->data.hostel, p->data.telephone);
            fprintf(fp, "\n");
            p = p->next;
        }
        fclose(fp);
        printf("通訊錄已儲存!\n");
    }
}

void List_free(LinkList L)  //銷燬連結串列
{
    LinkList p;
    while (L != NULL)
    {
        p = L;
        L = L->next;
        free(p);
    }
}

/*readFile(L) InitList_L(L) Find_Name(L) Find_Num(L) CreateFromTail(L)   ListInsert_L(L) ListInsert_LName(L)
ListDelete_L(L) ListDelete_LName(L) saveFile(L)
 PrintElem(L)  List_free(L)*/

int main()
{
    int n=1;
    LinkList L;
    InitList_L(L);
    while (n != 0)
    {
        printf("*****************************基於單連結串列的班級通訊錄*****************************\n\n");
        printf("         1:讀取檔案(**請先讀取檔案**)   |   2:通過姓名查詢聯絡人\n\n");
        printf("         3:通過學號查詢聯絡人           |   4:在最後新增某學生資訊\n\n");
        printf("         5:將新聯絡人加在第i條記錄之前  |   6:將新聯絡人加在“XXX”的學生之前\n\n");
        printf("         7:刪除第i條記錄                |   8:刪除姓名為“XXX”的學生記錄\n\n");
        printf("         9:顯示結果                     |   0:退出程式並儲存              \n\n");
        printf("********************************************************************************\n");
        printf("請選擇操作<1-9>,退出<0>:");
        scanf("%d", &n);
        switch (n)
        {
        case 1:readFile(L);
            system("pause");//輸入任意鍵繼續
            system("cls");//清屏
            break;
        case 2:Find_Name(L);
            system("pause");//輸入任意鍵繼續
            system("cls");//清屏
            break;
        case 3:Find_Num(L);
            system("pause");//輸入任意鍵繼續
            system("cls");//清屏
            break;
        case 4:CreateFromTail(L);
            system("pause");//輸入任意鍵繼續
            system("cls");//清屏
            break;
        case 5:ListInsert_L(L);
            system("pause");//輸入任意鍵繼續
            system("cls");//清屏
            break;
        case 6:ListInsert_LName(L);
            system("pause");//輸入任意鍵繼續
            system("cls");//清屏
            break;
        case 7:ListDelete_L(L);
            system("pause");//輸入任意鍵繼續
            system("cls");//清屏
            break;
        case 8:ListDelete_LName(L);
            system("pause");//輸入任意鍵繼續
            system("cls");//清屏
            break;
        case 9:PrintElem(L);
            system("pause");//輸入任意鍵繼續
            system("cls");//清屏
            break;
        case 0:saveFile(L); List_free(L);
            system("cls");//清屏
            break;
        }
    }
}

測試檔案
在這裡插入圖片描述
測試與結果
(1)讀取檔案
在這裡插入圖片描述
(2)通過姓名查詢聯絡人
在這裡插入圖片描述
(3)通過學號查詢聯絡人
在這裡插入圖片描述
(4)在最後新增某學生資訊
在這裡插入圖片描述
在這裡插入圖片描述
(5)將新聯絡人加在第i條記錄之前
在這裡插入圖片描述
在這裡插入圖片描述
(6)將新聯絡人加在“XXX”的學生之前
在這裡插入圖片描述
在這裡插入圖片描述
(7)刪除第i條記錄
在這裡插入圖片描述
在這裡插入圖片描述
(8)刪除姓名為“XXX”的學生記錄
在這裡插入圖片描述
在這裡插入圖片描述
(9)退出程式並儲存
在這裡插入圖片描述

相關文章