【探索数据结构与算法(C语言)】——顺序表

💓 博客主页:C-SDN花园GGbond

⏩ 文章专栏:探索数据结构与算法

目录

1. 什么是顺序表

2. 顺序表的功能 

3. 顺序表的定义 

4. 功能的具体实现 

4.1 初始化顺序表

4.2 打印数据 

4.3 尾插数据 

4.4 尾删数据 

4.5 头删数据 

4.6 查找指定值

4.7 指定位置修改

4.8 指定位置插入  

4.9 指定位置删除

4.10 回收空间

5. 完整代码 


1. 什么是顺序表

顺序表是数据结构中最基本的一种线性表,它以一段连续的存储空间来存储数据元素,元素之间的顺序由它们在内存中的位置来决定。在C语言中,我们通常使用数组来实现顺序表 

2. 顺序表的功能 

顺序表可以大致包含以下几个功能:

1.初始化顺序表中的数据。

2.打印顺序表中的数据。

3.对顺序表进行尾插(末尾插入数据)。

4.对顺序表进行尾删(末尾删除数据)。

5.对顺序表进行头插(开头插入数据)。

6.对顺序表进行头删(开头删除数据)。

7.对顺序表就像查找数据。

8.对顺序表数据进行修改。

9.任意位置的删除和插入数据。

10.销毁顺序表。

3. 顺序表的定义 

定义顺序表我们首先需要一个动态内存开辟的空间,当前数据的个数(size),以及方便扩容的容量大小(capacity)

typedef int SLDataType; //类型重命名,方便后续修改类型
#define N 4 //初始化空间大小
typedef struct SeqList
{
	SLDataType* a;    //指向动态开辟的数组
	size_t size;      //有效数据个数
	size_t capacity;  //容量大小
}SeqList;

4. 功能的具体实现 

4.1 初始化顺序表

初始化顺序表时我们可以先开辟四个空间,之后不够再进行扩容

void SeqListInit(SeqList* p)
{
	assert(p);  //断言
	p->a =(SLDataType*)malloc(N*sizeof(SLDataType));  //初始顺序表为四个空间
	if (p->a== NULL)
	{
		perror("malloc fail:");
                return ;
	}
	p->size = 0;  //初始数据个数为0
	p->capacity = 4;  //初始空间容量为4
}
4.2 打印数据 

打印数据只用循环打印就可以了。

void SeqListPrint(const SeqList* p)
{
	assert(p);  //断言
	if (p->size == 0)  //判断顺序表是否为空
	{
		printf("顺序表为空\n");
		return;
	}

	int i = 0;
	for (i = 0; i < p->size; i++)  //打印顺序表
	{
		printf("%d ", p->a[i]);
	}
	printf("\n");
}
4.3 尾插数据 

尾插数据,顾名思义就是在顺序表末尾插入数据,在插入数据之前我们应该检查顺序表是否为满。

 (1) 检查是否已满

void CheckCapacity(SeqList* p)
{
	assert(p);  //断言
	if (p->size == p->capacity)  //检查容量,满了则增容
	{
		size_t newcapacity = 2 * p->capacity;  //,扩容为原来的2倍
		SLDataType* prt = (SLDataType*)realloc(p->a, newcapacity * sizeof(SLDataType));  //扩容
		if (prt == NULL)
		{
			perror("realloc fail:");
			return ;
		}
		p->a = prt;  // prt不为空,开辟成功
		p->capacity = newcapacity;  //更新容量
	}
}

(2) 插入数据 

void SeqListPushBack(SeqList* p, SLDataType x)
{
	assert(p);  //断言
	CheckCapacity(p);  //检查顺序表容量是否已满
	p->a[p->size] = x;  //尾插数据
	p->size++;  //有效数据个数+1
}
4.4 尾删数据 

同理,尾删数据就是删除顺序表中最后一个元素,我们只需将size–。注意:删除之前要保证顺序表中有数据

代码实现 :

void SeqListPopBack(SeqList* p)
{
	assert(p);  //断言
	assert(p->size > 0);  //顺序表不能为空
	p->size--;  //有效数据个数-1
}
4.5 头删数据 

 从头部删除数据,与尾部删除数据不同,需要依次往前覆盖。

代码实现: 

void SeqListPopFront(SeqList* p)
{
	assert(p);  //断言
	assert(p->size > 0);  //顺序表不能为空

	int i = 0;
	for (i = 1; i < p->size; i++)  //顺序表中[1,size-1]的元素依次向前挪动一位
	{
		p->a[i - 1] = p->a[i];
	}
	p->size--;  //有效数据个数-1
}
4.6 查找指定值

根据输入参数,在顺序表中查找指定的值并返回其下标,若未找到则返回-1。

代码实现: 

int SeqListFind(const SeqList* p, SLDataType x)
{
	assert(p);  //断言

	int i = 0;
	for (i = 0; i < p->size; i++)
	{
		if (p->a[i] == x)
		{
			return i;  //查找到,返回该值在数组中的下标
		}
	}
	return -1;  //没有查找到
}

4.7 指定位置修改

我们可以通过指定下标或者查找指定值的下标来修改任意位置的值。

代码实现 :

void SeqListModify(SeqList* p, int pos, SLDataType x)
{
	assert(p);  //断言
	assert(p->size > 0);  //顺序表不能为空
	assert(pos >= 0 && pos < p->size);  //检查pos下标的合法性
	p->a[pos] = x;  //修改pos下标处对应的数据
}
4.8 指定位置插入  

和前面其他插入一样,指定位置插入也需要判断是否扩容。


 代码实现 :

void SeqListInsert(SeqList* p, int pos, SLDataType x)
{
	assert(p);//断言
	assert(pos>=0&&pos <= p->size); //检查pos下标的合法性
	SeqListCheck(p);//检查是否需要扩容
	int cur = p->size;
	while (cur > pos)
	{
		p->a[cur] = p->a[cur - 1];//覆盖
		--cur;
	}
	p->a[pos] = x;
	p->size++;
}
4.9 指定位置删除

和前面的删除差不多,但是指定删除可能会依次覆盖

代码实现: 

void SeqListErase(SeqList* p, int pos)
{
	assert(p);  //断言
	assert(p->size > 0);  //顺序表不能为空
	assert(pos >= 0 && pos < p->size);  //检查pos下标的合法性
	int i = 0;
	for (i = pos + 1; i < p->size; i++)  //将pos位置后面的数据依次向前挪动一位
	{
		p->a[i - 1] = p->a[i];
	}
	p->size--;  //有效数据个数-1
}
4.10 回收空间

在结束操作之后,需要释放开辟的空间,以防止内存泄漏。

void SeqListDestory(SeqList* p)
{
	assert(p);  //断言
	free(p->a);   //释放动态开辟的空间
	p->a = NULL;  //置空
	p->size = 0;  //数据个数置0
	p->capacity = 0;  //空间容量大小置0
}

5. 完整代码 

 SeqList.h

#include<stdio.h>
#include<stdlib.h>
#include<assert.h>
#define N 4 //初始化空间大小
typedef int SLDataType; //类型重命名,方便后续修改类型
typedef struct SeqList
{
	SLDataType* a;    //指向动态开辟的数组
	size_t size;      //有效数据个数
	size_t capacity;  //容量大小
}SeqList;

void SeqListInit(SeqList* p);//初始化顺序表
void SeqListPrint(const SeqList* p);//打印顺序表
void SeqListPushBack(SeqList* p, SLDataType x);//尾插
void SeqListPopBack(SeqList* p);//尾删
void SeqListPushFront(SeqList* p, SLDataType x);//头插
void SeqListPopFront(SeqList* p);//头删
int SeqListFind(const SeqList* p, SLDataType x);//查找数据
void SeqListModify(SeqList* p, int pos, SLDataType x);//修改数据
void SeqListInsert(SeqList* p, int pos, SLDataType x);//指定插入
void SeqListErase(SeqList* p, int pos);//指定删除
void SeqListDestory(SeqList* p);//释放空间

 SeqList.c 文件

#define _CRT_SECURE_NO_WARNINGS 1
#include"SeqList.h"
void SeqListInit(SeqList* p)
{
	assert(p);  //断言
	p->a =(SLDataType*)malloc(N*sizeof(SLDataType));  //初始顺序表为四个空间
	if (p->a == NULL)
	{
		perror("malloc fail:");
		return ;
	}
	p->size = 0;  //初始数据个数为0
	p->capacity = 4;  //初始空间容量为4
}
void CheckCapacity(SeqList* p)
{
	assert(p);  //断言

	if (p->size == p->capacity)  //检查容量,满了则增容
	{
		size_t newcapacity = 2 * p->capacity;  //,扩容为原来的2倍
		SLDataType* prt = (SLDataType*)realloc(p->a, newcapacity * sizeof(SLDataType));  //扩容
		if (prt == NULL)
		{
			perror("realloc");
			return ;
		}
		p->a = prt;  // prt不为空,开辟成功
		p->capacity = newcapacity;  //更新容量
	}
}
void SeqListPushBack(SeqList* p, SLDataType x)
{
	assert(p);  //断言
	CheckCapacity(p);  //检查顺序表容量是否已满
	p->a[p->size] = x;  //尾插数据
	p->size++;  //有效数据个数+1
}
void SeqListPrint(const SeqList* p)
{
	assert(p);  //断言
	if (p->size == 0)  //判断顺序表是否为空
	{
		printf("顺序表为空\n");
		return;
	}

	int i = 0;
	for (i = 0; i < p->size; i++)  //打印顺序表
	{
		printf("%d ", p->a[i]);
	}
	printf("\n");
}
void SeqListPopBack(SeqList* p)
{
	assert(p);  //断言
	assert(p->size > 0);  //顺序表不能为空
	p->size--;  //有效数据个数-1
}
void SeqListPushFront(SeqList* p, SLDataType x)
{
	assert(p);  //断言
	CheckCapacity(p);  //检查顺序表容量是否已满

	int i = 0;
	for (i = p->size - 1; i >= 0; i--)  //顺序表中[0,size-1]的元素依次向后挪动一位
	{
		p->a[i + 1] = p->a[i];
	}
	p->a[0] = x;  //头插数据
	p->size++;  //有效数据个数+1
}
void SeqListPopFront(SeqList* p)
{
	assert(p);  //断言
	assert(p->size > 0);  //顺序表不能为空

	int i = 0;
	for (i = 1; i < p->size; i++)  //顺序表中[1,size-1]的元素依次向前挪动一位
	{
		p->a[i - 1] = p->a[i];
	}
	p->size--;  //有效数据个数-1
}
int SeqListFind(const SeqList* p, SLDataType x)
{
	assert(p);  //断言

	int i = 0;
	for (i = 0; i < p->size; i++)
	{
		if (p->a[i] == x)
		{
			return i;  //查找到,返回该值在数组中的下标
		}
	}
	return -1;  //没有查找到
}
void SeqListModify(SeqList* p, int pos, SLDataType x)
{
	assert(p);  //断言
	assert(p->size > 0);  //顺序表不能为空
	assert(pos >= 0 && pos < p->size);  //检查pos下标的合法性
	p->a[pos] = x;  //修改pos下标处对应的数据
}
void SeqListInsert(SeqList* p, int pos, SLDataType x)
{
	assert(p);//断言
	assert(pos <= p->size); //检查pos下标的合法性
	SeqListCheck(p);//扩容
	int cur = p->size;
	while (cur > pos)
	{
		p->a[cur] = p->a[cur - 1];//覆盖
		--cur;
	}
	p->a[pos] = x;
	p->size++;
}
void SeqListErase(SeqList* p, int pos)
{
	assert(p);  //断言
	assert(p->size > 0);  //顺序表不能为空
	assert(pos >= 0 && pos < p->size);  //检查pos下标的合法性
	int i = 0;
	for (i = pos + 1; i < p->size; i++)  //将pos位置后面的数据依次向前挪动一位
	{
		p->a[i - 1] = p->a[i];
	}
	p->size--;  //有效数据个数-1
}
void SeqListDestory(SeqList* p)
{
	assert(p);  //断言
	free(p->a);   //释放动态开辟的空间
	p->a = NULL;  //置空
	p->size = 0;  //数据个数置0
	p->capacity = 0;  //空间容量大小置0
}


 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值