C语言顺序表的实现和应用

顺序表

顺序表的概念

• 顺序表是线性表的一种,即顺序表的逻辑结构是线性结构。
• 顺序表的物理结构也是线性的。
• 顺序表的底层是数组。
• 顺序表又分为静态顺序表和动态顺序表,如下:

//静态顺序表
struct Seqlist
{
	int a[100];//静态数组
	int size;//有效数据个数
}
//动态数据表
struct Seqlist
{
	int*a;
	int size;//有效数据个数
	int capacity;//顺序表当前的空间大小
}

• 实际情境中,使用动态顺序表的情况远远多于使用静态数据表的情况。因为,静态数据表空间少了会导致数据泄露、空间多了会导致空间浪费。

顺序表的创建

这里我们用动态顺序表作示范,此外,为了方便顺便表存储的数据类型可以方便改变,我们用typedef来重定义类型名:

typedef int SLDataType;
typedef struct SeqList
{
	SLDataType*a;
	int size;//有效数据个数
	int capacity;//顺序表空间大小
}SL;

顺序表初始化和销毁

• 注意实现初始化时,要传址调用。如果传值调用,那么只会对形参初始化。

void SLInit(SL*sp)
{
	SL->a=NULL;
	SL->size=SL->capacity=0;
}
void SLDestroy(SL*sp)
{
	if(SL->a)
	{
		free(SL->a);
		SL->a=NULL;
	}
	SL=NULL:
}

顺序表插入与删除

• 插入的方式有头插、尾插
• 删除的方式有头删、尾删
• 插入前需要判断空间是否足够、如果不够的话需要开辟空间。注意,频繁的扩容会降低数组的性能。为了提高性能我们通常进行1.5倍或者2倍的增容。

//检测是否空间足够
void SLCheckCapacity(SL*ps)
{
	if(ps->size==ps->capacity)
	{
		int NewCapacity=ps->capacity==0?4:2*ps->capacity;
		SLDataType*tmp=(SLDataType*)realloc(ps->a,NewCapacity*sizeof(SLDataType));//防止丢失顺序表地址
		if(!tmp)
		{
			perror("realloc");
			return 1;
		]
		ps->a=tmp;
		ps->capacity=NewCapacity;
	}
}
//尾插
void SLPushBack(SL*ps,SLDataType x)
{
	assert(ps);
	SLCheckCapacity(ps);
	ps->a[ps->size++]=x;
}
//头插
void SLPushFront(SL*ps,SLDataType x)
{
	assert(ps);
	SLCheckCapacity(ps);
	for(unsigned int i=ps->size;i>0;i--)
	{
		ps->a[i]=ps->a[i-1];
	}
	ps->a[0]=x;
}
//尾删
void SLPopBack(SL*ps)
{
	assert(ps&&ps->size);//size为0时不能删除
	ps->size--;
}
//头删
void SLPopFront(SL*ps)
{
	assert(ps&&ps->size);
	for(int i=0;i<size-1;i++)
	{
		ps->a[i]=ps->a[i+1];
	}
	ps->size--;
}
//在指定位置之前插入数据
void SLInset(SL*ps,int pos,SLDataType x)
{
	assert(ps);
	assert(pos >= 0 && pos <= ps->size);//可以在size处插入,相当于尾插
	SLCheckCapacity(ps);
	for (int i = ps->size; i > pos; i--)
	{
		ps->a[i] = ps->a[i - 1];
	}
	ps->a[pos] = x;
	ps->size++;
}
//删除指定位置数据
void SLErase(SL* ps, int pos)
{
	assert(ps && ps->size);
	assert(pos >= 0 && pos < ps->size);//不能在size处删除,因为不是有效数据
	for (int i = pos; i < ps->size - 1; i++)
	{
		ps->a[i] = ps->a[i + 1];
	}
	ps->size--;
}

顺序表的查找

当我们存储数据后,肯定想知道顺序表里面有没有想要的数据,这时可以定义一个查找函数。

bool SLFind(SL* ps, SLDataType x)
{
	assert(ps);
	for (int i = 0; i < ps->size; i++)
	{
		if (x == ps->a[i])
			return true;
	}
	return false;
}

那么以上就是顺序表的主要功能,接下来我们将基于顺序表实现通讯录。

通讯录

首先我们知道一个通讯录中通常存储电话号码、姓名、性别、住址、年龄等数据。我们要创建相应的结构体来存储数据。

创建

#define NAME_MAX 100
#define SEX_MAX 10
#define TEL_MAX 15
#define ADDR_MAX 100
typedef struct ContactInfo
{
	char name[NAME_MAX];
	char sex[SEX_MAX];
	int age;
	char tel[TEL_MAX];
	char addr[ADDR_MAX];
}CInfo;

初始化和销毁

·由于通讯录是基于顺序表实现的,所以我们能调用前面实现的顺序表函数来实现各种通讯录的功能。

void ContactInit(contact*pcon)
{
	SLInit(pcon);
}
void ContactDestroy(contact* pcon)
{
	SLDestroy(pcon);
}

添加、删除、修改联系人

int ContactExist(contact* pcon, char name[])
{
	assert(pcon);
	for (int i = 0; i < pcon->size; i++)
	{
		if (!(strcmp(pcon->a[i].name, name)))
			return i;
	}
	return -1;
}
void ContactAdd(contact* pcon)
{
	CInfo con;
	printf("请输入联系人的姓名:"); scanf("%s", con.name);
	printf("请输入联系人的号码:"); scanf("%s", con.tel);
	printf("请输入联系人的性别:"); scanf("%s", con.sex);
	printf("请输入联系人的年龄:"); scanf("%d", &con.age);
	printf("请输入联系人的地址:"); scanf("%s", con.addr);
	SLPushBack(pcon, con);
}
void ContactDel(contact* pcon)
{
	char name[NAME_MAX];
	printf("请输入要删除的联系人的姓名:"); scanf("%s", name);
	int x = ContactExist(pcon, name);
	if ( x< 0)
	{
		printf("不存在该联系人。\n");
		return;
	}
	SLErase(pcon, x);
}
void ContactModify(contact* pcon)
{
	assert(pcon);
	char name[NAME_MAX];
	printf("请输入要修改的联系人的姓名:"); scanf("%s", name);
	int x = ContactExist(pcon, name);
	if (x < 0)
	{
		printf("不存在该联系人。\n");
		return;
	}
	printf("请输入新的联系人的姓名:"); scanf("%s", pcon->a[x].name);
	printf("请输入新的联系人的号码:"); scanf("%s", pcon->a[x].tel);
	printf("请输入新的联系人的性别:"); scanf("%s", pcon->a[x].sex);
	printf("请输入新的联系人的年龄:"); scanf("%d", &pcon->a[x].age);
	printf("请输入新的联系人的地址:"); scanf("%s", pcon->a[x].addr);
	printf("修改成功!\n");
}

通讯录的查找指定联系人

void ContactFind(contact* pcon)
{
	assert(pcon);
	char name[NAME_MAX];
	printf("请输入要查找的联系人的姓名:"); scanf("%s", name);
	int x = ContactExist(pcon, name);
	if (x < 0)
	{
		printf("不存在该联系人。\n");
		return;
	}
	printf("%-10s|%-10s|%-10s|%-12s|%-10s\n", "姓名", "性别", "年龄", "号码", "住址");
	printf("%-10s|%-10s|%-10d|%-12s|%-10s\n", pcon->a[x].name, pcon->a[x].sex,
		pcon->a[x].age, pcon->a[x].tel, pcon->a[x].addr);
}

通讯录整体功能整合

void Menu()
{
	printf("*********************************************\n");
	printf("***************1.添加联系人******************\n");
	printf("***************2.删除联系人******************\n");
	printf("***************3.查看通讯录******************\n");
	printf("***************4.查找联系人******************\n");
	printf("***************5.修改联系人******************\n");
	printf("***************0.   退出   ******************\n");
	printf("*********************************************\n");
}
int main()
{
	int cho = 0;
	contact con;
	ContactInit(&con);
	do {
		Menu();
		printf("请输入你的选择:"); scanf("%d", &cho);
		switch (cho)
		{
		case 1:
			ContactAdd(&con);
			break;
		case 2:
			ContactDel(&con);
			break;
		case 3:
			ContactShow(&con);
			break;
		case 4:
			ContactFind(&con);
			break;
		case 5:
			ContactModify(&con);
			break;
		case 0:
			break;
		default:
			printf("非法输入,请重新输入:\n");
		}
	} while (cho != 0);
	ContactDestroy(&con);
	return 0;
}

·以上就是顺序表以及顺序表应用的所有内容了!

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值