目录
顺序表的概念及结构
顺序表的实现
初始化顺序表
顺序表的增加
尾插
头插
顺序表的删除
尾删
头删
销毁顺序表
顺序表查找
在pos位置插入元素
在pos位置删除元素
说明
整合源代码
顺序表:指的是用一组地址连续的存储单元依次存储线性表的数据元素。一般情况下采 用数组存储,在数组上完成数据的增删查改。
顺序表一般可以分为静态顺序表和动态顺序表
静态顺序表---使用定长数组存储元素。分配的空间长度是固定的,表一旦空间不足时不 能扩充。
存储结构类型定义:
动态顺序表---使用动态开辟的数组存储。分配的空间长度大小是可变的,当空间不足时可进行再次分配,即可自由扩充空间大小。
存储类型定义:
静态顺序表只适用于确定知道需要存多少数据的场景,静态顺序表的定长数组分配的空间长度是固定的,不能自由扩充,可能存在浪费或不够用。因此,现实中基本都是使用动态顺序表,根据需要动态的分配空间大小,所以我们实现动态顺序表。
当在一些大型项目中,分模块进行是比较常见的,因此,顺序表的实现就采用分模块的方式.
顺序表的实现需要分两个模块:SeqList.h和SeqList.c
SeqList.h //函数的声明及类型的定义
#include
#include
#include
typedef int SLDateType;
//动态顺序表
typedef struct SeqList
{
SLDateType* a;
int size; //当前有效元素的个数
int capacity; //当前分配的最大存储容量
}SeqList;
//初始化顺序表
void SeqListInit(SeqList* ps);
//销毁顺序表
void SeqListDestroy(SeqList* ps);
//顺序表的增加
//尾插、尾删
void SeqListPushBack(SeqList* ps, SLDateType x);
void SeqListPopBack(SeqList* ps);
//头插、头删
void SeqListPushFront(SeqList* ps, SLDateType x);
void SeqListPopFront(SeqList* ps);
// 顺序表查找
//找到返回下标、找不到返回-1
int SeqListFind(SeqList* ps, SLDateType x);
// 顺序表在pos位置插入x
void SeqListInsert(SeqList* ps, int pos, SLDateType x);
// 顺序表删除pos位置的值
void SeqListErase(SeqList* ps, int pos);
SeqList.c //函数的实现
初始化时预先给表分配一些空间
void SeqListInit(SeqList* ps)
{
assert(ps); //防止为空指针
ps->a = (SLDateType*)malloc(sizeof(SLDateType) * 4);//动态开辟数组空间
if (ps->a == NULL)
{
perror("malloc failed");
exit(-1);
}
ps->size = 0; //当前有效元素个数初始化为0
ps->capacity = 4; //当前起始最大限度存储容量先设为4
}
此时比较简便,直接在size个元素后插入即可。 但在插入元素当前空间是否已满,此时采用封装一个检查容量并增容的函数,直接调用此函数判断是否空间已满,后面用起来比较方便。
//检查容量并增容
void SLCheckCapacity(SeqList* ps)
{
assert(ps);
if (ps->size == ps->capacity)
{
SLDateType* pt = (SLDateType*)realloc(ps->a, ps->capacity * 2 * sizeof(SLDateType));
if (pt == NULL)
{
perror("realloc failed");
exit(-1);
}
ps->a = pt;
ps->capacity *= 2;
}
}
//尾插
void SeqListPushBack(SeqList* ps, SLDateType x)
{
SLCheckCapacity(ps); //判断空间是否满了,若满则扩容
ps->a[ps->size] = x; //插入值为x的元素
ps->size++; //元素个数加一
}
在插入元素之前需要判满。比起尾插较麻烦一些,要从尾部开始size个元素依次往后挪。
//头插
void SeqListPushFront(SeqList* ps, SLDateType x)
{
assert(ps);
SLCheckCapacity(ps);//检查容量
int end = ps->size - 1; //尾元素所在位置
//后面元素依次向后挪
while(end >= 0)
{
ps->a[end + 1] = ps->a[end];
end--;
}
//插入元素
ps->a[0] = x;
ps->size++;
}
在删除元素之前,需要先判断当前是否为空,这里使用assert来检查,这是一种严格的检查,相比if判断比较暴力,若元素为空直接终止并提示程序异常。if也可判断
//尾删
void SeqListPopBack(SeqList* ps)
{
assert(ps);
assert(ps->size > 0); //检查是否为空,为空程序异常报错,这是比较严格的检查;也可用if来判断
ps->size--; //元素个数减一
}
同样需要先进行检查是否为空,检查方式同上。
//头删
void SeqListPopFront(SeqList* ps)
{
assert(ps);
assert(ps->size > 0); //检查是否为空
int start = 1; //首元素的位置
//后面size-1个元素依次向前覆盖
while (start < ps->size)
{
ps->a[start - 1] = ps->a[start];
start++;
}
//元素个数减一
ps->size--;
}
//顺序表的销毁
void SeqListDestroy(SeqList* ps)
{
assert(ps);
free(ps->a); //释放动态开辟的数组
ps->a = NULL;
ps->capacity = ps->size = 0;
}
查找值为x的元素,找到了就返回元素所在的下标,找不到返回-1。
//顺序表的查找
int SeqListFind(SeqList* ps, SLDateType x)
{
assert(ps);
int i = 0;
//查找值为x的元素,找到返回其下标,否则返回-1
for (i = 0; i < ps->size; i++)
{
if (ps->a[i] == x)
return i;
}
return -1;
}
在插入元素之前,需要检查插入位置是否合法以及当前空间容量。
// 在pos位置插入x
void SeqListInsert(SeqList* ps, int pos, SLDateType x)
{
assert(pos >= 0 && pos <= ps->size); //位置是否合法
SLCheckCapacity(ps); //判断当前容量是否为空
int end = ps->size - 1; //尾元素的位置
//pos位置及其后面的元素依次后挪
while (end >= pos)
{
ps->a[end + 1] = ps->a[end];
end--;
}
ps->a[pos] = x; //在插入位置插入元素x
ps->size++; //元素个数加一
}
同样注意删除前要判断插入位置是否合法
// 在pos位置删除x
void SeqListErase(SeqList* ps, int pos)
{
assert(pos >= 0 && pos < ps->size); //插入位置是否合法
int start = pos + 1; //找到要删除元素位置后一个元素的位置
//pos位置后面的元素依次向前覆盖
while (start < ps->size)
{
ps->a[start - 1] = ps->a[start];
start++;
}
ps->size--; //元素个数减一
}
前面的头插尾插、头删尾删都可附用以上两段代码,在插入和删除时无伦头插头删、尾插尾删或者只要是插入和删除操作均可,即插入和删除通用代码,用时直接调用即可
//SeqList.h
#include
#include
#include
typedef int SLDateType;
typedef struct SeqList
{
SLDateType* a;
int size;
int capacity;
}SeqList;
//初始化顺序表
void SeqListInit(SeqList* ps);
//打印顺序表
void SeqListPrint(SeqList* ps);
//销毁顺序表
void SeqListDestroy(SeqList* ps);
//顺序表的增加
//尾插、尾删
void SeqListPushBack(SeqList* ps, SLDateType x);
void SeqListPopBack(SeqList* ps);
//头插、头删
void SeqListPushFront(SeqList* ps, SLDateType x);
void SeqListPopFront(SeqList* ps);
// 顺序表查找
int SeqListFind(SeqList* ps, SLDateType x);
// 顺序表在pos位置插入x
void SeqListInsert(SeqList* ps, int pos, SLDateType x);
// 顺序表删除pos位置的值
void SeqListErase(SeqList* ps, int pos);
//SeqList.c
#include "SeqList.h"
void SeqListInit(SeqList* ps)
{
assert(ps);
ps->a = (SLDateType*)malloc(sizeof(SLDateType) * 4);
if (ps->a == NULL)
{
perror("malloc failed");
exit(-1);
}
ps->size = 0;
ps->capacity = 4;
}
//检查容量并增容
void SLCheckCapacity(SeqList* ps)
{
assert(ps);
if (ps->size == ps->capacity)
{
SLDateType* pt = (SLDateType*)realloc(ps->a, ps->capacity * 2 * sizeof(SLDateType));
if (pt == NULL)
{
perror("realloc failed");
exit(-1);
}
ps->a = pt;
ps->capacity *= 2;
}
}
//顺序表增添数据
//尾插
void SeqListPushBack(SeqList* ps, SLDateType x)
{
SLCheckCapacity(ps);
ps->a[ps->size] = x;
ps->size++;
}
//尾删
void SeqListPopBack(SeqList* ps)
{
assert(ps);
assert(ps->size > 0);
ps->size--;
}
//头插
void SeqListPushFront(SeqList* ps, SLDateType x)
{
assert(ps);
SLCheckCapacity(ps);
int end = ps->size - 1;
while(end >= 0)
{
ps->a[end + 1] = ps->a[end];
end--;
}
ps->a[0] = x;
ps->size++;
}
//头删
void SeqListPopFront(SeqList* ps)
{
assert(ps);
assert(ps->size > 0);
int start = 1;
while (start < ps->size)
{
ps->a[start - 1] = ps->a[start];
start++;
}
ps->size--;
}
//顺序表的销毁
void SeqListDestroy(SeqList* ps)
{
assert(ps);
free(ps->a);
ps->a = NULL;
ps->capacity = ps->size = 0;
}
//顺序表的查找
int SeqListFind(SeqList* ps, SLDateType x)
{
assert(ps);
int i = 0;
for (i = 0; i < ps->size; i++)
{
if (ps->a[i] == x)
return i;
}
return -1;
}
// 在pos位置插入x
void SeqListInsert(SeqList* ps, int pos, SLDateType x)
{
assert(pos >= 0 && pos <= ps->size);
SLCheckCapacity(ps);
int end = ps->size - 1;
while (end >= pos)
{
ps->a[end + 1] = ps->a[end];
end--;
}
ps->a[pos] = x;
ps->size++;
}
// 在pos位置删除x
void SeqListErase(SeqList* ps, int pos)
{
assert(pos >= 0 && pos < ps->size);
int start = pos + 1;
while (start < ps->size)
{
ps->a[start - 1] = ps->a[start];
start++;
}
ps->size--;
}