一.顺序表定义
目录
1.线性表
线性表(
linear list
)是n个具有相同特性的数据元素的有限序列, 线性表是⼀种在实际中⼴泛使
⽤的数据结构,常⻅的线性表:顺序表、链表、栈、队列、字符串...
线性表在逻辑上是线性结构,也就说是连续的⼀条直线。但是在物理结构上并不⼀定是连续的,
线性表在物理上存储时,通常以数组和链式结构的形式存储。
简单来说顺序表是线性表的一种,而且逻辑和物理都是线性结构
2.顺序表的定义和分类
顺序表的底层是数组,通过增加一些增删查找等接口实现
2.1 静态顺序表
静态顺序表(这里拿里面存储的整形举例)
typedef int SLDataType;
#define N 100
typedef struct SeqList
{
SLDatatype arr[N];
int size;//size是有效数据的个数
}SL;
解释一下为什么要把存储的类型变为SLDataType
这么做是为了方便以后修改
还有把数组存储的数据容量便于修改
2.2 动态顺序表
typedef int SLDataType;
typedef struct SeqList
{
SLDataType* arr;
int size;
int capacity;
}SL;//这里我们定义了一个结构体,其实这就是一个动态的顺序表
因为动态顺序表的结构更加灵活,所以我们下面的接口都是通过动态顺序表实现的
二.接口的实现
1.准备工作及其注意事项
我们需要创建3个文件
我先来解释一下这三个文件的作用,头文件SeqList.h是来声明接口以及定义顺序表
源文件SeqList.c是用来具体实现接口,源文件test.c用于接口的测试工作
注意事项几条小点
1.不管是任意一种操作我们在处理之前都要判段 assert(ps->arr) ;
2.在进行扩容的时候别忘记了 要把容量变成新开出来的那个
3.进行插入操作之后 要把size++; 在进行删除操作的时候要进行size--;
4.进行删除操作的时候 除了要判断第一种断言之外,还要在判断 assert(ps->size)
5.进行指定位置插入或者删除的时候,要进行判断pos的范围问题
小拓展:
1.尝试用memmove函数覆盖数据
2.for循环的使用方法其实只看头尾即可
3.尝试用while循环代替for循环实现
4.进行移动的时候方向问题的判断就是是否会有重叠
2.顺序表的基本功能接口
2.1 顺序表的初始化
void SLInit(SL* ps)
{
assert(ps);
ps->arr = NULL;
ps->capacity = ps->size = 0;
}
2.2 顺序表的销毁
void SLDestroy(SL* ps)
{
assert(ps);
free(ps->arr);
ps->arr = NULL;
ps->capacity = ps->size = 0;
}
2.3 顺序表的打印
void SLPrint(SL* ps)
{
assert(ps);
for (int i = 0;i < ps->size;++i)
{
printf("%d ", ps->arr[i]);
}
printf("\n");
}
3.顺序表的扩容检查接口
这个接口在进行增加元素的时候,需要用到,因为不确定空间是否足够
void SLCheckCapacity(SL* ps)
{
assert(ps);
int newCapacity = ps->capacity == 0 ? 4 : 2 * ps->capacity;
if (ps->capacity == ps->size)
{
SLDataType* ptr = (SLDataType*)realloc(ps->arr, sizeof(SLDataType) * newCapacity);
if (ptr == NULL)
{
perror("realloc");
exit(1);
}
ps->arr = ptr;
ps->capacity = newCapacity;
}
}
4.顺序表的增加功能接口
4.1 尾插接口
void SLPushBack(SL* ps,int x)
{
assert(ps);
SLCheckCapacity(ps);//判断以下是否需要扩容
ps->arr[ps->size] = x;//经过判断是否扩容之后,直接插入arr[size]的位置
}
4.2 头插接口
我们给三种实现方式,循环实现的时候,从头部遍历还是尾部遍历要看元素是否有重叠
//01(for循环实现)
void SLPushFront01(SL* ps, int x)
{
assert(ps);
SLCheckCapacity(ps);//判断以下是否需要扩容
for (int i = ps->size;i > 0;--i)
{
ps->arr[i] = ps->arr[i - 1];
}//只看头尾进行判断
ps->arr[0] = x;
ps->size++;
}
//02(while循环实现)
void SLPushFront02(SL* ps, int x)
{
assert(ps);
SLCheckCapacity(ps);//判断以下是否需要扩容
int begin = ps->size;
while (begin > 0)
{
ps->arr[begin] = ps->arr[begin - 1];
begin--;
}
ps->arr[0] = x;
ps->size++;
}
//03(内存操作函数memmove实现)
void SLPushFront03(SL* ps, int x)
{
assert(ps);
SLCheckCapacity(ps);//判断以下是否需要扩容
memmove((ps->arr) + 1, ps->arr, sizeof(SLDataType) * ps->size);
ps->arr[0] = x;
ps->size++;
}
4.3 指定位置插入接口
这个与上面的头插类似
//01for循环实现
void SLInsert01(SL* ps, int pos, int x)
{
assert(ps);
SLCheckCapacity(ps);
for (int i = ps->size;i > pos;--i)
{
ps->arr[i] = ps->arr[i - 1];
}
ps->arr[pos] = x;
ps->size++;
}
//02while循环实现
void SLInsert02(SL* ps, int pos,int x)
{
assert(ps);
int begin = ps->size;
while (begin > pos)
{
ps->arr[begin] = ps->arr[begin - 1];
begin--;
}
ps->arr[pos] = x;
ps->size++;
}
//03memmove内存操作函数实现
void SLInsert03(SL* ps, int pos, int x)
{
assert(ps);
memmove(ps->arr + pos, ps->arr + pos + 1, sizeof(SLDataType) * (ps->size - pos));
ps->arr[pos] = x;
ps->size++;
}
5.顺序表的删除功能接口
5.1 尾删接口
void SLPopBack(SL* ps)
{
assert(ps);
assert(ps->size);
ps->size--;
}
5.2头删接口
//01for循环实现
void SLPopFront01(SL* ps)
{
assert(ps);
assert(ps->size);
for (int i = 0;i < ps->size - 1;++i)
{
ps->arr[i] = ps->arr[i + 1];
}
ps->size--;
}
//02while循环实现
void SLPopFront02(SL* ps)
{
assert(ps);
assert(ps->size);
int begin = 0;
while (begin < ps->size - 1)
{
ps->arr[begin] = ps->arr[begin + 1];
}
ps->size--;
}
//03memmove内存操作函数实现
void SLPopFront03(SL* ps)
{
assert(ps);
assert(ps->size);
memmove(ps->arr, ps->arr + 1, sizeof(SLDataType) * (ps->size - 1));
ps->size--;
}
5.3指定位置删除接口
//01for循环实现
void SLErase01(SL* ps, int pos)
{
assert(ps);
assert(ps->size);
for (int i = pos;i < ps->size-1;++i)
{
ps->arr[i] = ps->arr[i + 1];
}
ps->size--;
}
//02while循环实现
void SLErase02(SL* ps, int pos)
{
assert(ps);
assert(ps->size);
int begin = pos;
while (begin < pos - 1)
{
ps->arr[begin] = ps->arr[begin + 1];
begin++;
}
ps->size--;
}
//03memmove内存操作函数实现
void SLErase03(SL* ps, int pos)
{
assert(ps);
assert(ps->size);
memmove(ps ->arr, ps->arr + 1, sizeof(SLDataType) * (ps->size - pos - 1));
ps->size--;
}
6.顺序表的查找实现接口
int SLFind(SL* ps, int x)
{
for (int i = 0;i < ps->size;++i)
{
if (ps->arr[i] == x)
{
return i;
}
}
return -1;
}
三.总代码概览
SeqList.h文件
#pragma once
#include<memory.h>
//这里的头文件进行的顺序表的声明
typedef int SLDataType;
typedef struct SeqList
{
SLDataType* arr;
int size;
int capacity;
}SL;//这里我们定义了一个结构体,其实这就是一个动态的顺序表
void SLInit(SL* ps);//顺序表的初始化
void SLPrint(SL* ps);//顺序表的打印
void SLDestroy(SL* ps);//顺序表的销毁
void SLCheckCapacity(SL* ps);//顺序表的扩容检查(扩容的原则,以及扩容的方法)
void SLPushBack(SL* ps,int x);//顺序表的尾插
//顺序表的头插
void SLPushFront01(SL* ps, int x);
void SLPushFront02(SL* ps, int x);
void SLPushFront03(SL* ps, int x);
//顺序表的指定位置插入(这里的指定位置我们指的是下标前面)
void SLInsert01(SL* ps, int pos, int x);
void SLInsert02(SL* ps, int pos, int x);
void SLInsert03(SL* ps, int pos, int x);
void SLPopBack(SL* ps);//顺序表的尾删
void SLPopFront(SL* ps);//顺手表的头删
void SLErase(SL* ps,int pos);//顺序表的指定位置删除
SeqList.c文件
#include<stdio.h>
#include<assert.h>
#include<memory.h>
#include"SeqList.h"
//这里的源文件我们进行的头文件中的函数的具体实现
//也就是封装相关的函数
//1.顺序表的初始化
void SLInit(SL* ps)
{
assert(ps);
ps->arr = NULL;
ps->capacity = ps->size = 0;
}
//2.顺序表的打印
void SLPrint(SL* ps)
{
assert(ps);
for (int i = 0;i < ps->size;++i)
{
printf("%d ", ps->arr[i]);
}
printf("\n");
}
//3.顺序表的销毁
void SLDestroy(SL* ps)
{
assert(ps);
free(ps->arr);
ps->arr = NULL;
ps->capacity = ps->size = 0;
}
//4.顺序表的扩容检查(扩容的原则,以及扩容的方法)
void SLCheckCapacity(SL* ps)
{
assert(ps);
int newCapacity = ps->capacity == 0 ? 4 : 2 * ps->capacity;
if (ps->capacity == ps->size)
{
SLDataType* ptr = (SLDataType*)realloc(ps->arr, sizeof(SLDataType) * newCapacity);
if (ptr == NULL)
{
perror("realloc");
exit(1);
}
ps->arr = ptr;
ps->capacity = newCapacity;
}
}
//5.顺序表的尾插
void SLPushBack(SL* ps,int x)
{
assert(ps);
SLCheckCapacity(ps);//判断以下是否需要扩容
ps->arr[ps->size] = x;//经过判断是否扩容之后,直接插入arr[size]的位置
}
//6.顺序表的头插
//01(for循环实现)
void SLPushFront01(SL* ps, int x)
{
assert(ps);
SLCheckCapacity(ps);//判断以下是否需要扩容
for (int i = ps->size;i > 0;--i)
{
ps->arr[i] = ps->arr[i - 1];
}//只看头尾进行判断
ps->arr[0] = x;
ps->size++;
}
//02(while循环实现)
void SLPushFront02(SL* ps, int x)
{
assert(ps);
SLCheckCapacity(ps);//判断以下是否需要扩容
int begin = ps->size;
while (begin > 0)
{
ps->arr[begin] = ps->arr[begin - 1];
begin--;
}
ps->arr[0] = x;
ps->size++;
}
//03(内存操作函数memmove实现)
void SLPushFront03(SL* ps, int x)
{
assert(ps);
SLCheckCapacity(ps);//判断以下是否需要扩容
memmove((ps->arr) + 1, ps->arr, sizeof(SLDataType) * ps->size);
ps->arr[0] = x;
ps->size++;
}
//7.顺序表的指定位置插入
//01for循环实现
void SLInsert01(SL* ps, int pos, int x)
{
assert(ps);
SLCheckCapacity(ps);
for (int i = ps->size;i > pos;--i)
{
ps->arr[i] = ps->arr[i - 1];
}
ps->arr[pos] = x;
ps->size++;
}
//02while循环实现
void SLInsert02(SL* ps, int pos,int x)
{
assert(ps);
int begin = ps->size;
while (begin > pos)
{
ps->arr[begin] = ps->arr[begin - 1];
begin--;
}
ps->arr[pos] = x;
ps->size++;
}
//03memmove内存操作函数实现
void SLInsert03(SL* ps, int pos, int x)
{
assert(ps);
memmove(ps->arr + pos, ps->arr + pos + 1, sizeof(SLDataType) * (ps->size - pos));
ps->arr[pos] = x;
ps->size++;
}
//8.顺序表的头删
//01for循环实现
void SLPopFront01(SL* ps)
{
assert(ps);
assert(ps->size);
for (int i = 0;i < ps->size - 1;++i)
{
ps->arr[i] = ps->arr[i + 1];
}
ps->size--;
}
//02while循环实现
void SLPopFront02(SL* ps)
{
assert(ps);
assert(ps->size);
int begin = 0;
while (begin < ps->size - 1)
{
ps->arr[begin] = ps->arr[begin + 1];
}
ps->size--;
}
//03memmove内存操作函数实现
void SLPopFront03(SL* ps)
{
assert(ps);
assert(ps->size);
memmove(ps->arr, ps->arr + 1, sizeof(SLDataType) * (ps->size - 1));
ps->size--;
}
//9.顺序表的尾删
void SLPopBack(SL* ps)
{
assert(ps);
assert(ps->size);
ps->size--;
}
//10.指定位置删除
//01for循环实现
void SLErase01(SL* ps, int pos)
{
assert(ps);
assert(ps->size);
for (int i = pos;i < ps->size-1;++i)
{
ps->arr[i] = ps->arr[i + 1];
}
ps->size--;
}
//02while循环实现
void SLErase02(SL* ps, int pos)
{
assert(ps);
assert(ps->size);
int begin = pos;
while (begin < pos - 1)
{
ps->arr[begin] = ps->arr[begin + 1];
begin++;
}
ps->size--;
}
//03memmove内存操作函数实现
void SLErase03(SL* ps, int pos)
{
assert(ps);
assert(ps->size);
memmove(ps ->arr, ps->arr + 1, sizeof(SLDataType) * (ps->size - pos - 1));
ps->size--;
}
//查找接口的实现
int SLFind(SL* ps, int x)
{
for (int i = 0;i < ps->size;++i)
{
if (ps->arr[i] == x)
{
return i;
}
}
return -1;
}