上一篇文章我们详细讲解了顺序表的构建,而顺序表构建完之后,就可以进行一些小的应用,比如建立一个通讯录
首先,我们还是先把顺序表的基本函数写出来
//SeqList.h
#include<stdio.h>
#include<stdlib.h>
#include<stdbool.h>
#include<assert.h>
typedef int SLDataType;
typedef struct SeqList
{
SLDataType* a;//放指针
int size;//有效数据
int capacity;//空间
}SL;
void SLInit(SL* ps);//初始化
void SLDestroy(SL* ps);//销毁
void SLCheckCapacity(SL* ps);//扩容
void SLPushBack(SL* ps, SLDataType x);//尾插
void SLPushFront(SL* ps, SLDataType x);//头插
void SLPopBack(SL* ps);//尾删
void SLPopFront(SL* ps);//头删
void SLPrint(SL* ps);//打印顺序表
bool SLISEmpty(SL* ps);//检查顺序表是否还有有效数据
void SLInsert(SL* ps, int index, SLDataType x);//任意位置插入
void SLErase(SL* ps, int index);//任意位置删除
int SLFind(SL* ps, SLDataType x);//找到对应数据的下标
//这些函数的具体内容在上一篇文章中可以找到
我们知道顺序表的底层结构是数组,而对于通讯录,可以使用顺序表作为其底层数据结构。顺序表是一种线性数据结构,使用数组来存储元素,这样可以快速访问和操作其中的数据。
在通讯录中,每个联系人可以表示为一个结构体或类,包含姓名、电话号码、地址等信息。然后,你可以使用顺序表来存储这些联系人,即将联系人结构体的实例存储在数组的不同位置。
通讯录底层结构
#define NAME_MAX 50
#define GENDER_MAX 10
#define TEL_MAX 15
#define ADDR_MAX 100
//使用的是定长数组,因为这些数据的长度基本上都不会怎么变,无需使用变长数组
typedef struct ContactInfo
{
char name[NAME_MAX];//名字
char gender[GENDER_MAX];//性别
int age;//年龄
char tel[TEL_MAX];//电话
char addr[ADDR_MAX];//地址
}CInfo;//通讯录更名为CInfo
//通讯录底层是由顺序表来实现
typedef struct SeqList contact;
//后面传的指针其实都是顺序表的地址
void ContactInit(contact* con);//初始化
void ContactDestroy(contact* con);//销毁
void ContactAdd(contact* con);//添加联系人
void ContactDel(contact* con);//删除联系人
int FindByName(contact* con, char* name);//找到联系人的下标
void ContactModify(contact* con);//修改联系人
void ContactShow(contact* con);//查看通讯录
void ContactFind(contact* con);//查找指定联系人
通讯录的函数实现
#include"Contact.h"
#include"Seqlist.h"
//初始化和销毁直接用顺序表的销毁即可,因为两者实质上都是结构体
void ContactInit(contact* con) {
SLInit(con);
}
void ContactDestroy(contact* con) {
SLDestroy(con);
}
void ContactAdd(contact* con) {
CInfo info;//先创建info,也就是通讯录个人的信息,把名字、性别等一个一个填进去,再把它放到顺序表成为其中一个元素
printf("请输入联系人的名字:\n");
scanf("%s", info.name);
printf("请输入联系人的性别:\n");
scanf("%s", info.gender);
printf("请输入联系人的年龄:\n");
scanf("%d", &info.age);
printf("请输入联系人的电话:\n");
scanf("%s", info.tel);
printf("请输入联系人的地址:\n");
scanf("%s", info.addr);
SLPushBack(con, info);//用尾插把联系人的信息放进去
}
void ContactDel(contact* con) {
char name[NAME_MAX];
printf("请输入想删除的联系人:\n");
scanf("%s", name);//临时创建一个字符数组来储存要找的联系人姓名
int findindex = FindByName(con, name);//把函数返回值传回来进行判断
if (findindex < 0)
{
printf("要删除的联系人找不到!\n");
return;
}
SLErase(con, findindex);//直接用顺序表删除函数删除
}
int FindByName(contact* con, char* name) {
for (size_t i = 0; i < con->size; i++)
{
if (strcmp(con->a[i].name, name)==0)
{
return i;//两个字符串完全相等才会等于0,这时才能返回下标
}
}
return -1;//找不到就返回-1
}
void ContactModify(contact* con) {
char name[NAME_MAX];
printf("请输入要修改的联系人:\n");
scanf("%s", name);
int findindex = FindByName(con, name);
if (findindex < 0)
{
printf("要修改的联系人找不到!\n");
return;
}
//这里是进行了全部的修改,如果想只改其中几个,可以试试if语句
printf("请输入联系人的名字:\n");
scanf("%s", con->a[findindex].name);
printf("请输入联系人的性别:\n");
scanf("%s", con->a[findindex].gender);
printf("请输入联系人的年龄:\n");
scanf("%d", &con->a[findindex].age);
printf("请输入联系人的电话:\n");
scanf("%s", con->a[findindex].tel);
printf("请输入联系人的地址:\n");
scanf("%s", con->a[findindex].addr);
printf("修改成功!\n");
ContactShow(con);//修改成功之后显示一下新的信息
}
void ContactShow(contact* con) {
printf("%s %s %s %s %s\n", "名字", "性别", "年龄", "电话", "地址");//属性
for (int i = 0; i < con->size; i++)
{
printf("%-4s %-4s %-4d %-4s %-4s\n",
con->a[i].name,
con->a[i].gender,
con->a[i].age,
con->a[i].tel,
con->a[i].addr);
}//-4s表示用于格式化输出一个字符串,并保证输出的字段宽度为4个字符,并且左对齐对齐方式,-4d的格式也相同,只不过输出的数据类型不同
}
//这里是用于查看单个联系人
void ContactFind(contact* con) {
char name[NAME_MAX];
printf("请输入你想查找的联系人姓名:\n");
scanf("%s", name);
int findindex = FindByName(con, name);
if (findindex < 0)
{
printf("要查找的联系人找不到!\n");
return;
}
printf("%s %s %s %s %s\n", "姓名", "性别", "年龄", "电话", "地址");
printf("%-4s %-4s %-4d %-4s %-4s\n",
con->a[findindex].name,
con->a[findindex].gender,
con->a[findindex].age,
con->a[findindex].tel,
con->a[findindex].addr);
}
通讯录简单运用
#include"contact.h"
#include"Seqlist.h"
void menu()//菜单
{
printf("************ 通讯录 *************\n");
printf("*****1. 创建联系人 2. 删除联系人*****\n");
printf("*****3. 修改联系人 4. 查找联系人*****\n");
printf("*****5. 查看通讯录 0. 退出 *****\n");
printf("**************************************\n");
}
int main()
{
contact pcon;//首先创建一个顺序表变量
int i = 0;
ContactInit(&pcon);
do
{
menu();
printf("请选择您的操作:\n");
scanf("%d", &i);
switch (i)
{
case 1:
ContactAdd(&pcon);
break;
case 2:
ContactDel(&pcon);
break;
case 3:
ContactModify(&pcon);
break;
case 4:
ContactFind(&pcon);
break;
case 5:
ContactShow(&pcon);
break;
case 0:
printf("goodbye~\n");
break;
default:
printf("输入错误,请重新输入!\n");
break;
}
} while (i);
ContactDestroy(&pcon);
return 0;
}
可以看出,作为通讯录的底层结构,顺序表很好的发挥了其作用,而且在运行代码时也有一系列优点:
- 随机访问:由于顺序表使用数组存储元素,可以通过索引快速访问特定位置的联系人。
- 内存连续性:顺序表在内存中存储元素是连续的,这可以提高数据的访问效率。
- 简单操作:顺序表对增加、删除和搜索联系人提供了简单的操作方法。
希望大家在看完这篇文章之后可以掌握如何利用顺序表作为底层结构,来构建一个简易的通讯录,如果大家有什么更好的意见,也欢迎大家来交流!