目录
概念及结构
顺序表是用一段物理地址连续的存储单元依次存储数据元素的线性结构,一般情况下采用数组存储。在数组上完成数据的增删改查。
顺序表分类
- 静态顺序表:使用定长数组存储
- 动态顺序表:使用动态开辟的数组存储
接口实现
静态顺序表只适应于确定知道需要存多少数据的场景。静态顺序表的定长数组导致N定大了,空间开多了浪费,开少了不够用。所以现实中基本都是使用动态顺序表,根据需要动态分配空间大小,所以下面我们实现动态顺序表。
SeqList.h代码实现
#pragma once
#include <stdio.h>
#include <stdlib.h>
#include <assert.h>
//要求:存储的数据从0开始,依次连续存储
//静态的顺序表存在的问题:开小了不够用,开大了,存在浪费
//#define N 100
//struct SeqList
//{
// int a[N];
// int size; //记录存储了多少个数据
//};
typedef int SLDataType;
typedef struct SeqList
{
SLDataType* a; //指向动态开辟的数组
int size; //存储数据个数
int capacity; //存储空间大小
}SeqList;
void SeqListInit(SeqList* psl);//初始化
void SeqListDestroy(SeqList* psl);//销毁
void SeqListCheck(SeqList* psl);//检查空间,增容
void SeqListPrint(SeqList * p);//顺序表打印
int SeqListFind(SeqList* psl, SLDataType x);//查找
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的位置上插入x
void SeqListErase(SeqList* psl,size_t pos);//删除pos位置
SeqList.c代码实现
#include "SeqList.h"
void SeqListCheck(SeqList* psl)
{
if (psl->size == psl->capacity)
{
size_t newCapacity = psl->capacity == 0 ? 4 : psl->capacity * 2;
SLDataType* tmp = realloc(psl->a, sizeof(SLDataType)*newCapacity);
if (tmp == NULL)
{
printf("realloc fail\n");
exit(-1);
}
else
{
psl->a = tmp;
psl->capacity = newCapacity;
}
}
}
void SeqListPrint(SeqList * p)
{
for (int i = 0; i < p->size; i++)
{
printf("%d ", p->a[i]);
}
printf("\n");
}
void SeqListInit(SeqList* psl)
{
psl->a = NULL;
psl->size = 0;
psl->capacity = 0;
}
尾插的实现
从图中可以看出,我们只需在顺序表最后添加需要插入的值即可。首先我们要进行容量判断,判断是否需要扩容,因为插入位置的下标等于size,所以我们可以直接操作,最后将size++即可,代码实现如下:
void SeqListPushBack(SeqList* psl, SLDataType x)
{
//如果满了 ,要扩容
SeqListCheck(psl);
psl->a[psl->size] = x;
psl->size++;
}
尾删的实现
从上图可以看出,只要顺序表中还有数,那么我们只需将size--即可达到尾删的效果。
void SeqListPopBack(SeqList* psl)
{
if (psl->size > 0)
{
psl->size--;
}
}
头插的实现
如上图,首先进行容量检查,然后将所有元素依次往后移一位,找到插入的位置插入即可。代码如下:
void SeqListPushFront(SeqList* psl, SLDataType x)
{
assert(psl);
SeqListCheck(psl);
/*int end = psl->size - 1;
while (end >= 0)
{
psl->a[end + 1] = psl->a[end];
--end;
}
psl->a[0] = x;
psl->size++;*/
SeqListInsert(psl, 0, x);
}
头删的实现
如上图,从元素下标为1开始往前边依次移动元素,当移动到size的位置时停止,size--即可。代码实现如下:
void SeqListPopFront(SeqList* psl)
{
assert(psl);
/*if (psl->size > 0)
{
int begin = 1;
while (begin < psl->size)
{
psl->a[begin - 1] = psl->a[begin];
++begin;
}
--psl->size;
}*/
SeqListErase(psl, 0);
}
在pos的位置上插入x
实现思路和头插思路一样,代码实现如下:
void SeqListInsert(SeqList* psl, size_t pos, SLDataType x)
{
assert(psl);
if (pos > psl->size)
{
printf("pos越界\n");
return -1;
}
SeqListCheck(psl);
size_t end = psl->size;
while (end > pos)
{
psl->a[end] = psl->a[end - 1];
--end;
}
psl->a[pos] = x;
psl->size++;
}
删除pos位置的值
和头删实现方法一样,代码实现如下:
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 1;
}
}
return -1;
}