一、前言
1、实现通讯录首先我们要了解并懂得如何通过C语言来完成有关顺序表的实现
2、需要了解的内容:如何使用顺序表结构实现增、删、改、查等操作
二、顺序表的认识和实现
1、什么是顺序表
最基础的数据结构就是数组。
顺序表则是线性表的一种,常见的线性表有:顺序表、链表、栈、队列等。线性表在逻辑上是线性结构,但是在物理上不一定是连续的。
2、顺序表的与数组的不同
顺序表的底层是数组,但是增加了一些封装起来的方法,实现了数组不能实现的一些接口。
3、顺序表的分类
静态顺序表:
使用固定长度的数组存储元素,静态顺序表的缺点就是内存的固定性,大多数情况下会出现内存给大了会造成浪费,给少了不够用的情况,而动态顺序表就很大程度的解决了这个问题。
动态顺序表:
使用变长数组来存储元素,动态顺序表就很大程度的解决了静态顺序表内存浪费和不够用的问题,在创建之初不给值或者给较小值,之后每次出现不够的情况就扩容数组(malloc\calloc\realloc)。
4、实现一个顺序表
创建结构体变量:
typedef int SLtypeDate;//重定义int为SLtypeDate方便后续需要更改数据时使用typedef struct SeqList
{SLtypeDate* arr;int size;//有效数据个数int capcity;//当前最大空间
}SL;//重定义结构体类型为SL
结构体初始化:
在.h文件中先进行声明
//初始化
void SLInit(SL* ps);
然后在.c文件中实现
#include"SeqList.h"//使用前需要引入我们写好的头文件//初始化
void SLInit(SL* ps)
{ps->arr = NULL;//在这个不赋值ps->size = 0;ps->capcity = 0;
}
实现增、删、查、改功能:
(1)增
//将判断空间是否足够封装为一个函数
void SLCheckCapcity(SL * ps)
{if (ps->capcity == ps->size){//判断capcity是否为0int newcapcity = ps->capcity == 0 ? 4 : 2 * ps->capcity;//使用realloc进行扩容SLtypeDate* tmp = (SLtypeDate*)realloc(ps->arr, newcapcity * sizeof(SLtypeDate));//由于realloc是有可能不成功的,所以要进行判断,并且不能直接赋值给结构体,避免原数据丢失if (tmp == NULL){perror("realloc");exit(1);}ps->arr = tmp;ps->capcity = newcapcity;}
}
void SLPushBack(SL*ps, SLtypeDate x)
{assert(ps);//插入数据要先判断内存够不够 相等则说明内存不够SLCheckCapcity(ps);ps->arr[ps->size++] = x;
}
//头插
void SLPushFront(SL* ps, SLtypeDate x)
{assert(ps);SLCheckCapcity(ps);for (int i = ps->size; i > 0; i--){ps->arr[i] = ps->arr[i - 1];}ps->arr[0] = x;ps->size++;
}
//在指定位置之前插入数据
void SLInsert(SL* ps, int pos, SLtypeDate x)
{assert(ps);//因为是之前所以可以等于assert(pos >= 0 && pos <= ps->size);SLCheckCapcity(ps);for (int i = ps->size; i > pos; i--){ps->arr[i] = ps->arr[i - 1];}ps->arr[pos] = x;ps->size++;
}
(2)删
//删除->尾删
void SLPopBack(SL* ps)
{assert(ps);assert(ps->size);ps->size--;
}
//删除->头删
void SLPopFront(SL* ps)
{assert(ps);assert(ps->size);for (int i = 0; i < ps->size-1; i++){ps->arr[i] = ps->arr[i + 1];}ps->size--;
}
//指定位置删除
void SLErase(SL* ps, int pos)
{assert(ps);assert(pos >= 0 && pos < ps->size);assert(ps->size);for (int i = pos; i < ps->size; i++){ps->arr[i] = ps->arr[i + 1];}ps->size--;
}
(3)查
int SLFind(SL* ps, SLtypeDate x)
{int i = 0;int flag = -1;for(i = 0;i<ps->size;i++){if (ps->arr[i] == x){return i;}}return flag;
}
(4)改
//修改
void SLModify(SL* ps, int pos, SLtypeDate x)
{assert(ps);assert(pos >= 0 && pos < ps->size);ps->arr[pos] = x;
}
最后不要忘记销毁创建的空间
//销毁
void SLDestory(SL* ps)
{if (ps->arr){free(ps->arr);}ps->size = 0;ps->capcity = 0;
}
5、测试
这里只进行了部分测试,感兴趣的朋友可以全部测试一遍(个人练习时一定切记写出一个接口就测试一个接口,不要等好多个都写好了再测试,难以发现出现的问题!!!)
void SLTest3()
{SL ps;SLInit(&ps);//测试尾插SLPushBack(&ps, 1);SLPushBack(&ps, 2);SLPushBack(&ps, 3);SLPushBack(&ps, 4);SLPushBack(&ps, 5);SLModify(&ps, 3, 5);//打印函数SLPrint(ps);SLDestory(&ps);
}
int main()
{SLTest3();return 0;
}
三、通讯录的实现
1、通讯录的基本格式
菜单--选择要进行的项目--将用户选择的项目展示给用户
2、借助上面的顺序表实现通讯录
创建结构体变量
//实现通讯录#define NAME_MAX 20
#define GENDER_MAX 10
#define TEL_MAX 20
#define ADDR_MAX 20//创建一个结构体
//其中包含:姓名 性别 年龄 电话 住址typedef struct PersonInfo
{char name[NAME_MAX];char gender[GENDER_MAX];int age;char tel[TEL_MAX];char addr[ADDR_MAX];
}peoInfo;
结构体初始化
头文件声明
//对通讯录的操作实际是对顺序表的操作
//初始化之前要先给顺序表改个名字 叫通讯录
typedef struct SeqList Contact;//初始化
void ContactInit(Contact* con);
.c文件中实现
void ContactInit(Contact* con)
{//对通讯录的操作实际是对顺序表的操作SLInit(con);
}
(1)增
//插入数据
void ContactAdd(Contact* con)
{//首先创建一个缓冲区用来保存信息peoInfo 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);
}
(2)删
void ContactDel(Contact* con)
{assert(con);char name[NAME_MAX];printf("请输入要删除的联系人姓名:\n");scanf("%s",name);//将查询封装为一个方法,方便后续使用//for (int i = 0; i < con->size; i++)//{// //strcmp相等返回0,大于返回1,小于返回-1// if (strcmp(con->arr[i].name, name) == 0)// {// SLErase(con, i);// return i;// }//}//return -1;int find = FindByName(con,name);if (find < 0){printf("没有找到该联系人,删除失败!\n");}SLErase(con, find);printf("找到了,删除成功!\n");
}
(3)查
//查找成员
void ContactFind(Contact* con)
{assert(con);char name[NAME_MAX];printf("请输入要查找的联系人姓名:\n");scanf("%s", name);int find = FindByName(con, name);if (find < 0){printf("没有找到该联系人!\n");return;}printf("找到了,以下是该联系人信息!\n");printf("姓名\t性别\t年龄\t电话\t地址\n");printf("%s\t%s\t%d\t%s\t%s\n",con->arr[find].name,con->arr[find].gender,con->arr[find].age,con->arr[find].tel,con->arr[find].addr);
}
(4)改
//修改数据
void ContactModify(Contact* con)
{assert(con);assert(con);char name[NAME_MAX];printf("请输入要修改的联系人姓名:\n");scanf("%s", name);int find = FindByName(con, name);if (find < 0){printf("没有找到该联系人,删除失败!\n");}printf("请输入要添加的联系人姓名:\n");scanf("%s", con->arr[find].name);printf("请输入要添加的联系人性别:\n");scanf("%s", con->arr[find].gender);printf("请输入要添加的联系人年龄:\n");scanf("%d", &con->arr[find].age);printf("请输入要添加的联系人电话:\n");scanf("%s", con->arr[find].tel);printf("请输入要添加的联系人住址:\n");scanf("%s", con->arr[find].addr);printf("修改成功!\n");
}
(5)将数据展示给用户
//展示数据
void ContactShow(Contact* con)
{printf("姓名\t性别\t年龄\t电话\t地址\n");for (int i = 0; i < con->size; i++){printf("%s\t%s\t%d\t%s\t%s\n",con->arr[i].name,con->arr[i].gender,con->arr[i].age,con->arr[i].tel,con->arr[i].addr);}
}
同样最后不要忘记销毁在此中间创建的结构体以及申请的内存
//销毁
void ContactDestory(Contact* con)
{SLDestory(con);
}