前言💖:
顺序表是线性表的一种,而线性表是n个具有相同特性的数据元素(换种说法,顺序表其实就是数组)的有限序列。线性表是在实际中广泛使用的数据结构,常见的线性表:顺序表,链表,栈,队列,字符串…
线性表在逻辑上是线性结构,也就是连续的一条直线。但是在物理结构上并不一定是连续的,线性表在物理上储存时,通常以数组和链式结构的形式存储。为什么要学习顺序表?
1.连续的物理空间,方便下标随机访问(查找访问)
2.支持排序,二分查找
车站🚗:
注释👀:
制作顺序表需要的功能有:增删查改
我们创建两个.c文件,一个.h文件分别实现菜单(test.c),具体代码(SeqList.c),函数声明和头文件(SeqList.h)
void SeqListPrint(SeqList* psl); //打印
void SeqListInit(SeqList* psl); //初始化
void SeqListDestroy(SeqList* psl); //清空
void SeqListCheckCapacity(SeqList* psl); //扩容
void SeqListPushBack(SeqList* psl, SLDataType x); //尾加
void SeqListPopBack(SeqList* psl); //尾删
void SeqListPushFront(SeqList* psl, SLDataType x); //头插
void SeqListPopFront(SeqList* psl); //头删
void SeqListInsert(SeqList* psl, size_t pos, SLDataType x); //在pos位置插入
void SeqListErase(SeqList* psl, size_t pos); //删除pos位置的数据
int SeqListFind(SeqList* psl, SLDataType x); //查找
void SeqListModify(SeqList* psl, size_t pos, SLDataType x); //修改
过程🙌:
//重定义int和链表名字,增加可读性和维护性
typedef int SLDataType;
typedef struct SeqList {
SLDataType* a;
int size; //存储数据的个数
int capacity; //存数据的大小(扩容大小)
}SeqList;
2.定义完成后,在菜单文件进行结构体命名,再实现初始化和打印函数
//test.c
SeqList s;
SeqListInit(&s); //传入结构体s的地址
//SeqList.h
void SeqListInit(SeqList* psl); //用*psl接收s
void SeqListPrint(SeqList* psl);
//SeqList.c
void SeqListInit(SeqList* psl)
{
assert(psl); //断言psl不为空
psl->a = NULL;
psl->size = 0;
psl->capacity = 0;
}
void SeqListPrint(SeqList* psl)
{
assert(psl);
for (int i = 0; i < psl->size; ++i)
{
printf("%d ", psl->a[i]);
}
printf("\n");
}
//SeqList.h
void SeqListCheckCapacity(SeqList* psl); //扩容
//SeqList.c
void SeqListCheckCapacity(SeqList* psl)
{
assert(psl);
if (psl->size == psl->capacity) //当已有大小等于扩容大小时
{
size_t newCapacity = psl->capacity == 0 ? 4 : psl->capacity * 2; //从4开始扩容,之后每扩一次都是两倍扩
SLDataType* tmp = realloc(psl->a, sizeof(SLDataType) * newCapacity); //用*tmp接收扩容后的值
if (tmp == NULL) //当已经无法扩容时退出程序
{
printf("realloc fail\n");
exit(-1);
}
else
{
psl->a = tmp;
psl->capacity = newCapacity;
}
}
}
4.完成了扩容函数,现在就可以开始实现插入删除了,我们先完成尾插尾删的函数
//test.c
SeqListPopBack(&s);//尾删
SeqListPushBack(&s, x); //尾插x
//SeqList.h
void SeqListPopBack(SeqList* psl);
void SeqListPushBack(SeqList* psl, SLDataType x);
//SeqList.c
void SeqListPopBack(SeqList* psl)
{
assert(psl);
if(psl->size > 0)
{
psl->size--;
}
}
void SeqListPushBack(SeqList* psl, SLDataType x)
{
assert(psl->a);
SeqListCheckCapacity(psl); //防止内存不够先进行扩容
psl->a[psl->size] = x; //原本最后一位下标为size-1,插入一个元素为size
psl->size++; //size个数+1
}
//test.c
SeqListPopFront(&s, x); //在头部插入x
SeqListPushFront(&s);
//SeqList.h
void SeqListPushFront(SeqList*psl,SLDataType x);
void SeqListPopFront(SeqList*psl);
//SeqList.c
void SeqListPushFront(SeqList* psl, SLDataType x)
{
assert(psl);
SeqListCheckCapacity(psl); //老样子,先扩容
int end = psl->size - 1;
while(end >= 0)
{
psl->a[end + 1] = psl->a[end]; //让元素依次往后移
--end;
}
psl->a[0] = x; //在覆盖完成后,x的值就可以赋给第一个元素了
psl->size++;
}
void SeqListPopFront(SeqList*psl)
{
assert(psl);
if(psl->size > 0) //防止size为负
{
int begin = 1; //定义下标begin,从第二个元素开始
while(begin < psl->size) //当begin没有超过size时便会一直覆盖
{
psl->a[begin - 1] = psl->a[begin]; //让元素依次往前移
begin++;
}
--psl->size; //size个数-1
}
}
//test.c
SeqListInsert(&s, pos, x);//在pos位置之前插入x
SeqListInsert(&s, pos); //在pos位置删除
//SeqList.h
void SeqListInsert(SeqList* psl, size_t pos, SLDataType x);
void SeqListErase(SeqList* psl, size_t pos);
//SeqList.c
void SeqListInsert(SeqList* psl, size_t pos, SLDataType x)
{
assert(psl);
assert(pos < psl->size); //防止查找的pos越界
SeqListCheckCapacity(psl); //扩容
size_t end = psl->size; //end为最后一个元素的下标
while (end > pos)
{
psl->a[end] = psl->a[end - 1]; //从后往前移动元素,直到遇到pos位置时停下,相当于将pos位置之前的位置进行前移
--end;
}
psl->a[pos] = x;
psl->size++;
}
void SeqListErase(SeqList* psl, size_t pos)
{
assert(psl);
assert(pos < psl->size);
size_t begin = pos + 1;
while(begin < psl->size)
{
psl->a[begin - 1] = psl->a[begin]; //从后往前移动
begin++;
}
psl->size--;
}
7.目前为止,我们的增和删就已经完成了,接下来的查和改就很简单了
//test.c
SeqListFind(&s, x);
SeqListModify(&s, pos, x); //将pos位置改为x
//SeqList.h
int SeqListFind(SeqList* psl, SLDataType x);
void SeqListModify(SeqList* psl, size_t pos, SLDataType x);
//SeqList.c
int SeqListFind(SeqList* psl, SLDataType x)
{
assert(psl);
for (int i = 0; i < psl->size; ++i)
{
if (psl->a[i] == x)
{
return i;
}
}
return -1;
}
void SeqListModify(SeqList* psl, size_t pos, SLDataType x)
{
assert(psl);
assert(pos < psl->size);
psl->a[pos] = x;
}
//test.c
SeqListDestroy(&s);
//SeqList.h
void SeqListDestroy(SeqList* psl);
//SeqList.c
void SeqListDestroy(SeqList* psl)
{
assert(psl);
free(psl->a); //注意:释放后的指针为野指针,我们还需要将其置空
psl->a = NULL;
psl->capacity = psl->size = 0;
}
test.c部分
#include "SeqList.h"
int main()
{
SeqList s;
SeqListInit(&s); //传入结构体s的地址
SeqListPushFront(&s, 13);//头插
SeqListPushFront(&s, 12);
SeqListPushFront(&s, 11);
SeqListPushFront(&s, 10);
SeqListPushBack(&s, 19);//尾插
SeqListPushBack(&s, 20);
SeqListPushBack(&s, 21);
SeqListPushBack(&s, 22);
SeqListInsert(&s, 3, 100);//在第三个元素后插入100
SeqListPrint(&s);
SeqListErase(&s, 3);//删除第三个元素
SeqListPopFront(&s); //头删
SeqListPopBack(&s); //尾删
SeqListPrint(&s);
int num = SeqListFind(&s, 11); //查找值为11的下标
printf("下标为:%d\n", num); //打印值为11的下标
SeqListModify(&s, 3, 200); //修改pos之后的值
SeqListPrint(&s);
SeqListDestroy(&s);
}
SeqList.h部分
#include <stdio.h>
#include <stdlib.h>
#include <assert.h>
typedef int SLDataType;
typedef struct SeqList {
SLDataType* a;
int size; //存储数据的个数
int capacity; //存数据的大小(扩容大小)
}SeqList;
void SeqListPrint(SeqList* psl); //打印
void SeqListInit(SeqList* psl); //初始化
void SeqListDestroy(SeqList* psl); //清空
void SeqListCheckCapacity(SeqList* psl); //扩容
void SeqListPushBack(SeqList* psl, SLDataType x); //尾加
void SeqListPopBack(SeqList* psl); //尾删
void SeqListPushFront(SeqList* psl, SLDataType x); //头插
void SeqListPopFront(SeqList* psl); //头删
void SeqListInsert(SeqList* psl, size_t pos, SLDataType x); //在pos位置插入
void SeqListErase(SeqList* psl, size_t pos); //删除pos位置的数据
int SeqListFind(SeqList* psl, SLDataType x); //查找
void SeqListModify(SeqList* psl, size_t pos, SLDataType x); //修改
SeqList.c部分
#include "SeqList.h"
void SeqListInit(SeqList* psl)
{
assert(psl); //断言psl不为空
psl->a = NULL;
psl->size = 0;
psl->capacity = 0;
}
void SeqListPrint(SeqList* psl)
{
assert(psl);
for (int i = 0; i < psl->size; ++i)
{
printf("%d ", psl->a[i]);
}
printf("\n");
}
void SeqListCheckCapacity(SeqList* psl)
{
assert(psl);
if (psl->size == psl->capacity) //当已有大小等于扩容大小时
{
size_t newCapacity = psl->capacity == 0 ? 4 : psl->capacity * 2; //从4开始扩容,之后每扩一次都是两倍扩
SLDataType* tmp = realloc(psl->a, sizeof(SLDataType) * newCapacity); //用*tmp接收扩容后的值
if (tmp == NULL) //当已经无法扩容时退出程序
{
printf("realloc fail\n");
exit(-1);
}
else
{
psl->a = tmp;
psl->capacity = newCapacity;
}
}
}
void SeqListPopBack(SeqList* psl)
{
assert(psl);
if (psl->size > 0)
{
psl->size--;
}
}
void SeqListPushBack(SeqList* psl, SLDataType x)
{
assert(psl->a);
SeqListCheckCapacity(psl); //防止内存不够先进行扩容
psl->a[psl->size] = x; //原本最后一位下标为size-1,插入一个元素为size
psl->size++; //size个数+1
}
void SeqListPushFront(SeqList* psl, SLDataType x)
{
assert(psl);
SeqListCheckCapacity(psl); //老样子,先扩容
int end = psl->size - 1;
while (end >= 0)
{
psl->a[end + 1] = psl->a[end]; //让元素依次往后移
--end;
}
psl->a[0] = x; //在覆盖完成后,x的值就可以赋给第一个元素了
psl->size++;
}
void SeqListPopFront(SeqList* psl)
{
assert(psl);
if (psl->size > 0) //防止size为负
{
int begin = 1; //定义下标begin,从第二个元素开始
while (begin < psl->size) //当begin没有超过size时便会一直覆盖
{
psl->a[begin - 1] = psl->a[begin]; //让元素依次往前移
begin++;
}
--psl->size; //size个数-1
}
}
void SeqListInsert(SeqList* psl, size_t pos, SLDataType x)
{
assert(psl);
assert(pos < psl->size); //防止查找的pos越界
SeqListCheckCapacity(psl); //扩容
size_t end = psl->size; //end为最后一个元素的下标
while (end > pos)
{
psl->a[end] = psl->a[end - 1]; //从后往前移动元素,直到遇到pos位置时停下,相当于将pos位置之前的位置进行前移
--end;
}
psl->a[pos] = x;
psl->size++;
}
void SeqListErase(SeqList* psl, size_t pos)
{
assert(psl);
assert(pos < psl->size);
size_t begin = pos + 1;
while (begin < psl->size)
{
psl->a[begin - 1] = psl->a[begin]; //从后往前移动
begin++;
}
psl->size--;
}
int SeqListFind(SeqList* psl, SLDataType x)
{
assert(psl);
for (int i = 0; i < psl->size; ++i)
{
if (psl->a[i] == x)
{
return i;
}
}
return -1;
}
void SeqListModify(SeqList* psl, size_t pos, SLDataType x)
{
assert(psl);
assert(pos < psl->size);
psl->a[pos] = x;
}
void SeqListDestroy(SeqList* psl)
{
assert(psl);
free(psl->a); //注意:释放后的指针为野指针,我们还需要将其置空
psl->a = NULL;
psl->capacity = psl->size = 0;
printf("释放完成!\n");
}