顺序表的应用

顺序表的应用

前情回顾

在这里插入图片描述

在指定位置插入数据

在这里插入图片描述

代码如下:

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;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值