数据结构入门之顺序表(SeqList)
创作时间:
作者:
@小白创作中心
数据结构入门之顺序表(SeqList)
引用
CSDN
1.
https://m.blog.csdn.net/wuge041118/article/details/144123183
一、顺序表
顺序表的底层其实就是数组,那有了数组,为什么还要创建顺序呢?
举个例子:假设我创建一个数组int arr[100] = {1, 2, 3, 4, 5},我想要插入删除或者查找某个数据就需要先查找数组中已有元素个数,再进行增删查,就使用循环,顺序表由此而生,顺序表是线性表的一种。
注:线性表是具有n个相同特性的数据元素的有限序列,主要从物理结构和逻辑结构两个方面有相同特性。在物理结构上不一定连续,即储存方式,如果储存方式是以数组的形式储存,则连续,如果以链式结构的方式储存则不连续;在逻辑结构上是连续的,也就是线性的。
由上可知顺序表在物理结构上是连续的,在逻辑结构上也是连续的。
二、顺序表的分类
(一)、静态顺序表
#define N 100 //使用宏定义N为100
//静态顺序表的定义
struct SeqList
{
int arr[N];//定长数组
int size; //顺序表当前有效的数据个数
};
(二)、动态顺序表
typedef int SLDataType;//方便对于存储其他类型数据时的更改
typedef struct SeqList
{
SLDataType* arr;
int size;//有效数据的个数
int capacity;//记录空间大小,方便后续对数组进行扩容
}SL;//使用typedef对顺序表重命名
typedef int SLDataType;//方便对于存储其他类型数据时的更改
struct SeqList
{
SLDataType* arr;
int size;//有效数据的个数
int capacity;//记录空间大小,方便后续对数组进行扩容
};
typedef struct SeqList SL;//使用typedef对顺序表重命名
以上两种对顺序表重命名的方式都可以
(三)、静态顺序表与动态顺序表的比较
显而易见,静态顺序表的空间大小不可变,在实际使用中很不方便,如果空间给小了会不够用,而给大了就会出现空间浪费的情况。所以可以动态开辟空间的动态顺序表更加符合我们日常的使用,在创建顺序表时,往往也都创建动态顺序表,所以接下来的代码,也都将基于动态顺序表来实现。
三、顺序表的实现(先看源文件的实现过程,再看头文件)
(一)头文件(.h文件)
#pragma once
#include<stdio.h>
#include<stdlib.h>
#include<assert.h>
typedef int SLDataType;
typedef struct SeqList
{
SLDataType* arr;
int size;//有效数据的个数
int capacity;//空间大小
}SL;
//顺序表的初始化
void SLInit(SL* ps);
//顺序表的销毁
void SLDestroy(SL* ps);
//检验空间是否需要扩容,如果需要则进行扩容
void SLCheckCapacity(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);
//顺序表的查找
int SLFind(SL* ps, SLDataType x);
(二)源文件(.c文件)
导入库只有SeqList.h
1.顺序表的初始化
//顺序表的初始化
void SLInit(SL* ps)
{
assert(ps);//防止传进空指针
ps->arr = NULL;
ps->size = ps->capacity = 0;
}
2.顺序表的销毁
//顺序表的销毁
void SLDestroy(SL* ps)
{
assert(ps);//防止传进空指针
if (ps->arr)
{
free(ps->arr);
}
ps->arr = NULL;
ps->size = ps->capacity = 0;
}
3.顺序表的尾插(有扩容)
频繁增容会使程序的运行效率大大降低,经过数学计算(感兴趣的话可自行上网搜索,2倍或3倍的增长更适合)
//尾插
void SLPushBack(SL* ps, SLDataType x)
{
assert(ps);//防止传进空指针
if (ps->size == ps->capacity)//空间满了,要申请空间
{
int newCapacity = ps->capacity == 0 ? 4 : 2 * ps->capacity;//如果开始没有空间,则给4,有空间,则变为原来的2倍
SLDataType* tmp = (SLDataType*)realloc(ps->arr, newCapacity * sizeof(SLDataType));//对原来的空间扩大一倍
if (tmp == NULL)
{
perror("realloc fail!");
exit(1);
}
//空间申请成功
ps->arr = tmp;
ps->capacity = newCapacity;
}
ps->arr[ps->size++] = x;
}
我们对尾插进行调试
可以看到前四次插入都成功,且此时空间大小为4
空间扩容成功,第五次插入也成功
4.顺序表的头插(将扩容分装成一个函数)
在头插时我们发现,还需要检验空间大小以及扩容,所以此时我们将上面实现扩容的代码分装成一个函数。
void SLCheckCapacity(SL* ps)
{
if (ps->size == ps->capacity)//空间满了,要申请空间
{
int newCapacity = ps->capacity == 0 ? 4 : 2 * ps->capacity;
SLDataType* tmp = (SLDataType*)realloc(ps->arr, newCapacity * sizeof(SLDataType));
if (tmp == NULL)
{
perror("realloc fail!");
exit(1);
}
//空间申请成功
ps->arr = tmp;
ps->capacity = newCapacity;
}
}
尾插代码就变成了如下
//尾插
void SLPushBack(SL* ps, SLDataType x)
{
assert(ps);//防止传进空指针
SLCheckCapacity(ps);
ps->arr[ps->size++] = x;
}
接下来开始实现头插
//头插
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]
}
ps->arr[0] = x;
ps->size++;
}
在检验头插时,觉得调试看起来太麻烦了,这时候我们需要一个新的函数来显示我们的结果。
//打印查看
void SLPrint(SL s)
{
for (int i = 0; i < s.size; i++)
{
printf("%d ", s.arr[i]);
}
printf("\n");
}
5.顺序表的尾删
//尾删
void SLPopBack(SL* ps)
{
assert(ps && ps->size);
//顺序表现在不为空
--ps->size;
}
删空之后再删就会报错
6.顺序表的头删
//头删
void SLPopFront(SL* ps)
{
assert(ps && ps->size);
//顺序表现在不为空
//数据整体往前移动一位
for (int i = 0; i < ps->size - 1; i++)
{
ps->arr[i] = ps->arr[i + 1];
}
ps->size--;
}
删空之后再删就会报错
7.在指定位置之前插入数据
//在指定位置之前插入数据
void SLInsert(SL* ps, int pos, SLDataType x)
{
assert(ps);
assert(pos >= 0 && pos <= ps->size);
SLCheckCapacity(ps);
//让pos和pos以后的数据整体往后移动一位
for (int i = ps->size; i > pos; i--)
{
ps->arr[i] = ps->arr[i - 1];
}
ps->arr[pos] = x;
ps->size++;
}
8.删除指定位置之前的数据
//删除指定位置的数据
void SLErase(SL* ps, int pos)
{
assert(ps);
assert(ps->size > 0);//顺序表不为空
assert(pos >= 0 && pos < ps->size);
//让pos之后的数据整体往前挪动一位
for (int i = pos; i < ps->size - 1; i++)
{
ps->arr[i] = ps->arr[i + 1];
}
ps->size--;
}
9.顺序表的查找
//顺序表的查找
int SLFind(SL* ps, SLDataType x)
{
assert(ps);
for (int i = 0; i < ps->size; i++)
{
if (ps->arr[i] == x)
{
//找到了
return i;
}
}
//没找到
return -1;
}
热门推荐
清明踏青打卡:拙政园最美江南景
观前街必打卡地道美食指南
呼延村:河西第一大村的前世今生
巴黎奥运会结束了,那些打破常规的励志故事,或许更值得讲给孩子听
冰箱噪音让你失眠?这些小妙招拯救你的睡眠
情人节浪漫情话:给老公的暖心祝福
B站春晚上那些让人笑到肚子疼的瞬间!
B站上线42年春晚,年轻人的“名梗”记忆库
新年送祝福,古风诗意卡片走起!
探秘盘古与龙的神秘渊源
花生与龙:吉祥婚配寓意的文化解读
武安舍利塔:巍巍古塔,屹立千年
古塔——中国古代独特的高层建筑
2025央视春晚:科技创新与人文关怀的完美融合
DIY寿司模型,你也能成为大师!
从零开始学做美味寿司:小野二郎的制作秘诀
壽司組裝模型:364颗米粒还原真实,手工达人的新挑战
高考体检结果解读:哪些情况会影响录取?
让年画娃娃开口说话送祝福,腾讯智影AI助力传统非遗焕新活力
2024年生肖运势:龙蛇虎兔将迎来好运连连
赵本山新剧《象牙山的好人们》遭观众吐槽,剧情设计引发争议
婚戒戴法大揭秘:提升人缘的小秘密
“三生三世”戒指:承载千年情缘的浪漫信物
康奈尔大学祈祷者:以爱与服务精神增强社区凝聚力
从14秒72看萌娃短跑天赋:如何科学激发孩子运动潜能?
萌娃短跑大赛:陪娃跑步也能这么嗨!
嫦娥奔月背后的兔文化揭秘:从神话传说走向现代文创
玉兔呈祥:兔年的吉祥寓意与文化内涵
央视《兔年兔宝贝》教你拍兔年短视频
冬季在家也能跑!九岁儿童室内短跑训练指南