何为顺序表
😉😉😉
1.在理论上顺序表是这样定义的
顺序表是用一段物理地址连续的存储单元依次存储数据元素的线性结构,一般情况下采用数组存储。在数组上完成数据的增删查改。
作为初学者的同学读完定义之后可能会说这尼玛是什么鬼,看不懂呀。😦
我们来举几个栗子来帮助同学们理解何为顺序表,大家在学校考完试之后,我们的老师会将考试成绩录入一个叫学生成绩管理系统中,在这个系统中,按学号将每位同学的成绩依次录入到系统中,在这里我们使用的数据结构就是顺序表结构。还有银行排队系统,任务调度器等等也是应用的顺序表结构,由此可见顺序表结构的重要性。
2.顺序表的优劣
内存中地址连续使得顺序表有了以下优点
随机访问⽐较便捷快速,创建也⽐较简单,随机查找⽐较⽅便,可以直接给出下标,排序也⽅便简单。
但相应的也出现了以下缺点
不够灵活,删除增加的⼯作量叫⼤,⽐较⿇烦
适⽤场景:适⽤于需要⼤量访问元素的 ⽽少量增添/删除元素的程序
顺序表的实现
😆😆😆
对于一个顺序表我们要实现增删查改的最基本功能,在之后如果想能够动态控制一个顺序表的容量我们还要实现扩容检查的功能,我们如果想要在一个顺序表中查询我们想要的信息(例如查看某位同学的学科成绩)就需要建立查找功能,然后还要有打印功能等许多功能,这个功能需要根据业务需要建立,博主就先介绍最简单的一个顺序表如何实现。
大家可以先阅读以下头文件中的函数声明对顺序表先有一个大体上的了解👊👊👊
typedef int SLDataType;
// 顺序表的动态存储
typedef struct SeqList
{
SLDataType* array; // 指向动态开辟的数组
int size; // 有效数据个数
int capicity; // 容量空间的大小
}SeqList;
// 基本增删查改接口
// 顺序表初始化
void SeqListInit(SeqList * psl);
// 检查空间,如果满了,进行增容
void CheckCapacity(SeqList* psl);
// 顺序表尾插
void SeqListPushBack(SeqList* psl, SLDataType x);
// 顺序表尾删
void SeqListPopBack(SeqList* psl);
// 顺序表头插
void SeqListPushFront(SeqList* psl, SLDataType x);
// 顺序表头删
void SeqListPopFront(SeqList* psl);
// 顺序表查找
int SeqListFind(SeqList* psl, SLDataType x);
// 顺序表在pos位置插入x
void SeqListInsert(SeqList* psl, size_t pos, SLDataType x);
// 顺序表删除pos位置的值
void SeqListErase(SeqList* psl, size_t pos);
// 顺序表销毁
void SeqListDestory(SeqList* psl);
// 顺序表打印
void SeqListPrint(SeqList* psl);
好了我们开始对顺序表进行拆分💃💃💃
顺序表初始化 😃😃😃
// 顺序表初始化
void SeqListInit(SeqList* psl) {
assert(psl);//一个断言检查,这里就不作详细介绍了
psl->array = (SLDataType*)malloc(sizeof(SLDataType) * 5);
psl->capicity = 5;
psl->size = 0;
}
so easy这里没有什么难点,但是有一些细节需要同学们注意,我们对顺序表的大小进行初始化时一定要合理,不要我设计一个班级的信息管理系统我初始化数组大小为1万个空间
顺序表的尾插尾删💃💃💃
// 顺序表尾插
void SeqListPushBack(SeqList* psl, SLDataType x) {
assert(psl);
CheckCapacity(psl);//每次新增数据时一定要检查容量,不然就越界啦
psl->array[psl->size] = x;
++psl->size;
}
// 顺序表尾删
void SeqListPopBack(SeqList* psl) {
assert(psl);
assert(psl->size != 0);
--psl->size;
}
顺序表的容量检查 😎 😎
// 检查空间,如果满了,进行增容
void CheckCapacity(SeqList* psl) {
if (psl->capicity == psl->size) {
int newcapacity = psl->capicity * 2;
SLDataType* tmp=(SLDataType*)realloc(psl->array,sizeof(SLDataType) * newcapacity);
if (tmp == NULL) {
perror("CheckCapacity");
exit(-1);
}
psl->array = tmp;
psl->capicity = newcapacity;
}
}
这里有一个小细节需要注意realloc时一定要再设置一个新的指针,因为当我们realloc时不一定是百分百成功的如果还用之前的指针接收,如果realloc成功还好说,如果失败就会导致我们不仅不会扩容还会导致之前的数据丢失。
顺序表头插头删💚 💚 💚
// 顺序表头插
void SeqListPushFront(SeqList* psl, SLDataType x) {
assert(psl);
CheckCapacity(psl);
memmove(psl->array + 1, psl->array, sizeof(SLDataType)*psl->size);
psl->array[0] = x;
++psl->size;
}
// 顺序表头删
void SeqListPopFront(SeqList* psl) {
assert(psl);
assert(psl->size != 0);
memmove(psl->array, psl->array+1, sizeof(SLDataType)*psl->size-1);
--psl->size;
}
这里是顺序表中比较困难的地方,我介绍一下如何memmove(一定要用memmove,因为他能够解决数据重叠问题,博主有一篇对memmove的详细介绍,有需要的同学可以学习一下)
头删💃💃💃
我们可以直观的看出头删就是把size-1个数据从array+1的位置移动到array的位置
头增💃💃💃
我们可以直观的看出头删就是把size个数据从array的位置移动到array+1的位置并在array[0]处填入新数据
在pos处插入数据
💚💚💚💚💚💚💚💚💚💚💚💚💚💚💚💚💚💚💚💚💚
这里有一个细节需要同学们注意,我们要知道我们写出的程序是给谁用的,那当然是给客户用的了,所以我们要站在客户的角度思考,客户说的pos位置是从1开始计数的,我们的数组下标则是从0开始的所以我们在计算时要把pos-1才是我们真正要插入的位置😉
💚💚💚💚💚💚💚💚💚💚💚💚💚💚💚💚💚💚💚💚💚
// 顺序表在pos位置插入x
void SeqListInsert(SeqList* psl, size_t pos, SLDataType x) {
assert(psl);
CheckCapacity(psl);
memmove(psl->array + pos - 1 + 1, psl->array + pos - 1, sizeof(SLDataType) * (psl->size - pos -1+ 1));
psl->array[pos - 1] = x;
}
顺序表在pos位置插入x就是把size - pos + 1个数据从array + pos - 1位置移动到array + pos - 1 + 1位置
在pos处删除数据
// 顺序表删除pos位置的值
void SeqListErase(SeqList* psl, size_t pos) {
assert(psl);
assert(psl->size != 0);
memmove(psl->array + pos - 1, psl->array + pos - 1 + 1, sizeof(SLDataType) * (psl->size - pos-1));
--psl->size;
}
顺序表删除pos位置的值就是把size - pos-1个数据从array + pos - 1 + 1位置移动到array + pos - 1
接下来我就把顺序表的查找和打印一起给出,这两点没有什么难点,都是简单的遍历
💃💃💃💃💃💃💃💃
// 顺序表查找找到返回下标,没找到返回-1;
int SeqListFind(SeqList* psl, SLDataType x) {
assert(psl);
if (psl->size == 0) {
return -1;
}//如果是空直接返回
int cur = 0;
while(cur != psl->size) {
if (psl->array[0] == x) {
return cur+1;
}
cur++;
}
return -1;
}
// 顺序表打印
void SeqListPrint(SeqList* psl) {
assert(psl);
int cur = 0;
while (cur != psl->size) {
printf("%d\n", psl->array[cur]);
cur++;
}
}
顺序表的销毁,一定要销毁不然会内存泄漏
💃💃💃💃💃
// 顺序表销毁
void SeqListDestory(SeqList* psl) {
assert(psl);
free(psl->array);
psl->array = NULL;
psl->capicity = 0;
psl->size = 0;
}
希望大家能够给大家提供到帮助,使大家有所收获
💃💃💃💃💃💃💃💃💃💃💃💃💃💃💃💃💃💃💃💃
成功在于坚持,梦想在于行动。
加油少年。
😉😉😉😉😉😉😉😉😉😉😉😉😉😉😉😉😉😉😉😉