目录
1.顺序表的概念
顺序表是用一段物理地址连续的存储单元依次存储数据元素的线性结构,一般情况下采用数组存储。在数组上完成数据的增删查改。
不过还是有一点区别的:数组的数据可以按照下标随意存放数据,顺序表需要按照空间的顺序存放。
1.1分类
顺序表可以分为:静态顺序表、动态顺序表。
静态顺序表:
//静态版本
#define N 6
typedef int SLDataType;
typedef struct SeqList
{
SLDataType a[N];
size_t size;
}SL;
静态顺序表值适用于确定知道需要存多少数据的情景。这在一定程度上是不太方便的,静态顺序表的定长数组其中的N大了就会浪费空间,N小了就会不够用。所以现实中使用动态顺序表的场景更多,根据需要的存储空间来申请内存大小。下面我们一起来看看动态顺序表的接口实现:
新建一个工程:
SeqList.h(顺序表的定义、头文件的引用、函数声明)
SeqList.c(具体接口函数的实现)
Test.c(测试)
2.顺序表的定义
typedef int SLDataType;
typedef struct SeqList
{
SLDataType* a;//顺序表所定义元素类型的指针
int size;//顺序表当前元素类型
int capacity;//顺序表的容量
}SL;
3.顺序表的初始化
void SLInit(SL* psl)
{
assert(psl);
psl->a = (SLDataType*)malloc(sizeof(SLDataType)*4);//初始化开辟4个所要定义元素类型的空间
if (psl->a == NULL)
{
perror("malloc fail");
return;
}
psl->capacity = 4;//容量初始化为4
psl->size = 0;//还没有放入元素,size为0
}
初始化开辟4个空间。
4.顺序表的销毁
void SLDestroy(SL* psl)
{
assert(psl);//断言
free(psl->a);
psl->a = NULL;
psl->size = 0;
psl->capacity = 0;
}
5.顺序表的头插、尾插
在顺序表需要插入数据的时候,如果空间是够的就直接插入数据,在空间不够的时候需要考虑扩容的问题,所以我们写一个检查是否需要扩容的函数,便于头插、尾插前的复用,减少重复的代码量。
如果空间不足,我们将开辟的空间大小为当前大小的2倍。代码如下:
void SLCheckCapacity(SL*psl)
{
assert(psl);
if (psl->size == psl->capacity)
{
SLDataType* tmp = (SLDataType*)realloc(psl->a,sizeof(SLDataType)*psl->capacity*2);
if (tmp == NULL)
{
perror("realloc fail");
return;
}
psl->a = tmp;
psl->capacity *= 2;
}
}
头插:
void SLPushFront(SL* psl, SLDataType x)
{
assert(psl);
SLCheckCapacity(psl);
int end = psl->size - 1;
while (end >= 0)//挪动数据
{
psl->a[end + 1] = psl->a[end];
--end;
}
psl->a[0] = x;
psl->size++;
}
尾插:
void SLPushBack(SL* psl, SLDataType x)
{
assert(psl);
SLCheckCapacity(psl);
psl->a[psl->size] = x;
psl->size++;
}
在实现了头插和尾插情况下,实现一下在pos处添加数据函数的实现。
void SLInsert(SL* psl, int pos, SLDataType x)
{
assert(psl);
assert(0<=pos && pos<=psl->size);
SLCheckCapacity(psl);
int end = psl->size - 1;
while (end >= pos)
{
psl->a[end + 1] = psl->a[end];
--end;
}
psl->a[pos] = x;
psl->size++;
}
6.顺序表的头删、尾删
头删:
void SLPopFront(SL* psl)
{
assert(psl->size > 0);
int start = 0;
while (start < psl->size - 1)
{
psl->a[start] = psl->a[start + 1];
start++;
}
psl->size--;
}
尾删:
void SLPopBack(SL* psl)
{
assert(psl->size > 0);
psl->a[psl->size - 1] = 0;
psl->size--;
}
在实现头删、尾删的情况下,实现一下删除pos位置的数据,代码如下:
void SLErase(SL* psl, int pos)
{
assert(0 <= pos && pos < psl->size);
SLCheckCapacity(psl);
int start = pos + 1;
while (start < psl->size)
{
psl->a[start - 1] = psl->a[start];
start++;
}
psl->size--;
}
7.顺序表的查找
查找某一个事数据的位置(找到返回数据下标,找不到返回-1)
void SLFind(SL* psl, SLDataType x)
{
assert(psl);
int i = 0;
for (i = 0; i < psl->size; i++)
{
if (psl->a[i] == x)
{
return i;
}
}
return -1;
}
8.顺序表的修改
更改在pos位置的数据
void SLModify(SL* psl, int pos, SLDataType x)
{
assert(psl);
assert(0<=pos && pos< psl->size);
psl->a[pos] = x;
}
9.打印函数
void SLPrintf(SL* psl)
{
assert(psl);
int i = 0;
for (i = 0; i < psl->size; i++)
{
printf("%d ",psl->a[i]);
}
printf("\n");
}
这样顺序表的基本操作的接口就实现完了。
今天分享寄到这里,希望大家一起提高!!!