C语言实现顺序表及顺序表的应用--》通讯录

顺序表

声明:本文是我这个小菜鸟学习时记录下来的,如有意见,请提出,咱们友好探讨,共同进步,感谢。

顺序表其实是一种线性表

顺序表底层是数组,对数组进行了封装,实现了增删改查等接口

线性表结构特点:

物理结构:不一定是线性的(指的是元素不一定在内存中连续存放)

逻辑结构:一定连续

顺序表结构特点:

物理结构:线性

逻辑结构:线性

顺序表分类:静态和动态

静态有明显的缺点:空间给小了不够用;给多了又太过于浪费;分配不够灵活

所以咱一般用动态顺序表

方便:动态增容(成2到3倍增加)

实现顺序表的时候,最好是分两个文件,

一个.h文件,里面放着需要用到的头文件,顺序表的声明,顺序表需要的各种功能的实现函数的声明,  在这里我根据个人习惯,命名为seqlist.h

另一个是.c或者.cpp文件,该文件直接#include”seqlist.h” 引用自己写的头文件,简洁,且条理清晰  该.c或者.cpp文件内,写顺序表需要的各种功能的实现函数

如果要使用顺序表以及它的各种功能,那么就新建一个.cpp或者.c文件,引用自己写的头文件(因为头文件中有相关函数的声明),就可以直接进行测试辣  

要想实现顺序表的各种功能,咱们首先需要干嘛呢?

typedef struct SeqList

{

SqlDataType* memberlist;   //此为顺序表的数组部分  用指针的原因:方便增容与存储数据   

int size;          

int box;

}SqL;

用顺序表之前,需要干什么呢?---》初始化

void SqLInit(SqL* ps)    //顺序表初始化

{

ps->memberlist = NULL;    //顺序表数组部分的初始化

ps->size = 0;         //有效数据个数  --》初始化为0代表啥也没存

ps->box = 10;         //当前的空间容量

}

有初始化,那自然也有销毁对吧!---》销毁

//顺序表的销毁

void SqLDestroy(SqL* ps)

{

//咱们写的是动态顺序表,会用到malloc calloc realloc这些函数,所以要手动释放,且必须注意,不能释放空指针NULL

if (ps->memberlist != NULL)   

{

free(ps->memberlist);

}

ps->memberlist = NULL;

ps->size = 0;

ps->box = 0;

}

----------------------元素插入部分--------------------

头插:即把顺序表所有元素后移一位,然后在头部空出来的那个位置插入元素

void SqLPushHead(SqL* ps, SqLDataType x)   //(顺序表地址,要插入的数据)

{

//阻止空指针的传入

assert(ps);

//首先检测空间够不够

if (ps->size == ps->box)

{

SqLExpanse(ps);

}

for (int i = ps->size - 1; i >= 0; i--)

{

ps->memberlist[i + 1] = ps->memberlist[i];

}

ps->memberlist[0] = x;

ps->size++;

}

尾插:在顺序表最后一个元素后面插入元素

void SqLPushBack(SqL* ps, SqLDataType x)    //(顺序表地址,要插入的数据)   --测试一下

{

//阻止空指针的传入

assert(ps);  

if (ps->size == ps->box)  //先检查一下,顺序表还有没有剩余空间

{

//进来了就是没剩余空间辣,需要申请

SqLExpanse(ps); 

}

ps->memberlist[ps->size] = x;   //size为有效元素个数,第size个有效元素下标为(size-1),所以下标为size的地方,就是我们尾插元素的地方

ps->size++;   //有效元素又多了一个

}

中插:选定一个元素(以下标的方式),在其前/后插入元素

//3.中插--》在某个数据前/后插入数据    我这里就写在某个数据前插入吧

void SqLPushInside(SqL* ps, int position, SqLDataType x)   //(顺序表地址,要找到的数据的下标,在找到的数据前/后插入的数据)

{

//阻止空指针的传入

assert(ps);

//限制position的大小  

assert(position >= 0 && position <= ps->size);  //position=size时

//首先检测空间够不够

if (ps->size == ps->box)

{

SqLExpanse(ps);

}

for (int i = ps->size-1; i >=position; i--)

{

ps->memberlist[i+1] = ps->memberlist[i];

}

ps->memberlist[position] = x;

ps->size++;

}

有插入元素,那自然会有删除元素

---------------元素删除部分-------------------

//尾删

void SqLDelBack(SqL* ps)    //(顺序表地址,要插入的数据)   

{

//阻止空指针的传入

assert(ps);

if (ps->size == 0)

{

printf("删除失败!顺序表中并未存放数据\n");

return;

}

ps->memberlist[ps->size] = 0;   //size为有效元素个数,第size个有效元素下标为(size-1),所以下标为size的地方,就是我们尾插元素的地方

ps->size--;   //有效元素又少了一个

}

//头删

void SqLDelHead(SqL* ps)   //(顺序表地址,要插入的数据)

{

//阻止空指针的传入

assert(ps);

if (ps->size == 0)

{

printf("删除失败!顺序表中并未存放数据\n");

return;

}

for (int i = 0; i < ps->size-1; i++)

{

ps->memberlist[i] = ps->memberlist[i+1];

}

ps->size--;

}

//中删

void SqLDelInside(SqL* ps, int position)

{

//阻止空指针传入

assert(ps);

for (int i = position; i < ps->size-1; i++)

{

ps->memberlist[i] = ps->memberlist[i + 1];

}

ps->size--;

}

查找数据

//顺序表的查找   --导向可以是数据本身,也可以是下标    --》在顺序表的应用里面,

//我这里写的是数据本身为导向

void SqLSearch(SqL* ps, SqLDataType x)

{

//阻止空指针传入

assert(ps);

for (int i = 0; i < ps->size; i++)

{

if (ps->memberlist[i] == x)

{

printf("找到了!\n");

printf("该数据下标为%d\n",i);

return; 

}

}

//走到这说明没找到

printf("该数据不存在!\n");

return;

}

到这里顺序表的基础增删改查都完事辣,是时候整些更高级的东西了

----------------------------顺序表的应用:通讯录-----------------------------

SqLDataType x  ---x的数据类型,可以是int,可以是char等等,那当然也可以是结构体类型

想象一下,顺序表的每个位置上,存着一个结构体变量,该变量里存储着联系人的年龄等个人信息

如下图

在这里,

我们又要新建一个头文件叫contact.h,用于通讯录中:

  1. 储存个人信息的结构体变量初始化
  2. 各种功能函数的声明

还要新建一个源文件contact.cpp,用于:各种函数的实现

在顺序表的基础上,做出如下改变:

  1. 把存储的数据类型改成“个人信息”这个结构体
  2. 在顺序表功能的实现函数的基础上稍微加一点东西,让他适配通讯录

不多bb,直接上代码

Seqlist.h

#include<stdio.h>

#include<stdlib.h>

#include<assert.h>

//typedef int SqLDataType;

typedef struct PersonalInformation SqLDataType;   

typedef struct SeqList

{

SqLDataType* memberlist;   //此为顺序表的数组部分  用指针的原因:方便增容与存储数据   

int size;            //有效内容个数

int box;            //当前最大空间大小

}SqL;

//顺序表的初始化     

void SqLInit(SqL* ps);

//顺序表的销毁

void SqLDestroy(SqL* ps);

//顺序表的空间申请-->扩容

void SqLExpanse(SqL* ps);

//顺序表的数据插入

//1.尾插

void SqLPushBack(SqL* ps, SqLDataType x);

//2.头插

void SqLPushHead(SqL* ps, SqLDataType x);

//3.中插--》在某个数据前/后插入数据

void SqLPushInside(SqL* ps, int position, SqLDataType x);

//顺序表的数据删除

//尾删

void SqLDelBack(SqL* ps);

//头删

void SqLDelHead(SqL* ps);

//中删

//void SqLDelInside(SqL* ps, int position);

   通讯录特供版中删

void SqLDelInside(SqL* ps,char name);

//改

  //通讯录特供版改数据

void SqLChangeInside(SqL* ps, char named);

//顺序表的查找   --导向可以是数据本身,也可以是下标    --》在顺序表的应用里面,

void SqLSearch(SqL* ps, char named);

//顺序表的打印

void SqLPrint(SqL* ps);

-----------------------------------------------------------------------------------------------------------------

Contact.h

#include"seqlist.h"

#define NAME_MAX 20    

#define GENDER_MAX 20

#define PHONENUM_MAX 20

#define ADDRESS_MAX 20

typedef struct PersonalInformation     //这个结构体,作为顺序表中储存的元素

{

char name[NAME_MAX];   //名字

char gender[GENDER_MAX];   //性别

int age;  //年龄

char phonum[PHONENUM_MAX];

char address[ADDRESS_MAX];

}Personel;

//菜单

void menu();

//通讯录创建

void ContactInit(SqL *sl);

//通讯录销毁

void ContactDestroy(SqL *sl);

//增加数据 ---》使用尾插

void ContactInput(SqL *sl);

//删除数据 --》选择删除 --》输入名字,找到就删,找不到就报个查不到

void ContactDel(SqL *sl);

//改变数据  --》选择改变 --》输入名字,找到就可以改,找不到就报个查不到

void ContactChange(SqL *sl);

//查询数据 --》输入名字查找

int ContactSearchByname(SqL *sl);

//打印数据

void ContactPrint(SqL *sl);

//把写入的联系人信息保存到文件

void ContactSavetoFile(SqL *sl);

//从文件读取已保存的通讯录

void ContactLoadFile(SqL *sl);

以上都是头文件,里面都是函数的声明,需要用到的头文件的包含等

接下来看源文件

Contact.cpp

#define _CRT_SECURE_NO_WARNINGS 1

#include"contact.h"

void menu()

{

int n = 0;

SqL sl;

ContactInit(&sl);

ContactLoadFile(&sl);

while (1)

{

printf("-------------------------------------------------------\n");

printf("-------------------------------------------------------\n");

printf("--------------------Contact List-----------------------\n");

printf("-------------------------------------------------------\n");

printf("-------------------------------------------------------\n");

printf("------------------1.Add Contacts-----------------------\n");

printf("-------------------------------------------------------\n");

printf("------------------2.Delete Contacts--------------------\n");

printf("-------------------------------------------------------\n");

printf("------------------3.Change Infomation------------------\n");

printf("-------------------------------------------------------\n");

printf("------------------4.Show   Contacts--------------------\n");

printf("-------------------------------------------------------\n");

printf("------------------ElseChoice====>exit------------------\n");

printf("-------------------------------------------------------\n");

printf("-------------------------------------------------------\n");

printf("请选择:");

scanf("%d", &n);

if (n == 1)

{

ContactInput(&sl);

continue;

}

else if (n == 2)

{

ContactDel(&sl);

continue;

}

else if (n == 3)

{

ContactChange(&sl);

continue;

}

else if (n == 4)

{

ContactPrint(&sl);

continue;

}

else

{

ContactSavetoFile(&sl);

ContactDestroy(&sl);

return;

}

} 

}

//通讯录创建

void ContactInit(SqL *sl)

{

SqLInit(sl);

}

//通讯录销毁

void ContactDestroy(SqL *sl)

{

SqLDestroy(sl);

}

//增加数据 ---》使用尾插

void ContactInput(SqL *sl)

{

SqLDataType x;

printf("请输入联系人姓名\n");

scanf("%s", &x.name);

printf("请输入联系人性别\n");

scanf("%s", &x.gender);

printf("请输入联系人年龄\n");

scanf("%d", &x.age);

printf("请输入联系人电话号码\n");

scanf("%s", &x.phonum);

printf("请输入联系人住址\n");

scanf("%s", &x.address);

SqLPushBack(sl, x);

}

//删除数据 --》选择删除 --》输入名字,找到就删,找不到就报个查不到

void ContactDel(SqL *sl)

{

int pos = ContactSearchByname(sl);

SqLDelInside(sl, pos);

printf("删除完成!\n");

printf("\n");

}

//改变数据  --》选择改变 --》输入名字,找到就可以改,找不到就报个查不到

void ContactChange(SqL *sl)

{

//错误示范-------------------------------------------------------------

// /*char named[NAME_MAX];    

// printf("请输入联系人姓名\n");

// scanf("%s",named);*/

// SqLChangeInside(sl, named[0]);

//

// /*int i = 0;

// int j = 0;

//

// for (i = 0; i < sl->size; i++)

// {

// if (0 == strcmp(sl->memberlist[i].name, named))

// {

// printf("找到了!\n");

// j = i;

// }

// }

//

// if (j == sl->size - 1)

// {

// printf("您要修改的联系人数据不存在!\n");

// return;

// }

//

// printf("请输入更改后的联系人姓名\n");

// scanf("%s", sl->memberlist[j].name);

// printf("请输入更改后的联系人性别\n");

// scanf("%s", sl->memberlist[j].gender);

// printf("请输入更改后的联系人年龄\n");

// scanf("%d", &sl->memberlist[j].age);

// printf("请输入更改后的联系人电话号码\n");

// scanf("%s", sl->memberlist[j].phonum);

// printf("请输入更改后的联系人住址\n");

// scanf("%s", sl->memberlist[j].address);

//*/-------------------------------------------------------------------------

int ret = ContactSearchByname(sl);

if (ret < 0)

{

printf("该联系人不存在!\n");

return;

}

printf("请输入更改后的联系人姓名\n");

scanf("%s", sl->memberlist[ret].name);

printf("请输入更改后的联系人性别\n");

scanf("%s", sl->memberlist[ret].gender);

printf("请输入更改后的联系人年龄\n");

scanf("%d", &sl->memberlist[ret].age);

printf("请输入更改后的联系人电话号码\n");

scanf("%s", sl->memberlist[ret].phonum);

printf("请输入更改后的联系人住址\n");

scanf("%s", sl->memberlist[ret].address);

//测试用

printf("更改成功\n");

}

//查询数据 --》输入名字查找

int ContactSearchByname(SqL *sl)

{

char named[NAME_MAX];

printf("请输入要查找的联系人姓名: \n");

scanf("%s", named);

int i = 0;

for (i = 0; i < sl->size; i++)

{

if (0 == strcmp(sl->memberlist[i].name, named))

{

printf("找到了!\n");

return i;

}

}

//到这里了就是没找到

return -1;

}

//打印数据

void ContactPrint(SqL *sl)

{

SqLPrint(sl);

}

//把写入的联系人信息保存到文件

void ContactSavetoFile(SqL *sl)

{

FILE* pfdata = fopen("text.txt", "wb");  //开二进制文件

if (pfdata == NULL)  //判断上一步是否成功

{

perror("pfdata");

return;

}

for (int i = 0; i < sl->size; i++)

{

fwrite(sl->memberlist + i, sizeof(Personel), 1, pfdata);  //写入二进制文件

}

printf("数据已存入文件\n");

fclose(pfdata);

pfdata = NULL;

}

//从文件读取已保存的通讯录

void ContactLoadFile(SqL *sl)     

{

FILE* pfdata = fopen("text.txt", "rb");  //开二进制文件

if (pfdata == NULL)

{

perror("pfdata");

return;

}

Personel tem;

Personel *temp1 = &tem;   //中继器

while (fread(temp1, sizeof(Personel), 1, pfdata))  //这里用不了for  用while,为真就一直读,读到没有为止

{

SqLPushBack(sl, *temp1);

}

printf("文件中的数据已导入\n");

fclose(pfdata);

pfdata = NULL;

}

结尾处有两个文件操作函数,作用是把每次通讯录里面写的东西保存到test.txt这个文件,下次打开通讯录的时候还能读出来

通讯录中的函数基本上都是基于顺序表的,通讯录本质上就是顺序表,顺序表中储存的元素是包含了个人信息的结构体

本文到此结束,如有错误,敬请指正

  • 25
    点赞
  • 15
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值