顺序表的应用
顺序表的应用
前情回顾
在指定位置插入数据
代码如下:
void SLInsert(SL* ps, int pos, SLDataType x)
{assert(ps);assert(pos >= 0 && pos <= ps->size);//pos=ps->size相当于尾插//插入数据看空间大小够不够SLCheckCapacity(ps);//让pos及之后的数据的数据往后挪动一位for (int i =ps->size; i > pos; i--){ps->arr[i] = ps->arr[i - 1];}ps->arr[pos] = x;ps->size++;
}
在指定位置删除数据
特别注意:
assert(ps >= 0 && pos < ps->size);
这里pos不可以等于ps->size,因为size是有效个数的下一位,删去一位之后位置就空了一位,就没有意义
代码如下:
void SLErase(SL* ps, int pos)
{assert(ps);assert(ps >= 0 && pos < ps->size);for (int i = pos; i < ps->size - 1; i--){ps->arr[i] = ps->arr[i + 1];//arr[size-2]=arr[size-1]}ps->size--;
}
查找数据
//查找
void SLFind(SL* ps, SLDataType x)
{assert(ps);for (int i = 0; i < ps->size; i++){//找到了if (ps->arr[i] == x){return i;}}//找不到return -1;//返回不存在的下标,-2,-3都可以
}
基于顺序表实现通讯录项目
这个代表有个联系人
这个是联系人里面所要存储的信息
写通讯录就相当于写一个结构体的顺序表
详情如下:
顺序表里面可以存放内置的数据:int, char,也可以是自定义类型如结构体
接下来是一个大体的框架:
为什么在SeqList.h里面typedef peoInfo SLDataType 不要加上struct呢?
根据前面学过的预处理相关的知识可以知道,我们这里包含了Contact.h这个头文件,就相当于Contact.h文件里面全部内容在SeqList.h里面,所以不用加struct
下图为模型:
小小补充:
关于scanf函数:
scanf("",);//双引号后面是变量的地址
如下:
int a;
scanf("%d",&a);
再看这个:
char name[10];
scanf("%s",name);//数组名就是sh
最终想要实现的形式:
代码过程如下:
Contact.h
#pragma once
#define NAME_MAX 20
#define GENDER_MAX 10
#define TEL_MAX 20
#define ADDR_MAX 100
//定义联系人数据结构
//姓名 性别 年龄 电话 地址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);//通讯录的销毁void ContactDestory(Contact* con);//通讯录添加数据void ContactAdd(Contact* con);//通讯录删除void ContactDel(Contact* con);//通讯录的修改void ContactModify(Contact* con);//通讯录的查找void ContactFind(Contact* con);//通讯录的展示void ContactShow(Contact* con);
Contact.c
#define _CRT_SECURE_NO_WARNINGS 1
#include "contact.h"
#include "SeqList.h"
void LoadContact(Contact* con) {FILE* pf = fopen("contact.txt", "rb");if (pf == NULL) {perror("fopen error!\n");return;}//循环读取⽂件数据peoInfo info;while (fread(&info, sizeof(peoInfo), 1, pf)){SeqListPushBack(con, info);}printf("历史数据导⼊通讯录成功!\n");
}
//通讯录的初始化
void ContactInit(Contact* con)
{//实际上要进行的顺序表的初始化//顺序表的初始化已经实现好了SLInit(con);LoadContact(con);
}
//通讯录的销毁
void ContactDestory(Contact* con)
{SLDestory(con);
}
//通讯录的添加
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);//实现了对顺序表
}
int FindByName(Contact* con, char name[])
{for (int i = 0; i < con->size; i++){if (0 == strcmp(con->arr[i].name, name)){return i;//找到了}else{return -1;//没找到,返回一个无效指令}}
}
//通讯录的删除
void ContactDel(Contact* con)
{//要删除的数据必须要存在,才能被执行删除操作//查找char name[NAME_MAX];printf("请输入要删除的联系人的姓名:\n");scanf("%s",name);int Find = FindByName(con, name);if (Find < 0){printf("要删除的联系人数据不存在\n");return;}//要删除的联系人的数据存在--->知道了要删除的联系人数据对应的下标SLErase(con, name);printf("删除成功");
}
//通讯录的展示
void ContactShow(Contact* con)
{//表头:姓名,性别,年龄,电话,住址printf("%s %s %s %s %s\n", "姓名","性别","年龄","电话","住址");//遍历通讯录,按照格式打印出来for (int i = 0; i < con->size; i++){printf("%3s %3s %3d %3s %3s\n", con->arr[i].name, con->arr[i].gender, con->arr[i].age,con->arr[i].tel, con->arr[i].addr);}
}
//通讯录的修改
void ContactModify(Contact* con)
{//要修改的联系人信息存在char name[NAME_MAX];printf("请输入要修改的联系人的姓名:\n");scanf("%s", name);int Find = FindByName(con, name);if (Find < 0){printf("要修改的联系人数据不存在\n");return;}//直接修改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");
}
//通讯录的查找
void ContactFind(Contact* con)
{char name[NAME_MAX];printf("请输入要查找的联系人的姓名:\n");scanf("%s", name);int Find = FindByName(con, name);if (Find < 0){printf("要查找的联系人数据不存在\n");return;}printf("%s %s %s %s %s\n", "姓名", "性别", "年龄", "电话", "住址");printf("%3s %3s %3d %3s %3s\n", con->arr[i].name, con->arr[i].gender, con->arr[i].age,con->arr[i].tel, con->arr[i].addr);
}
void SaveContact( Contact* con) {FILE* pf = fopen("contact.txt", "wb");if (pf == NULL) {perror("fopen error!\n");return;}//将通讯录数据写⼊⽂件for (int i = 0; i < con->size; i++){fwrite(con->size, sizeof(peoInfo), 1, pf);}printf("通讯录数据保存成功!\n");
}
SeqList.h
#pragma once
#define _CRT_SECURE_NO_WARNINGS 1
#include <stdio.h>
#include <stdlib.h>
#include <assert.h>
#include "Contact.h"
//一般不推荐写静态顺序表
//以下是动态顺序表
typedef peoInfo SLDataType;
struct SeqList
{SLDataType* arr;int size;//有效的数据大小int capacity;//空间大小
}SL;
//顺序表的初始化
void SLInit(SL* ps);
//顺序表的销毁
void SLDestory(SL* ps);
//顺序表的打印
void SLPrint(SL s);
//头部插入删除 / 尾部插入删除
//插入
void SLPushBack(SL* ps, SLDataType x);
void SLPushFront(SL* ps, SLDataType x);
//删除
void SLPopBack(SL* ps);
void SLPopFront(SL* ps);void SLInsert(SL* ps, int pos, SLDataType x);
void SLErase(SL* ps, int pos);
void SLFind(SL* ps, SLDataType x);
SeqList.c
#define _CRT_SECURE_NO_WARNINGS 1
#include "SeqList.h"
//专门封装一个函数用来检查空间是否够不够
void SLCheckCapacity(SL* ps)
{//插入前先看空间够不够if (ps->capacity == ps->size){//温柔的解决方法if (ps == NULL){return;}//判断空间大小是否为0// 三目表达式int newCapacity = ps->capacity == 0 ? 4 : 2 * ps->capacity;//申请空间SLDataType* tmp = realloc(ps->arr, ps->newCapacity * 2 * sizeof(SLDataType));if (tmp == NULL){perror("realloc fail!");exit(1);}//空间申请成功ps->arr = tmp;ps->capacity = newCapacity;}
}
void SLInit(SL* ps)
{ps->arr = NULL;ps->size = ps->capcacity = 0;
}
void SLDestory(SL* ps)
{if (ps->arr){free(ps->arr);}ps->arr = NULL;ps->size = ps->capcacity = 0;
}
//尾插
void SLPushBack(SL* ps, SLDataType x)
{assert(ps);SLCheckCapacity(ps);//ps->arr[ps->size]=x;//++ps->size;ps->arr[ps->size++] = x;//这行代码是将上面的两行代码变成了一行代码,//对其size进行了后置++,提高程序运行效率
}
void SLPushFront(SL* ps, SLDataType x)
{assert(ps);SLCheckCapacity(ps);//先让顺序表已有的数据往后挪动一位for (int i = ps->size; i > 0; i--){ps->arr[i] = ps->arr[i - 1];//arr[1]=arr[0],最后一次情况是这样,由此来推断i的限制条件ps->size++;//特别要注意了}ps->arr = x;
}//void SLPrint(SL s)
//{
// for (int i = 0; i < s.size; i++)
// {
// printf("%d ", s.arr[i]);
// }
// printf("\n");
//}
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 < size - 2; i++){ps->arr[i] = ps->arr[i + 1];//arr[size-2]=arr[size-1];}ps->size--;
}
//在指定位置之前插入数据
void SLInsert(SL* ps, int pos, SLDataType x)
{assert(ps);assert(pos >= 0 && pos <= ps->size);//pos=ps->size相当于尾插//插入数据看空间大小够不够SLCheckCapacity(ps);//让pos及之后的数据的数据往后挪动一位for (int i =ps->size; i > pos; i--){ps->arr[i] = ps->arr[i - 1];}ps->arr[pos] = x;ps->size++;
}
void SLErase(SL* ps, int pos)
{assert(ps);assert(ps >= 0 && pos < ps->size);SLCheckCapacity(ps);for (int i = pos; i < ps->size - 1; i--){ps->arr[i] = ps->arr[i + 1];//arr[size-2]=arr[size-1]}ps->size--;
}
//查找
//void SLFind(SL* ps, SLDataType x)
//{
// assert(ps);
// for (int i = 0; i < ps->size; i++)
// {
// //找到了
// if (ps->arr[i] == x)
// {
// return i;
// }
// }
// //找不到
// return -1;//返回不存在的下标,-2,-3都可以
//}
test.c
#define _CRT_SECURE_NO_WARNINGS 1
#include "SeqList.h"
//int main()
//void SLTest01()
//{
// SL sl;
// SLInit(&sl);
// //增删查改操作
// //测试尾插
// SLPushBack(&sl, 1);
// SLPushBack(&sl, 2);
// SLPushBack(&sl, 3);
// SLPushBack(&sl, 4);
// //SLPushBack(NULL, 5);
// SLPrint(sl);
// SLPushFront(&sl, 6);
// SLPrint(sl);
// SLDestory(&sl);
//}
//void SLTest02()
//{
// SLInsert(&sl, 0, 99);
// SLErase(&sl, 0);
// SLPrint(sl);
// int find = SLFind(&sl, 4);
// if (find < 0)
// {
// printf("没有找到");
// }
// else
// {
// printf("找到了,下标为%d\n", find);
// }
//}
//void ContactTest01()
//{
// Contact con;//创建的通讯录对象 实际上就是 顺序表对象 等价于SL sl
// ContactInit(&con);
// ContactAdd(&con);
// ContactShow(&con);
// ContactModify(&con);
// ContactFind(&con);
// ContactDel(&con);
// ContactShow(&con);
// ContactDestory(&con);
//}
void menu()
{printf("*************************\n");printf("*******1.添加2.删除******\n");printf("*******3.修改4.查找******\n");printf("*******5.查找0.退出******\n");
}
int main()
{//SLTest01();//ContactTest01();int op = -1;Contact con;ContactInit(&con);do{menu();printf("请选择您的操作:\n");scanf("%d", &op);//要根据对应的op执行对应的操作switch (op){case 1:ContactAdd(&con);break;case 2:ContactDel(&con);break;case 3:ContactModify(&con);break;case 4:ContactFind(&con);break;case 5:ContactShow(&con);break;case 0:printf("退出通讯录\n");default:break;}} while (op!=0);ContactDestory(&con);return 0;
}
***\n");
printf(“*5.查找0.退出\n”);
}
int main()
{
//SLTest01();
//ContactTest01();
int op = -1;
Contact con;
ContactInit(&con);
do
{
menu();
printf(“请选择您的操作:\n”);
scanf(“%d”, &op);
//要根据对应的op执行对应的操作
switch (op)
{
case 1:
ContactAdd(&con);
break;
case 2:
ContactDel(&con);
break;
case 3:
ContactModify(&con);
break;
case 4:
ContactFind(&con);
break;
case 5:
ContactShow(&con);
break;
case 0:
printf(“退出通讯录\n”);
default:
break;
}
} while (op!=0);
ContactDestory(&con);
return 0;
}