介绍:
我们知道,顺序表是将各种类型数据存储到一块连续的空间中,存储数据的类型多样,意味着顺序表的使用方式也多样化,在我们的实际生活中,顺序表的应用非常广泛,这篇文章就来向大家介绍顺序表在我们日常生活中的一种应用——顺序表实现通讯录,所谓通讯录,就是当顺序表中数据存储类型改为存放着联系人信息的结构体类型时,顺序表就可以等同于我们日常生活中的通讯录,实现这种顺序表的增删查改,也就相当于通讯录联系人的增删查改,因此,这种代码实现对于我们自身能力的提升非常重要,在巩固我们知识的同时,还加深了对顺序表的理解和使用;
顺序表增删查改的实现:
在进行我们通讯录的实现之前,我们当然要牢牢掌握当存放数据的类型为int时的动态顺序表的增删查改,由于这并不是这篇文章的重点,我们直接将代码给出,大家可以以此为参考:
头文件部分:
#pragma once
#include <stdio.h>
#include <stdlib.h>
#include <assert.h>
typedef int SLDataType;
typedef struct SeqList
{
SLDataType* arr;
int size;
int capacity;
}SL;
//初始化顺序表
void SeqListInit(SL* ps);
//摧毁顺序表
void SeqListDestory(SL* ps);
//打印顺序表
void SeqListPrint(SL* ps);
//检查容量
void CheckCapacity(SL* ps);
//顺序表尾插数据
void SeqListPushBack(SL* ps, SLDataType x);
//顺序表头插数据
void SeqListPushFront(SL* ps, SLDataType x);
//顺序表尾删数据
void SeqListPopBack(SL* ps);
//顺序表头删数据
void SeqListPopFront(SL* ps);
//在下标pos前插入数据
void SeqListInsert(SL* ps, int pos, SLDataType x);
//删除下标pos处的数据
void SeqListErase(SL* ps, int pos);
功能实现部分:
#define _CRT_SECURE_NO_WARNINGS 1
#include "SeqList.h"
void SeqListInit(SL* ps)
{
assert(ps);
ps->arr = NULL;
ps->capacity = ps->size = 0;
}
void SeqListDestory(SL* ps)
{
assert(ps);
free(ps->arr);
ps->arr = NULL;
ps->capacity = ps->size = 0;
}
void SeqListPrint(SL* ps)
{
assert(ps);
for (int i = 0; i < ps->size; i++)
{
printf("%d ", ps->arr[i]);
}
printf("\n");
}
void CheckCapacity(SL* ps)
{
assert(ps);
if (ps->capacity == ps->size)
{
int newcapacity = ps->capacity == 0 ? 4 : ps->capacity * 2;
SLDataType* tmp = (SLDataType*)realloc(ps->arr, newcapacity * sizeof(SLDataType));
if (tmp == NULL)
{
perror("realloc");
exit(-1);
}
ps->arr = tmp;
ps->capacity = newcapacity;
}
}
void SeqListPushBack(SL* ps, SLDataType x)
{
assert(ps);
//先检查容量,不够增容;
CheckCapacity(ps);
ps->arr[ps->size] = x;
ps->size++;
}
void SeqListPushFront(SL* ps, SLDataType x)
{
assert(ps);
//先检查容量,不够增容;
CheckCapacity(ps);
int i = ps->size;
while (i)
{
//集体向后挪一位
ps->arr[i] = ps->arr[i - 1];
i--;
}
ps->arr[0] = x;
ps->size++;
}
void SeqListPopBack(SL* ps)
{
assert(ps);
assert(ps->size);//有元素才能删,没有元素不能调用该函数;
ps->size--;
}
void SeqListPopFront(SL* ps)
{
assert(ps);
assert(ps->size);
int i = 0;
//元素集体向前挪动
while (i < ps->size - 1)
{
ps->arr[i] = ps->arr[i + 1];
i++;
}
ps->size--;
}
void SeqListInsert(SL* ps, int pos, SLDataType x)
{
assert(ps);
assert(pos <= ps->size);
CheckCapacity(ps);
int i = ps->size;
while (i > pos)
{
ps->arr[i] = ps->arr[i - 1];
i--;
}
ps->arr[pos] = x;
ps->size++;
}
void SeqListErase(SL* ps, int pos)
{
assert(ps);
assert(pos >= 0 && pos < ps->size);
int i = pos;
while (i < ps->size - 1)
{
ps->arr[i] = ps->arr[i + 1];
i++;
}
ps->size--;
}
通讯录功能的实现:
前面说到,通讯录的实现就是将顺序表中存储类型改为结构体类型,在存储类型变为结构体之后,其相应的增删查改的方式也会发生一系列微妙变化,但对于顺序表,万变不离其宗形容它再适合不过,不管存储类型怎么变,其增删查改的大致思维是基本一致的;
实现顺序表,我们要先创建Contact.h头文件,对其进行一系列准备工作——创建出顺序表要存储的结构体,以及将顺序表的命名改为通讯录,最后将顺序表中数据的存储类型改为我们创建的结构体类型,以方便我们后续的使用,如下所示:
#define NAME_MAX 20
#define GENDER_MAX 10
#define TELE_MAX 20
#define ADDRESS_MAX 200
//定义一个联系人结构体:——包括姓名、性别、联系电话、年龄,住址;
typedef struct PersonInform
{
char name[NAME_MAX];
char gender[GENDER_MAX];
char tele[TELE_MAX];
int age;
char address[ADDRESS_MAX];
}PI;
struct SeqList;//提前声明一下需要用到的结构体;
typedef struct SeqList Contact;//将顺序表进化成通讯录—
//顺序表中的每一个数据不再是整型,而是结构体
我们可以看到,我们创建的结构体,它存放着联系人的信息——姓名,性别、电话号码、年龄和地址,做完这些准备工作之后,我们就可以直接上手实验通讯录的功能:
1.通讯录的初始化和销毁:
//通讯录初始化
void InitContact(Contact* pc);
//通讯录销毁
void DestoryContact(Contact* pc);
这两个功能的实现非常简单,存储数据类型的变化,并不影响销毁和创建,因此,对通讯录的初始化和销毁,也就是对顺序表的初始化和销毁,可以直接调用实现顺序表初始化和销毁的函数:
void InitContact(Contact* pc)
{
assert(pc);
//初始化通讯录就是初始化顺序表
SeqListInit(pc);
}
void DestoryContact(Contact* pc)
{
assert(pc);
//摧毁通讯录也是摧毁链表;
SeqListDestory(pc);
}
2.通讯录添加联系人:
//添加联系人
void AddContact(Contact* pc);
顺序表存储数据的类型变成了结构体,我们要存入的数据就不再是像整型那么简单明了,首先我们应该创建出这个结构体,并存放好其中的数据,再根据顺序表尾插或者头插的方式将其存入通讯录中,如下所示:
void AddContact(Contact* pc)
{
assert(pc);
//添加数据之前要先构建出要添加的数据:
PI inform;
printf("请输入联系人姓名:\n");
scanf("%s", inform.name);
printf("请输入联系人性别:\n");
scanf("%s", inform.gender);
printf("请输入联系人电话号码:\n");
scanf("%s", inform.tele);
printf("请输入联系人年龄:\n");
scanf("%d", &inform.age);
printf("请输入联系人地址:\n");
scanf("%s", inform.address);
//创建完成,直接尾插进通讯录,如同顺序表的尾插:
SeqListPushBack(pc, inform);
}
在填入之前可以使用printf标注一下,让我们在使用的时候思路能更加清晰,这里有个小地方一定要注意,姓名、性别、电话号码、联系人地址对应的是字符串%s,而年龄对应的是整型%d,一定要区分清楚,要不然程序无法正常执行;
3.通讯录查找联系人
//查找联系人信息:
void FindContact(Contact* pc);
查找某个联系人,即通过某一条件比对通讯录中的数据,匹配则显示出这个数据的全部信息,而在通讯录中,我们可以通过联系人的姓名或者电话号码来查找联系人,下面我们来一一介绍:
3.1.通过姓名查找联系人
//通过姓名查找联系人
int FindByName(Contact* pc, char* des);
des为我们需要查找的联系人姓名,查找的时候我们要将其首元素地址传入该函数中,那我们要怎么判断呢:这就得使用到我们熟知的一个函数————strcmp,遍历通讯录中的每一个结构体的name部分,通过strcmp比对des中的数据和name中的数据是否相同,相同则strcmp的返回值为0,当其返回值为0时,我们将此时通讯录中数组的下标返回,这样我们就可以通过这个下标直接找到通讯录中这个数据的全部信息,但是,当遍历完全后任然没有与des相匹配的数据,我们需要返回一个无效的下标,比如EOF(-1),这样就意味着查找失败了,如下所示:
int FindByName(Contact* pc, char* des)
{
assert(pc);
for (int i = 0; i < pc->size; i++)
{
if (strcmp(pc->arr[i].name, des) == 0)
return i;
}
return EOF;
}
3.2.通过电话号码查找联系人
//通过电话号码查找联系人
int FindByTele(Contact* pc, char* des);
此方法跟通过姓名查找联系人的方法完全相同,只是需要遍历的数据成为了结构体中的tele,如下所示:
int FindByTele(Contact* pc, char* des)
{
assert(pc);
for (int i = 0; i < pc->size; i++)
{
if (strcmp(pc->arr[i].tele, des) == 0)
return i;
}
return EOF;
}
3.3.整体实现:
void FindContact(Contact* pc)
{
assert(pc);
//查找的方式有很多种,可以使用姓名或者电话号码;
int find = 0;
int choice = 0;
do
{
printf("************** 请选择要查找的方式:**************\n");
printf("****************** 1.姓名查找 ***********************\n");
printf("****************** 2.电话查找 **********************\n");
printf("*************** 0.误选,退出查找 **********************\n");
printf("请选择:");
scanf("%d", &choice);
if (choice == 0)
{
printf("已退出:\n");
return;
}
switch(choice)
{
case 1:
printf("请输入要查找联系人的姓名:\n");
char name[20] = "happy";
scanf("%s", name);
find = FindByName(pc, name);
break;
case 2:
printf("请输入要查找联系人的电话号码:\n");
char tele[20] = "happy";
scanf("%s", tele);
find = FindByTele(pc, tele);
break;
default:
printf("选择错误,重新选择:\n");
break;
}
} while (choice != 1 && choice != 2);//选的不是0、1、2还得继续选
if (find == EOF)
{
//找不到
printf("查无此人,退出查找:\n");
return;
}
//找到了
printf("此人信息为:\n");
printf("姓名:%s\n", pc->arr[find].name);
printf("性别:%s\n", pc->arr[find].gender);
printf("电话号码:%s\n", pc->arr[find].tele);
printf("年龄:%d\n", pc->arr[find].age);
printf("地址:%s\n", pc->arr[find].address);
}
4.通讯录删除联系人
//删除通讯录联系人
void DelContact(Contact* pc);
这个功能的实现也比较简单直接,它综合了顺序表增删查改中的查和删,先查后删,首先要根据某一条件,如姓名、电话号码得到对应数据的下标,通过这个下标我们可以直接利用顺序表删除数据的方法删除这个联系人,这里我们以通过姓名删除联系人来做个示范,如下所示:
void DelContact(Contact* pc)
{
assert(pc);
printf("请输入要删除人的姓名:\n");
char name[20] = "happy";
scanf("%s", name);
int find = FindByName(pc, name);
if (find == EOF)
{
printf("查无此人:\n");
return;
}
SeqListErase(pc, find);
}
5.通讯录修改联系人:
//修改通讯录
void ModifyContact(Contact* pc);
与删除数据类似,修改通讯录联系人还是需要先通过某一条件找到需要删除数据的下标,再通过这个下标直接修改联系人信息,在修改的时候还是可以用printf备注一下,能让我们在使用的时候更加清晰明了;
void ModifyContact(Contact* pc)
{
assert(pc);
printf("请输入要修改的人的姓名:\n");
char name[20] = "happy";
scanf("%s", name);
int find = FindByName(pc, name);
if (find == EOF)
{
printf("查无此人:\n");
return;
}
printf("请输入新联系人姓名:\n");
scanf("%s", pc->arr[find].name);
printf("请输入新联系人性别:\n");
scanf("%s", pc->arr[find].gender);
printf("请输入新联系人电话号码:\n");
scanf("%s", pc->arr[find].tele);
printf("请输入新联系人年龄:\n");
scanf("%d", &pc->arr[find].age);
printf("请输入新联系人地址:\n");
scanf("%s", pc->arr[find].address);
printf("修改成功:\n");
}
6.通讯录展示
//展示通讯录
void ShowContact(Contact* pc);
展示出通讯录这个功能的实现就非常直接了,不过还是要区分好%s和%d的使用,以免程序无法正常执行,我们也可以发挥自己的想象让整个打印的界面更加美观:
void ShowContact(Contact* pc)
{
assert(pc);
printf("--------------------------------------\n");
printf(" 姓名 性别 电话号码 年龄 地址 \n");
for (int i = 0; i < pc->size; i++)
{
printf("| %s | %s | %s | %d | %s |\n", pc->arr[i].name,
pc->arr[i].gender,
pc->arr[i].tele,
pc->arr[i].age,
pc->arr[i].address);
}
printf("--------------------------------------\n");
}
通讯录的使用展示:
我们已经知道了通讯录所功能的实现,我们可以通过一个菜单将这些功能串接起来,以此来调用我们的整个通讯录,菜单如下所示:
void menu()
{
printf("**************************************************\n");
printf("**********************通讯录***********************\n");
printf("********** 1.新增联系人 2.删除联系人 **********\n");
printf("********** 3.修改联系人 4.查找联系人 **********\n");
printf("********** 5.展示通讯录 0.退出通讯录 **********\n");
printf("**************************************************\n");
printf("**************************************************\n");
}
接下来是全部的代码和结果展示:
1.代码实现:
头文件部分:
#pragma once
#define NAME_MAX 20
#define GENDER_MAX 10
#define TELE_MAX 20
#define ADDRESS_MAX 200
//定义一个联系人结构体:——包括姓名、性别、联系电话、年龄,住址;
typedef struct PersonInform
{
char name[NAME_MAX];
char gender[GENDER_MAX];
char tele[TELE_MAX];
int age;
char address[ADDRESS_MAX];
}PI;
struct SeqList;//提前声明一下需要用到的结构体;
typedef struct SeqList Contact;//将顺序表进化成通讯录—
//顺序表中的每一个数据不再是整型,而是结构体
//通讯录初始化
void InitContact(Contact* pc);
//通讯录销毁
void DestoryContact(Contact* pc);
//添加联系人
void AddContact(Contact* pc);
//查找联系人信息:
void FindContact(Contact* pc);
//通过姓名查找联系人
int FindByName(Contact* pc, char* des);
//通过电话号码查找联系人
int FindByTele(Contact* pc, char* des);
//删除通讯录联系人
void DelContact(Contact* pc);
//修改通讯录
void ModifyContact(Contact* pc);
//展示通讯录
void ShowContact(Contact* pc);
功能实现部分:
#define _CRT_SECURE_NO_WARNINGS 1
#include "SeqList.h"
void InitContact(Contact* pc)
{
assert(pc);
//初始化通讯录就是初始化顺序表
SeqListInit(pc);
}
void DestoryContact(Contact* pc)
{
assert(pc);
//摧毁通讯录也是摧毁链表;
SeqListDestory(pc);
}
void AddContact(Contact* pc)
{
assert(pc);
//添加数据之前要先构建出要添加的数据:
PI inform;
printf("请输入联系人姓名:\n");
scanf("%s", inform.name);
printf("请输入联系人性别:\n");
scanf("%s", inform.gender);
printf("请输入联系人电话号码:\n");
scanf("%s", inform.tele);
printf("请输入联系人年龄:\n");
scanf("%d", &inform.age);
printf("请输入联系人地址:\n");
scanf("%s", inform.address);
//创建完成,直接尾插进通讯录,如同顺序表的尾插:
SeqListPushBack(pc, inform);
}
int FindByName(Contact* pc, char* des)
{
assert(pc);
for (int i = 0; i < pc->size; i++)
{
if (strcmp(pc->arr[i].name, des) == 0)
return i;
}
return EOF;
}
int FindByTele(Contact* pc, char* des)
{
assert(pc);
for (int i = 0; i < pc->size; i++)
{
if (strcmp(pc->arr[i].tele, des) == 0)
return i;
}
return EOF;
}
void FindContact(Contact* pc)
{
assert(pc);
//查找的方式有很多种,可以使用姓名或者电话号码;
int find = 0;
int choice = 0;
do
{
printf("************** 请选择要查找的方式:**************\n");
printf("****************** 1.姓名查找 ***********************\n");
printf("****************** 2.电话查找 **********************\n");
printf("*************** 0.误选,退出查找 **********************\n");
printf("请选择:");
scanf("%d", &choice);
if (choice == 0)
{
printf("已退出:\n");
return;
}
switch(choice)
{
case 1:
printf("请输入要查找联系人的姓名:\n");
char name[20] = "happy";
scanf("%s", name);
find = FindByName(pc, name);
break;
case 2:
printf("请输入要查找联系人的电话号码:\n");
char tele[20] = "happy";
scanf("%s", tele);
find = FindByTele(pc, tele);
break;
default:
printf("选择错误,重新选择:\n");
break;
}
} while (choice != 1 && choice != 2);//选的不是0、1、2还得继续选
if (find == EOF)
{
//找不到
printf("查无此人,退出查找:\n");
return;
}
//找到了
printf("此人信息为:\n");
printf("姓名:%s\n", pc->arr[find].name);
printf("性别:%s\n", pc->arr[find].gender);
printf("电话号码:%s\n", pc->arr[find].tele);
printf("年龄:%d\n", pc->arr[find].age);
printf("地址:%s\n", pc->arr[find].address);
}
void DelContact(Contact* pc)
{
assert(pc);
printf("请输入要删除人的姓名:\n");
char name[20] = "happy";
scanf("%s", name);
int find = FindByName(pc, name);
if (find == EOF)
{
printf("查无此人:\n");
return;
}
SeqListErase(pc, find);
}
void ModifyContact(Contact* pc)
{
assert(pc);
printf("请输入要修改的人的姓名:\n");
char name[20] = "happy";
scanf("%s", name);
int find = FindByName(pc, name);
if (find == EOF)
{
printf("查无此人:\n");
return;
}
printf("请输入新联系人姓名:\n");
scanf("%s", pc->arr[find].name);
printf("请输入新联系人性别:\n");
scanf("%s", pc->arr[find].gender);
printf("请输入新联系人电话号码:\n");
scanf("%s", pc->arr[find].tele);
printf("请输入新联系人年龄:\n");
scanf("%d", &pc->arr[find].age);
printf("请输入新联系人地址:\n");
scanf("%s", pc->arr[find].address);
printf("修改成功:\n");
}
void ShowContact(Contact* pc)
{
assert(pc);
printf("--------------------------------------\n");
printf(" 姓名 性别 电话号码 年龄 地址 \n");
for (int i = 0; i < pc->size; i++)
{
printf("| %s | %s | %s | %d | %s |\n", pc->arr[i].name,
pc->arr[i].gender,
pc->arr[i].tele,
pc->arr[i].age,
pc->arr[i].address);
}
printf("--------------------------------------\n");
}
使用部分:
#define _CRT_SECURE_NO_WARNINGS 1
#include "SeqList.h"
void TestContact()
{
Contact con;
InitContact(&con);
AddContact(&con);
AddContact(&con);
FindContact(&con);
}
enum Contacts
{
Exit,
Add,
Delete,
Modify,
Find,
Show,
};
void menu()
{
printf("**************************************************\n");
printf("**********************通讯录***********************\n");
printf("********** 1.新增联系人 2.删除联系人 **********\n");
printf("********** 3.修改联系人 4.查找联系人 **********\n");
printf("********** 5.展示通讯录 0.退出通讯录 **********\n");
printf("**************************************************\n");
printf("**************************************************\n");
}
int main()
{
Contact con;
InitContact(&con);
//TestContact();
int option = 0;
do
{
menu();
printf("请选择:");
scanf("%d", &option);
switch (option)
{
case Add:
AddContact(&con);
break;
case Delete:
DelContact(&con);
break;
case Modify:
ModifyContact(&con);
break;
case Find:
FindContact(&con);
break;
case Show:
ShowContact(&con);
break;
case Exit:
printf("退出通讯录:\n");
break;
default:
printf("选择错误,重新选择:\n");
break;
}
} while (option);
DestoryContact(&con);
return 0;
}