文章目录
前言
线性表的顺序存储是指用一组地址连续的存储单元依次存储线性表中的各个元素、使得线性表中在逻辑结构上相邻的数据元素存储在相邻的物理存储单元中,即通过数据元素物理存储的相邻关系来反映数据元素之间逻辑上的相邻关系。
采用顺序存储结构的线性表通常称为顺序表。
顺序表是将表中的结点依次存放在计算机内存中一组地址连续的存储单元中。
一、什么是顺序表?
顺序表是用一段物理地址连续的存储单元依次存储数据元素的线性结构,一般情况下采用数组存储。在数组上完成数据的增删查改。
二、接口实现
顺序表的实现包括其声明和定义
声明存放在SeqList.h文件中,其定义则存放在SeqList.c文件中
1.SeqList.h
#include <stdio.h>
#include <stdlib.h>
#include <stdbool.h>
#include <assert.h>
#define INIT_CAPACITY 4
//顺序表:物理上内存连续,使用结构体
typedef int SLDataType;
typedef struct SL
{
SLDataType* a;//利用数组来实现顺序表
int size;//顺序表存放的元素下标
int capacity;//顺序表容量
}SL;
//初始化
void SLInit(SL* psl);
//销毁
void SLDestroy(SL* psl);
//增删查改
//尾插
void SLPushBack(SL* psl, SLDataType x);
//头插
void SLPushFront(SL* psl, SLDataType x);
//尾删
void SLPopBack(SL* psl);
//头删
void SLPopFront(SL* psl);
//求取有效元素个数
int SLSize(SL* psl);
//判空
bool SLEmpty(SL* psl);
//判满
bool SLIsFull(SL* psl);
//给定位置插入
void SLInsert(SL* psl, int pos, SLDataType x);
//在pos位置删除
void SLErase(SL* psl, int pos);
//打印
void PrintSLArray(SL* psl);
2.SeqList.c
#define _CRT_SECURE_NO_WARNINGS 1
#include "SeqList.h"
//初始化
void SLInit(SL* psl)
{
assert(psl);
psl->a = (SLDataType*)malloc(sizeof(SLDataType) * INIT_CAPACITY);
if (psl->a == NULL)
{
perror("malloc fail");
return;
}
//初始化size和capacity
psl->size = 0;
psl->capacity = INIT_CAPACITY;
}
//销毁
void SLDestroy(SL* psl)
{
assert(psl);
psl->size = psl->capacity = 0;
free(psl->a);
psl->a = NULL;
}
//扩容
void CheckCapacityIsFull(SL* psl)
{
assert(psl);
if (psl->size == psl->capacity)
{
//需要扩容
SLDataType* tmp = (SLDataType*)realloc(psl->a, sizeof(int)*psl->capacity * 2);
if (tmp == NULL)
{
perror("realloc fail");
return;
}
//扩容成功
psl->a = tmp;
psl->capacity *= 2;
}
}
//尾插
void SLPushBack(SL* psl, SLDataType x)
{
assert(psl);
CheckCapacityIsFull(psl);
//插入元素
psl->a[psl->size] = x;
psl->size++;
}
//头插
void SLPushFront(SL* psl, SLDataType x)
{
assert(psl);
//需要将元素向后覆盖
int end = psl->size;
CheckCapacityIsFull(psl);
while (end >= 0)
{
psl->a[end + 1] = psl->a[end];
end--;
}
psl->a[0] = x;
psl->size++;
}
//尾删
void SLPopBack(SL* psl)
{
assert(psl);
assert(SLEmpty(psl)!=true);
//直接更改size
psl->size--;
}
//头删
void SLPopFront(SL* psl)
{
assert(psl);
assert(SLEmpty(psl) != true);
//向前继续进行数据的覆盖
int begin = 1;
while (begin < psl->size)
{
psl->a[begin - 1] = psl->a[begin];
begin++;
}
psl->size--;
}
//求取有效元素个数
int SLSize(SL* psl)
{
assert(psl);
return psl->size;
}
//判空
bool SLEmpty(SL* psl)
{
assert(psl);
return psl->size == 0;
}
//在pos位置插入
void SLInsert(SL* psl, int pos, SLDataType x)
{
assert(psl);
int cur = psl->size;
//将pos以后含pos位置的元素向后覆盖
CheckCapacityIsFull(psl);
while (cur >= pos)
{
psl->a[cur + 1] = psl->a[cur];
cur--;
}
psl->a[pos] = x;
psl->size++;
}
//在pos位置删除
void SLErase(SL* psl, int pos)
{
assert(psl);
assert(SLEmpty(psl) != true);
int cur = pos + 1;
while (cur<psl->size)
{
//将pos之后的数据向前覆盖
psl->a[cur - 1] = psl->a[cur];
cur++;
}
psl->size--;
}
//打印
void PrintSLArray(SL* psl)
{
for (int i = 0; i < psl->size; i++)
{
printf("%d ", psl->a[i]);
}
printf("\n");
}
注意事项:
头插函数:对头元素进行修改,需要对后面的元素进行移动,即向后覆盖
头删函数:从头元素后面的位置进行向前覆盖,后续过程相同
总结
顺序表是数据结构中的基础结构,其本质是利用一块连续空间对于数据进行保存,相比较来说,其实现逻辑较为简单,无需太多赘述,但我们可以从中领略到它的独特的思想,同时,它也为我们后续的学习奠定了基础,它无法解决非连续空间的数据存储,那么我们又该如何解决该问题呢?这就是后面需要讨论的了!