一.题目要求
今天来和大家分享一个简易通讯录(C语言实现)
首先要介绍一下通讯录的基本功能
添加联系人信息
删除指定联系人信息
查找指定联系人信息
修改指定联系人信息
显示所有联系人信息
二.思路分析
1. 首先需要定义通讯录的数据结构,可以使用结构体来表示每个联系人的信息,包括姓名、电话号码、地址等。
2. 接着需要定义一个数组来存储所有联系人的信息,数组的大小可以根据实际需求进行调整。
3. 编写程序菜单,包括添加联系人、删除联系人、查找联系人、显示所有联系人等功能。
4. 在添加联系人功能中,需要让用户输入联系人的信息,并将其存储到数组中。
5. 在删除联系人功能中,需要让用户输入要删除的联系人姓名,并在数组中查找并删除该联系人的信息。
6. 在查找联系人功能中,需要让用户输入要查找的联系人姓名,并在数组中查找并显示该联系人的信息。
7. 在显示所有联系人功能中,需要遍历数组并逐个显示每个联系人的信息。
8. 最后,可以使用文件读写功能将通讯录数据保存到文件中,以便下次启动程序时可以读取之前保存的数据。
总结,考虑到数据结构中的顺序表和单链表,我们可以采用这两种结构来实现。本文选择使用顺序表来实现,下一章可以通过单链表来实现。
三.各部分功能实现
1.定义通讯录结构
在声明线性表的顺序存储类型时,定义一个data数组来存储线性表中的所有元素,定义一个整型变量length来存储线性表的实际长度,并采用结构体类型SqList表示。
//定义通讯录结构表 typedef struct { char name[20]; char tel[15]; } Elemtype; //声明顺序表 typedef struct { Elemtype data[MaxSize]; //存放线性表中的元素是Elemtype所指代的通讯录结构体 int length; //存放线性表的长度 } SqList; //表示本次实验使用顺序表类型来完成通讯录的建立
2.初始化以及销毁线性表
- 初始化线性表:该运算的功能是构造一个空的线性表L,实际上只需要分配线性表的存储空间并将 Length 域设置为0即可。
- 销毁线性表:释放线性表L所占的内存空间。
//初始化线性表 void InitList(SqList *&L) { /*如果不方便理解,可以把L作为一个结构体指针,则下面操作可以理解为首先把分配的 一个结构体SqList一样大小的空间的首地址赋给L,L所指向的结构体中数据元素个数为0*/ L = (SqList * )malloc(sizeof(SqList)); L->length = 0; } //撤销(销毁)线性表 void DestroyList(SqList *&L) { free(L); //释放指针L指向的顺序表空间 }
3.插入数据元素
该运算在顺序表L的第 i (1≤i≤n+1)个位置上插人新元素e。如果 i 值不正确,返回false;否则将顺序表原来的第i个元素及以后的元素均后移一个位置,并从最后一个元素an开始移动起。腾出一个空位置插入新元素,最后顺序表的长度增1并返回true。算法如下:
//插入数据元素 bool ListInsert(SqList *&L, int i, Elemtype e) { /*在顺序表L的第i个位置上插入新元素e*/ int j; //参数i不正确时,返回false if (i < 1 || i > L->length + 1 || L->length == MaxSize) return false; i--; //将顺序表逻辑序号转化为物理序号 //参数i正确时,将data[i]及后面的元素后移一个位置 for (j = L->length; j > i; j--) { L->data[j] = L->data[j - 1]; } L->data[i] = e; //插入元素e L->length++; //顺序表长度加1 return true; }
4.删除数据元素
该运算删除顺序表L的第 i (1≤i≤n)个元素。如果i值不正确,返回false;否则线性表第 i 个元素以后的元素均向前移动一个位置,并从元素a(i+1)开始移动起,这样覆盖了原来的第 i个元素,达到了删除该元素的目的,最后顺序表的长度减1并返回true。算法如下:
//删除数据元素 bool ListDelate (SqList *&L, int i, Elemtype &e) { /*删除顺序表中的第i个元素,其值为e*/ int j; if (i < 1 || i > L->length) return false; i--; //将顺序表逻辑序号转化为物理序号 e = L->data[i]; //参数正确时,将data[i]之后的元素前移一个位置 for (j = i; j < L->length - 1; j++) L->data[j] = L->data[j + 1]; L->length--; //顺序表的长度减1 return true; }
5.输出线性表
- 依次显示L中各元素的值
//输出线性表 void DispList(SqList *L) { if (L->length == 0) printf("线性表为空"); //扫描顺序表,输出各元素 for (int i = 0; i < L->length; i++) { printf("%s %s", L->data[i].name, L->data[i].tel); printf("\n"); } printf("\n"); }
6.求某个数据元素值
- 该运算用应用型参数e返回L中第i个元素的值
//求某个数据元素值 bool GetElem(SqList *L, int i, Elemtype &e) { if (i < 1 || i > L->length) return false; //参数i错误时,返回false e = L->data[i - 1]; //取元素值 return true; }
7.元素查找
- 该运算顺序查找第一个值域与e相等的元素的逻辑序号(找到后返回一个大于0的值),若这样的元素不存在,则返回值为0。
//元素查找 int LocateElem(SqList *L, Elemtype e) { /*顺序查找第一个值域与e相等的元素逻辑序号(根据e找i)*/ int i = 0; //while循环查找e while (i < L->length && strcmp(L->data[i].name, e.name) != 0) i++; if (i >= L->length) return 0; //未找到返回0 else printf("%s %s\n",L->data[i].name,L->data[i].tel); return i + 1; //找到后返回其逻辑序号 }
四. 完整代码
#include <stdlib.h> #include <stdio.h> #include <string.h> #define MaxSize 50 //定义通讯录结构表 typedef struct { char name[20]; char tel[15]; } Elemtype; //声明顺序表 typedef struct { Elemtype data[MaxSize]; //存放线性表中的元素是Elemtype所指代的通讯录结构体 int length; //存放线性表的长度 } SqList; //表示本次实验使用顺序表类型来完成通讯录的建立 /*我们这里可以有两种思路来完成顺序表的建立, 第一(整体创建):由数组元素a[0···n-1]创建顺序表L,即将数组a中的每个元素依次放入顺序表中,并将n赋给顺序表的长度域。 前提是已经有一个数组存在,把它作为建立顺序表函数的参数进行传入。 第二(添加创建):先初始化一个空的顺序表,然后通过顺序表的添加元素函数进行补充,从而构建一个完整的顺序表。 */ //初始化线性表 void InitList(SqList *&L) { /*如果不方便理解,可以把L作为一个结构体指针,则下面操作可以理解为首先把分配的 一个结构体SqList一样大小的空间的首地址赋给L,L所指向的结构体中数据元素个数为0*/ L = (SqList * )malloc(sizeof(SqList)); L->length = 0; } //撤销(销毁)线性表 void DestroyList(SqList *&L) { free(L); //释放指针L指向的顺序表空间 } //插入数据元素 bool ListInsert(SqList *&L, int i, Elemtype e) { /*在顺序表L的第i个位置上插入新元素e*/ int j; //参数i不正确时,返回false if (i < 1 || i > L->length + 1 || L->length == MaxSize) return false; i--; //将顺序表逻辑序号转化为物理序号 //参数i正确时,将data[i]及后面的元素后移一个位置 for (j = L->length; j > i; j--) { L->data[j] = L->data[j - 1]; } L->data[i] = e; //插入元素e L->length++; //顺序表长度加1 return true; } //删除数据元素 bool ListDelate (SqList *&L, int i, Elemtype &e) { /*删除顺序表中的第i个元素,其值为e*/ int j; if (i < 1 || i > L->length) return false; i--; //将顺序表逻辑序号转化为物理序号 e = L->data[i]; //参数正确时,将data[i]之后的元素前移一个位置 for (j = i; j < L->length - 1; j++) L->data[j] = L->data[j + 1]; L->length--; //顺序表的长度减1 return true; } //输出线性表 void DispList(SqList *L) { if (L->length == 0) printf("线性表为空"); //扫描顺序表,输出各元素 for (int i = 0; i < L->length; i++) { printf("%s %s", L->data[i].name, L->data[i].tel); printf("\n"); } printf("\n"); } //求某个数据元素值 bool GetElem(SqList *L, int i, Elemtype &e) { if (i < 1 || i > L->length) return false; //参数i错误时,返回false e = L->data[i - 1]; //取元素值 return true; } //元素查找 int LocateElem(SqList *L, Elemtype e) { /*顺序查找第一个值域与e相等的元素逻辑序号(根据e找i)*/ int i = 0; //while循环查找e while (i < L->length && strcmp(L->data[i].name, e.name) != 0) i++; if (i >= L->length) return 0; //未找到返回0 else printf("%s %s\n",L->data[i].name,L->data[i].tel); return i + 1; //找到后返回其逻辑序号 } //菜单实现 void menu() { printf(" -------------------------------\n"); printf(" 通讯录的应用:\n"); printf(" -------------------------------\n"); printf(" 1.建立(初始化)通讯录\n"); printf(" 2.显示联系人信息\n"); printf(" 3.增加联系人信息\n"); printf(" 4.删除联系人信息\n"); printf(" 5.查找联系人信息\n"); printf(" 6.退出程序!!!\n"); printf(" -------------------------------\n"); } int main() { SqList *L; int flag = 1; //定义循环体条件 int i, j; //存放用户输入的选项 Elemtype a[4] = {"张三", "15671580583", "李四", "13387592396", "王五", "15994272725", "赵六", "15972200598"}; Elemtype e; menu(); printf("初始化顺序表并插入开始元素:\n"); InitList(L); //这时是一个空表,接下来通过插入元素函数完成初始化 for (int i = 0; i < 4; i++) ListInsert(L, i + 1, a[i]); DispList(L); while (flag == 1) { printf("请输入你的选择:\n"); scanf("%d", &j); switch (j) { case 1: printf("已经完成初始化\n"); break; case 2: DispList(L); break; case 3: printf("请输入联系人姓名与电话:"); scanf("%s %s", e.name, e.tel); printf("请输入插入数据的位置:"); scanf("%d", &i); printf("\n"); ListInsert(L, i, e); break; case 4: printf("请输入删除数据的位置:"); scanf("%d", &i); ListDelate(L, i, e); break; case 5: printf("请输入联系人姓名:"); scanf("%s", &e.name); LocateElem(L, e); break; case 6: flag = 0; printf("退出程序\n"); break; } } return 0; }
五.实验截图
补充:完整源代码在我上传的资源里有。