系列文章目錄
【數據結構】順序表
文章目錄
- 系列文章目錄
- 前言
- 一、通訊錄的功能要求
- 二、通訊錄的代碼實現
- 1. 新建文件
- 2. 創建通訊錄的結構體
- 3. 對順序表文件進行修改
- 4. 通訊錄具體功能實現
- 4.1. 通訊錄的初始化和銷毀
- 4.2. 增加聯系人信息(尾插)
- 4.3. 查找指定聯系人(通過姓名查找)
- 4.4. 刪除指定聯系人
- 4.5. 修改指定聯系人
- 4.6. 顯示聯系人信息
- 三、完整代碼
- 四、效果展示
- 總結
前言
回顧上文,我們初步了解了順序表,順序表的本質就是數組,但相比于單純的數組,順序表多出了一些功能——增刪查改。那么順序表究竟有什么用呢?接下來為大家使用順序表實現一個簡易的通訊錄。(使用動態順序表實現)
正文開始
一、通訊錄的功能要求
- 至少能夠存儲100個人的通訊信息
- 能夠保存用戶信息:名字、性別、年齡、電話、地址等
- 增加聯系人信息
- 刪除指定聯系人
- 查找指定聯系人
- 修改指定聯系人
- 顯示聯系人信息
二、通訊錄的代碼實現
1. 新建文件
順序表作為一種數據結構,只是一個工具,當我們要使用它去實現具體的東西時還需要對其進行包裝。所以,我們這里在原來順序表的基礎上新建了兩個文件——Contact.h和Contact.c。
Contact.h中存放通訊錄所需的函數的聲明和結構體的聲明。
Contact.c中存放通訊錄中函數的定義。
2. 創建通訊錄的結構體
接下來我們就需要在Contact.h中創建一個通訊錄的結構體,要包含的信息有:名字、性別、年齡、電話、地址。所以我們的順序表中的元素的類型要是結構體,該結構體有5個成員。
#define NAME_MAX 20
#define GENDER_MAX 10
#define TEL_MAX 20
#define ADDR_MAX 20typedef struct personinform
{char name[NAME_MAX];char gender[GENDER_MAX];int age;char tel[TEL_MAX];char addr[ADDR_MAX];
}perinfo;
由于我們要實現通訊錄,我們的順序表的結構體的結構體名要更改為Contact,且要在該頭文件中就要實現,因為后面有對應函數的聲明,所以我們要在Contact.h中使用前置聲明。
typedef struct Sepline Contact; // 只有前置聲明才能更改順序表的結構體名。
3. 對順序表文件進行修改
我們在Contact.h中把套在順序表上的外殼寫完,我們還要對原來的順序表進行小幅度修改,使其與我們要實現的功能匹配。
首先就要包含Contact.h這個頭文件,然后將typedef后的int改為perinfo。
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
#include <assert.h>
#include "Contact.h"
typedef perinfo SLtype;
//動態順序表
typedef struct Sepline
{SLtype* arr;int size;//有效數字大小int capacity;//動態內存大小
}SL;
最后,我們要將順序表的函數實現進行修改,原本是實現int的,現在要改為實現結構體形式。
void SLshow(SL* sl)
{printf("%s %s %s %s %s\n", "姓名", "性別", "年齡", "電話", "地址");for (int i = 0; i < sl->size; i++)printf("%3s %3s %3d %3s %3s\n", sl->arr[i].name, sl->arr[i].gender,sl->arr[i].age,sl->arr[i].tel,sl->arr[i].addr);
}
順序表的修改和查找,我選擇刪除重新實現,要修改與重寫沒什么區別。
4. 通訊錄具體功能實現
4.1. 通訊錄的初始化和銷毀
//初始化
void Con_init(Contact* con);//銷毀
void Con_des(Contact* con);
void Con_init(Contact* con)
{SLinit(con);
}void Con_des(Contact* con)
{SLdestory(con);
}
這就是使用了順序表后的情況,在具體實現函數時只需要套用之前的函數就可以了。
4.2. 增加聯系人信息(尾插)
//插入(后插)
void Con_insert(Contact* con);
void Con_insert(Contact* con)
{perinfo x = { 0 };printf("請輸入聯系人姓名:");scanf("%s", x.name);printf("請輸入聯系人性別:");scanf("%s", x.gender);printf("請輸入聯系人年齡:");scanf("%d", &x.age);printf("請輸入聯系人電話:");scanf("%s", x.tel);printf("請輸入聯系人地址:");scanf("%s", x.addr);SL_in_back(con, x);
}
4.3. 查找指定聯系人(通過姓名查找)
int Con_find_name(Contact* con, char name[]);
int Con_find_name(Contact* con, char name[])
{for (int i = 0; i < con->size; i++){if (0 == strcmp(name, con->arr[i].name))return i;}return -1;
}
4.4. 刪除指定聯系人
//指定刪除
void Con_del(Contact* con);
void Con_del(Contact* con)
{char name[20];printf("請輸入需要刪除的聯系人:");scanf("%s", name);int find = Con_find_name(con, name);if (find != -1){SLindel(con, find);printf("刪除成功\n");}else{printf("需要刪除的聯系人不存在\n");}
}
4.5. 修改指定聯系人
//修改
void Con_fix_name(Contact* con);
void Con_fix_name(Contact* con)
{char name[20];printf("請輸入需要修改的聯系人姓名:");scanf("%s", name);int find = Con_find_name(con, name);perinfo x = { 0 };printf("請輸入修改后的姓名:");scanf("%s", x.name);printf("請輸入修改后的性別:");scanf("%s", x.gender);printf("請輸入修改后的年齡:");scanf("%d", &x.age);printf("請輸入修改后的電話:");scanf("%s", x.tel);printf("請輸入修改后的地址:");scanf("%s", x.addr);con->arr[find] = x;
}
4.6. 顯示聯系人信息
//展示
void Con_show(Contact* con);
void Con_show(Contact* con)
{SLshow(con);
}
這些通訊錄的函數的實現基本都通過調用了順序表的函數,大大減少了我們需要寫的代碼量,而且還不用考慮數據是如何增加,刪除等。當然,前提是順序表的函數沒有寫錯。
三、完整代碼
Contact.h
#pragma once#define NAME_MAX 20
#define GENDER_MAX 10
#define TEL_MAX 20
#define ADDR_MAX 20typedef struct personinform
{char name[NAME_MAX];char gender[GENDER_MAX];int age;char tel[TEL_MAX];char addr[ADDR_MAX];
}perinfo;typedef struct Sepline Contact; // 只有前置聲明才能更改順序表的結構體名。//初始化
void Con_init(Contact* con);//銷毀
void Con_des(Contact* con);//插入(后插)
void Con_insert(Contact* con);//指定刪除
void Con_del(Contact* con);//展示
void Con_show(Contact* con);//查找
int Con_find_name(Contact* con, char name[]);//修改
void Con_fix_name(Contact* con);
Sepline.h
#pragma once
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
#include <assert.h>
#include "Contact.h"
typedef perinfo SLtype;
//動態順序表
typedef struct Sepline
{SLtype* arr;int size;//有效數字大小int capacity;//動態內存大小
}SL;//順序表初始化
void SLinit(SL* sl);//順序表銷毀
void SLdestory(SL* sl);//后插
void SL_in_back(SL* sl, SLtype x);//前插
void SL_in_front(SL* sl, SLtype x);//后刪
void SL_out_back(SL* sl);//前刪
void SL_out_front(SL* sl);//展示
void SLshow(SL* sl);//查找
int SLfind(SL* sl, SLtype n);//修改
void SLfix(SL* sl, int n);//指定位置增加
void SLinsert(SL* sl, int n, SLtype x);//指定位置刪除
void SLindel(SL* sl, int n);//擴展空間
void SLapply(SL* sl);
Contact.c
#define _CRT_SECURE_NO_WARNINGS 1#include "Sepline.h"
#include "Contact.h"void Con_init(Contact* con)
{SLinit(con);
}void Con_des(Contact* con)
{SLdestory(con);
}void Con_insert(Contact* con)
{perinfo x = { 0 };printf("請輸入聯系人姓名:");scanf("%s", x.name);printf("請輸入聯系人性別:");scanf("%s", x.gender);printf("請輸入聯系人年齡:");scanf("%d", &x.age);printf("請輸入聯系人電話:");scanf("%s", x.tel);printf("請輸入聯系人地址:");scanf("%s", x.addr);SL_in_back(con, x);
}int Con_find_name(Contact* con, char name[])
{for (int i = 0; i < con->size; i++){if (0 == strcmp(name, con->arr[i].name))return i;}return -1;
}void Con_del(Contact* con)
{char name[20];printf("請輸入需要刪除的聯系人:");scanf("%s", name);int find = Con_find_name(con, name);if (find != -1){SLindel(con, find);printf("刪除成功\n");}else{printf("需要刪除的聯系人不存在\n");}
}void Con_show(Contact* con)
{SLshow(con);
}void Con_fix_name(Contact* con)
{char name[20];printf("請輸入需要修改的聯系人姓名:");scanf("%s", name);int find = Con_find_name(con, name);perinfo x = { 0 };printf("請輸入修改后的姓名:");scanf("%s", x.name);printf("請輸入修改后的性別:");scanf("%s", x.gender);printf("請輸入修改后的年齡:");scanf("%d", &x.age);printf("請輸入修改后的電話:");scanf("%s", x.tel);printf("請輸入修改后的地址:");scanf("%s", x.addr);con->arr[find] = x;
}
Sepline.c
#define _CRT_SECURE_NO_WARNINGS 1#include"Sepline.h"
void SLinit(SL* sl)
{sl->arr = NULL;sl->size = sl->capacity = 0;
}void SLdestory(SL* sl)
{free(sl->arr);sl->arr = NULL;sl->size = sl->capacity = 0;
}void SLapply(SL* sl)
{if (sl->size == sl->capacity){sl->capacity = sl->capacity == 0 ? 4 : 2 * sl->capacity;SLtype* tmp = (SLtype*)realloc(sl->arr, sl->capacity * sizeof(SLtype));if (tmp == NULL){perror("realloc");exit(1);}sl->arr = tmp;tmp = NULL;}
}void SL_in_back(SL* sl, SLtype x)
{assert(sl);SLapply(sl);sl->arr[sl->size++] = x;
}void SL_in_front(SL* sl, SLtype x)
{assert(sl);SLapply(sl);for (int i = sl->size; i > 0; i--){sl->arr[i] = sl->arr[i - 1];}sl->arr[0] = x;sl->size++;
}void SL_out_back(SL* sl)
{assert(sl);assert(sl->size);sl->size--;
}void SLshow(SL* sl)
{printf("%s %s %s %s %s\n", "姓名", "性別", "年齡", "電話", "地址");for (int i = 0; i < sl->size; i++)printf("%3s %3s %3d %3s %3s\n", sl->arr[i].name, sl->arr[i].gender,sl->arr[i].age,sl->arr[i].tel,sl->arr[i].addr);
}void SL_out_front(SL* sl)
{assert(sl);assert(sl->size);for (int i = 0; i < sl->size - 1; i++)sl->arr[i] = sl->arr[i + 1];sl->size--;
}//int SLfind(SL* sl, SLtype n)
//{
// assert(sl);
// //assert(n >= 0 && n < sl->size);
// for (int i = 0; i < sl->size; i++)
// {
// if (n == sl->arr[i])
// return i;
// }
// return -1;
//}//void SLfix(SL* sl, int n)
//{
// assert(sl);
// assert(n >= 0 && n < sl->size);
// int num = 0;
// printf("請輸入修改后的數:");
// scanf("%d", &num);
// sl->arr[n] = num;
//}void SLinsert(SL* sl, int n, SLtype x)
{assert(sl);assert(n >= 0 && n <= sl->size);SLapply(sl);for (int i = sl->size; i > n; i--){sl->arr[i] = sl->arr[i - 1];}sl->arr[n] = x;sl->size++;
}void SLindel(SL* sl, int n)
{assert(sl);assert(n >= 0 && n < sl->size);for (int i = n; i < sl->size - 1; i++){sl->arr[i] = sl->arr[i + 1];}sl->size--;
}
test.c
#define _CRT_SECURE_NO_WARNINGS 1
#include "Sepline.h"
#include "Contact.h"void menu()
{printf("\n");printf("***********通訊錄**********\n");printf("**** 1. 增加 2. 刪除 ****\n");printf("**** 3. 查找 4. 展示 ****\n");printf("**** 5. 修改 0. 退出 ****\n");printf("***************************\n");
}
void test()
{Contact con;char name[20];int choose = 0;Con_init(&con);do{menu();printf("請輸入你要進行的操作(輸入前面數字):");scanf("%d", &choose);switch (choose){case 1: Con_insert(&con);break;case 2: Con_del(&con);break;case 3:printf("請輸入你要查找的聯系人姓名:");scanf("%s", name);int find = Con_find_name(&con, name);if (find < 0)printf("沒找到\n");elseprintf("找到了,在第%d個\n", find);break;case 4: Con_show(&con);break;case 5: Con_fix_name(&con);break;case 0: printf("退出應用\n");break;default: printf("請輸入0~6之間的數\n");break;}} while (choose);Con_des(&con);
}int main()
{test();return 0;
}
四、效果展示
增加聯系人
修改聯系人
刪除聯系人
展示聯系人
查找聯系人
總結
通訊錄的實現實際十分簡單,我們只要能熟練掌握順序表的功能的實現,再在順序表上套一個外殼就變成了通訊錄。我們這個通訊錄還有點小問題——無法一直保存數據。如果想要一直保存可以使用文件來操作,將每次修改的數據保存到一個文件里,每次進入程序先從該文件中讀取數據,結束時將數據傳回文件中。大家可以試著實現以下。
這里是我的解決方法:
test.c
void test()
{FILE* pf = fopen("Contact.txt", "r");Contact con;char name[20];int choose = 0;Con_init(&con);Con_insert_file(&con, pf);do{menu();printf("請輸入你要進行的操作(輸入前面數字):");scanf("%d", &choose);switch (choose){case 1: Con_insert(&con);break;case 2: Con_del(&con);break;case 3: printf("請輸入你要查找的聯系人姓名:");scanf("%s", name);int find = Con_find_name(&con, name);if (find < 0)printf("沒找到\n");elseprintf("找到了,在第%d個\n", find);break;case 4: Con_show(&con);break;case 5: Con_fix_name(&con);break;case 0: printf("退出應用\n");break;default: printf("請輸入0~6之間的數\n");break;}} while(choose);fclose(pf);pf = NULL;pf = fopen("Contact.txt", "w");for (int i = 0; i < con.size; i++){fprintf(pf, "%s %s %d %s %s\n",con.arr[i].name,con.arr[i].gender,con.arr[i].age,con.arr[i].tel,con.arr[i].addr);}fclose(pf);pf = NULL;Con_des(&con);
}
Contact.c
void Con_insert_file(Contact* con, FILE* pf)
{int ret = 0;int i = 0;while (ret != EOF){SLapply(con);ret = fscanf(pf, "%s %s %d %s %s",con->arr[i].name,con->arr[i].gender,&con->arr[i].age,con->arr[i].tel,con->arr[i].addr);if (ret != EOF){con->size++;i++;}}
}
Contact.h
//文件插入
void Con_insert_file(Contact* con, FILE* pf);
感謝觀看!!!