系列文章目录
【数据结构】顺序表
文章目录
- 系列文章目录
- 前言
- 一、通讯录的功能要求
- 二、通讯录的代码实现
- 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);
感谢观看!!!