欢迎来CILMY23的博客
本篇主题为 从零开始:用C语言实现顺序表
个人主页:CILMY23-CSDN博客
C语言专栏: http://t.csdnimg.cn/hQ5a9
Python系列专栏:http://t.csdnimg.cn/HqYo8
上一篇C语言博客: http://t.csdnimg.cn/I4Zgf
感谢观看,支持的可以给个一键三连,点赞关注+收藏。
目录
一、 什么是顺序表?
1.1 顺序表概念
1.2 顺序表结构及初始化
二、顺序表的功能实现
2.1 增
2.1.1 头插
2.1.2 尾插
2.1.3 任意位置插入
2.2 删
2.2.1 头删
2.2.2 尾删
2.2.3 任意位置删除
2.3 查
2.4 改
三、 顺序表其余功能
3.1 打印顺序表
3.2 销毁顺序表
本文前言
在学习完C语言后,我们扩展学习几种的数据结构,目的是为了最后的通讯录项目做铺垫
一、 什么是顺序表?
如果不知道数据结构的概念可以看数据结构概念篇(http://t.csdnimg.cn/yPSMc)
1.1 顺序表概念
在讲顺序表之前得先讲讲线性表
线性表(linear list)是n个具有相同特性的数据元素的有限序列。 线性表是一种在实际中广泛使 用的数据结构,常见的线性表:顺序表、链表、栈、队列、字符串...
线性表在逻辑上是线性结构,也就说是连续的一条直线。但是在物理结构上并不一定是连续的, 线性表在物理上存储时,通常以数组和链式结构的形式存储。
顺序表(Seqlist)是用一段物理地址连续的存储单元依次存储数据元素的线性结构,一般情况下采用数组存 储。在数组上完成数据的增删查改。
顺序表又分为静态和动态,而静态的顺序表就是固定的空间,那本篇主要以动态顺序表的实现为主。
1.2 顺序表结构及初始化
顺序表的结构如下所示:
typedef int SLDataType;
typedef struct SeqList
{
SLDataType* a; // 起始位置
size_t data; // 有效数据个数
size_t capacity; // 空间容量
}SQ;
那在使用之前我们肯定是要初始化的,这里我们直接给了一个capacity = 4,意思是这个顺序表一开始就有4个空间(但这个时候实际还未创建好)
//顺序表的初始化
void SLInit(SL* sl)
{
assert(sl);
sl->a = NULL;
sl->data = 0;
sl->capacity = 4;
}
二、顺序表的功能实现
顺序表功能主要围绕四个部分,“增删查改”这四个字,当然我们还可以增加其他功能,这些是最基本的实现。
2.1 增
在插入前我们做的第一件事就是要看空间
空间的几种情况如下:
因为该过程较为常用,我们使用函数进行封装,这样在每次插入前都检查一遍空间。因为一次只插入一个数据,所以当有效数据和空间相等的时候,说明此时已经没有足够空间了,那要进行扩容,如果我们没在初始化给顺序表一个空间,就要使用newcapacity 对 capacity 进行判断,多一步去检查capacity。
//顺序表的空间检查
void SLCheckCapacity(SL*sl)
{
//如果空间不够,就要扩容
if (sl->data == sl->capacity)
{
SLDataType* psl;
psl = (SLDataType*)realloc(sl->a, sl->capacity * 2 * sizeof(SLDataType));
if (psl == NULL)
{
perror("realloc fail");
return 1;
}
sl->a = psl;
sl->capacity = sl->capacity*2;
}
}
2.1.1 头插
//顺序表的头插
void SLPushFront(SL* sl, SLDataType x)
{
assert(sl);
//检查空间
SLCheckCapacity(sl);
//插入数据,前要移动数据
for (size_t i = sl->data; i > 0; i--)
{
//从末尾开始移动数据
sl->a[i] = sl->a[i - 1];
}
//移动完数据开始插入数据
sl->a[0] = x;
sl->data++;
}
2.1.2 尾插
//顺序表的尾插
void SLPushBack(SL* sl, SLDataType x)
{
assert(sl);
//插入前,检查空间
SLCheckCapacity(sl);
//插入数据
sl->a[sl->data] = x;
sl->data++;
}
2.1.3 任意位置插入
我们这里说的是在任意位置之前插入数据
//任意位置插入
void SLInsert(SL* sl, int pos, SLDataType x)
{
assert(sl);
assert(pos >= 0 && pos <= sl->data);
//检查空间
SLCheckCapacity(sl);
//数据移动
for (int i = sl->data - 1; i >= pos; i--)
{
sl->a[i + 1] = sl->a[i];
}
sl->a[pos] = x;
sl->data++;
}
2.2 删
在删除的时候要判断顺序表是否为空,所以我们使用一个布尔类型来判断顺序表是否为空
//判断顺序表是否为空
bool SLIsEmpty(SL* sl)
{
assert(sl);
//当有效数据为0就为空的顺序表
return sl->data == 0;
}
2.2.1 头删
在删除的时候一定要保证size大于0,当然我还是更喜欢在删除的时候选择这种柔和的方式,当然你也可以选择用assert方式。
void SLPopFront(SL* sl)
{
assert(sl);
if (sl->data > 0)
{
for (int i = 0; i < sl->data; i++)
{
sl->a[i] = sl->a[i - 1];
}
sl->data--;
}
}
2.2.2 尾删
注意,我们删除的时候不能让有效数据小于0.
//顺序表的尾删
void SLPopBack(SL* sl)
{
assert(sl);
//保证有效数据大于0
if(sl->data > 0)
sl->data -= 1;
}
2.2.3 任意位置删除
注意pos不能等于 sl->data ,因为这个位置没有数据啦
//任意位置删除
void SLErase(SL* sl, int pos)
{
assert(sl);
assert(!SLIsEmpty(sl));
//对pos进行检查
assert(pos >= 0 && pos < sl->data);
//数据移动
for (int i = pos; i < sl->data - 1; i++)
{
sl->a[i] = sl->a[i + 1];
}
sl->data--;
}
2.3 查
在顺序表中查询数据,如果找到了则返回下标位置,如果找不到就返回-1
//顺序表查找数据
int SLFind(SL* sl, SLDataType x)
{
assert(sl);
assert(!SLIsEmpty(sl));
int i = 0;
for (i = 0; i < sl->data; i++)
{
if (sl->a[i] == x)
{
return i;
}
}
if (i == sl->data)
return -1;
}
2.4 改
在顺序表中修改指定位置的数据
//顺序表修改数据
void SLChange(SL* sl, SLDataType x)
{
assert(sl);
assert(!SLIsEmpty(sl));
int i = 0;
for (i = 0; i < sl->data; i++)
{
if (sl->a[i] == x)
{
sl ->a a[i] = x;
}
}
}
三、 顺序表其余功能
3.1 打印顺序表
//顺序表的打印
void SLPrint(SL* sl)
{
if (sl->data != 0)
{
int i = 0;
for (i = 0; i < sl->data;i++)
{
printf("%d ", sl->a[i]);
}
printf("\n");
}
}
3.2 销毁顺序表
有顺序表的初始化,那就有顺序表的销毁,因为是动态内存,所以我们就要用到free函数来释放空间
//顺序表的销毁
void SLDestroy(SL* sl)
{
if (sl->a != NULL)
{
free(sl->a);
sl->a = NULL;
sl->capacity = 0;
sl->data = 0;
}
}
感谢各位同伴的支持,本期顺序表就讲解到这啦,更详细的可以看,【数据结构和算法】4.超详细解析动态顺序表的实现(图文解析,附带源码)-CSDN博客
如果你觉得写的不错的话,可以给个一键三连,点赞,关注+收藏,若有不足,欢迎各位在评论区讨论。