目录
顺序表介绍
创建顺序表类型
初始化顺序表
销毁顺序表
打印顺序表
增加数据
头插
尾插
删除数据
头删
尾删
查找数据
修改指定下标的数据
整体代码
什么是顺序表?
顺序表是用一段物理地址连续的存储单元依次存储数据元素的线性结构,一般情况下采用数组存储。在数组 上完成数据的增删查改。
顺序表分为两种:一种是静态顺序表,另一种是动态开辟的顺序表
说简单一点,其实顺序表就是类比数组!
静态顺序表只适用于确定知道需要存多少数据的场景。静态顺序表的定长数组导致N定大了,空间开多了浪费,开少了不够用。所以现实中基本都是使用动态顺序表,根据需要动态的分配空间大小,所以下面我们实现动态顺序表。
typedef int SLDataType;
typedef struct SeqList
{
SLDataType* a;
int size;
int capacity;
}SL;
声明一个指针a用于动态开辟空间,用size记录当前顺序表中的数据个数,用capacity记录顺序表的容量大小
void SeqListInit(SL*ps)//初始化
{
assert(ps);
ps->a = NULL;
ps->size = 0;
ps->capacity = 0;
}
初始化就是全部变量置0处理
void SeqListDestory(SL* ps)//销毁
{
assert(ps);
free(ps->a);
ps = NULL;
ps->capacity = ps->size = 0;
}
因为是在内存的堆上进行动态内存开辟的,所以要及时释放空间,避免内存泄漏
void SeqListPrint(SL* ps)
{
assert(ps);
int i = 0;
for (i = 0; i < ps->size; i++)
{
printf("%d-> ",ps->a[i]);
}
printf("\n");
}
遍历进行打印即可
void SeqListCheckCapacity(SL* ps)//检查容量
{ assert(ps);
if (ps->size == ps->capacity)
{
int newcapacity = ps->capacity == 0 ? 4 : ps->capacity * 2;
SLDataType* tmp = (SLDataType)realloc(ps->a, newcapacity * sizeof(SLDataType));
if (tmp == NULL)
{
printf("realloc fail\n");
exit(-1);
}
ps->a = tmp;
ps->capacity = newcapacity;
}
}
void SeqListInsert(SL* ps,int pos, SLDataType x)
{
assert(ps);
assert(pos >= 0 && pos <= ps->size);
SeqListCheckCapacity(ps);
int i = 0;
for (i=ps->size-1;i>=pos;i--)
{
ps->a[i+1] = ps->a[i];//pos后的数据依次往后面挪动
}
ps->a[pos] = x;
ps->size++;
}
增加数据前,我们都要先检查一下空间容量是否已经满了,满了则需要扩容,容量变为原来的2倍,然后就可以在想要的位置pos插入数据了
void SeqListPushFront(SL* ps, SLDataType x)//在pos=0的位置插入数据
{ assert(ps);
SeqListInsert(ps, 0, x);
}
void SeqListPushBack(SL* ps, SLDataType x)//在size位置插入数据
{ assert(ps);
SeqListInsert(ps, ps->size, x);
}
在这里我们都可以调用我们的任意下标pos位置插入的函数,即头插就是在0位置处插入数据,尾插就是在size-1位置处插入数据
void SeqListErase(SL* ps, int pos)
{
assert(ps);
assert(pos>=0&&pos<=ps->size);
int i = 0;
for (i=pos;isize-1;i++)
{
ps->a[i-1] = ps->a[i];
}
ps->size--;
}
从pos下标位置开始,其后的数据从前往后依次向前覆盖,相当于将哪个数据删除了
void SeqListPopFront(SL* ps)//删除下标为0的位置的数据
{ assert(ps);
SeqListErase(ps, 0);
}
void SeqListPopBack(SL* ps)//删除下标为ps->size - 1的位置的数据
{ assert(ps);
SeqListErase(ps, ps->size - 1);
}
头删和尾删原理和头插和尾插类似,我们只需要调用在任意位置pos插入的函数,即头删就是在0的位置删除数据,尾删就是在size-1的位置删除数据
int SeqListFind(SL* ps, SLDataType x)
{ assert(ps);
for (int i = 0; i < ps->size; i++)
{
if (ps->a[i] == x)
{
return i;
}
}
return -1;
}
void SeqListModify(SL* ps, int pos, SLDataType x)
{
assert(ps);
assert(pos >= 0 && pos < ps->size);//检查输入下标的合法性
ps->a[pos] = x;//修改数据
}
//SList.h
#define _CRT_SECURE_NO_WARNINGS 1
#include
#include
#include
typedef int SLDataType;
typedef struct SeqList
{
SLDataType* a;
int size;
int capacity;
}SL;
void SeqListInit(SL* ps);//初始化
void SeqListDestory(SL* ps);//销毁
void SeqListCheckCapacity(SL* ps);//检查容量
void SeqListPopFront(SL* ps);//头删
void SeqListPopBack(SL* ps);//尾删
void SeqListErase(SL* ps, int pos);//直接删
void SeqListInsert(SL* ps, int pos, SLDataType x);//直接插
void SeqListPushFront(SL* ps, SLDataType x);//头插
void SeqListPushBack(SL* ps, SLDataType x);//尾插
void SeqListPrint(SL* ps);//打印
void SeqListModify(SL* ps, int pos, SLDataType x);//修改指定下标位置元素
int SeqListFind(SL* ps, SLDataType x);//查找数据
//SList.c
void SeqListInit(SL*ps)//初始化
{
ps->a = NULL;
ps->size = 0;
ps->capacity = 0;
}
void SeqListDestory(SL* ps)//销毁
{
free(ps->a);
ps = NULL;
ps->capacity = ps->size = 0;
}
void SeqListCheckCapacity(SL* ps)//检查容量
{
if (ps->size == ps->capacity)
{
int newcapacity = ps->capacity == 0 ? 4 : ps->capacity * 2;
SLDataType* tmp = (SLDataType)realloc(ps->a, newcapacity * sizeof(SLDataType));
if (tmp == NULL)
{
printf("realloc fail\n");
exit(-1);
}
ps->a = tmp;
ps->capacity = newcapacity;
}
}
//头删
void SeqListPopFront(SL* ps)//删除下标为0的位置的数据
{
SeqListErase(ps, 0);
}
//尾删
void SeqListPopBack(SL* ps)//删除下标为ps->size - 1的位置的数据
{
SeqListErase(ps, ps->size - 1);
}
//直接删
void SeqListErase(SL* ps, int pos)
{
assert(ps);
assert(pos>=0&&pos<=ps->size);
int i = 0;
for (i=pos;isize-1;i++)//从pos下标位置开始,其后的数据从前往后依次向前覆盖
{
ps->a[i-1] = ps->a[i];
}
ps->size--;
}
//查找数据
int SeqListFind(SL* ps, SLDataType x)
{
for (int i = 0; i < ps->size; i++)
{
if (ps->a[i] == x)
{
return i;
}
}
return -1;
}
//修改指定下标位置元素
void SeqListModify(SL* ps, int pos, SLDataType x)
{
assert(ps);
assert(pos >= 0 && pos < ps->size);//检查输入下标的合法性
ps->a[pos] = x;//修改数据
}
//直接插
void SeqListInsert(SL* ps,int pos, SLDataType x)
{
assert(ps);
assert(pos >= 0 && pos <= ps->size);
SeqListCheckCapacity(ps);
int i = 0;
for (i=ps->size-1;i>=pos;i--)
{
ps->a[i+1] = ps->a[i];//pos后的数据依次往后面挪动
}
ps->a[pos] = x;
ps->size++;
}
//头插
void SeqListPushFront(SL* ps, SLDataType x)//在pos=0的位置插入数据
{
SeqListInsert(ps, 0, x);
}
//尾插
void SeqListPushBack(SL* ps, SLDataType x)//在size位置插入数据
{
SeqListInsert(ps, ps->size, x);
}
//打印
void SeqListPrint(SL* ps)
{
assert(ps);
int i = 0;
for (i = 0; i < ps->size; i++)
{
printf("%d-> ",ps->a[i]);
}
printf("\n");
}
//test.c
void test()
{
SL a;
SeqListInit(&a);
SeqListInsert(&a,0,1);
SeqListInsert(&a, 1, 2);
SeqListErase(&a,1);
SeqListPrint(&a);
}
int main()
{
test();
return 0;
}
记得在每个函数传入指针时加入assert(ps);断言报错一下,以防传入空指针!
谢谢各位的观看!