一、顺序表
1.1概念及结构
顺序表是用一段物理地址连续的存储单元依次存储数据元素的线性结构,一般情况下采用数组存储。在数组上完成数据的增删查改。(顺序表就是数组,但是在数组的基础上,要求数据是从头开始并且连续存储的,不能跳跃间隔存放)
顺序表一般可以分为:
1. 静态顺序表:使用定长数组存储元素。
2. 动态顺序表:使用动态开辟的数组存储。
二、顺序表增删代码(C语言)
静态顺序表只适用于确定知道需要存多少数据的场景。静态顺序表的定长数组导致N定大了,空间开多了浪费,开少了不够用。所以现实中基本都是使用动态顺序表,根据需要动态的分配空间大小,所以下面我们实现动态顺序表。
我们创建
一个头文件:SeqList.h
两个源文件:1、SeqList.c 2、Test.c
SeqList.h 文件下的 代码:
#include<stdio.h>
#include<stdlib.h>
typedef int SLDataType;
//动态顺序表
typedef struct SeqList//定义一个结构体
{
SLDataType *a;
int size;//大小 表示数组中储存了多少个数据
int capacity;
}SL;
void SeqListnewcapacity(SL* ps);//增容函数
void SeqListPrint(SL* ps);//打印函数
void SeqListDestory(SL* ps);//释放空间
//接口函数 命名规范参照STL
void SeqListPushInit(SL* ps);//初始化结构体
void SeqListPushBack(SL* ps, SLDataType x);//在顺序表后面增加一个数
void SeqListPopBack(SL* ps);//删除顺序表最后一个
void SeqListPushFront(SL* ps, SLDataType x);//在顺序表前面增加一个数
void SeqListPopFront(SL* ps);//在顺序表前面删除一个数
SeqList.c文件下的代码 (主要为函数的实现)
#define _CRT_SECURE_NO_WARNINGS 1
#include"SeqList.h"
void SeqListPrint(SL* ps)//打印函数
{
for (int i = 0; i < ps->size; i++)
{
printf("%d ", ps->a[i]);
}
printf("\n");
}
void SeqListPushInit(SL* ps)//结构体初始化---Init 初始化
{
ps->a = NULL;
ps->capacity = ps->size = 0;
}
void SeqListnewcapacity(SL* ps)//开辟一个空间
{
if (ps->size == ps->capacity)
{
//newcapacity——新容量
int newcapacity = ps->capacity == 0 ? 4 : ps->capacity * 2;
//如果ps->capacity=0那么newcapacity就等于4,
//否则就等于capacity的两倍
SLDataType* tmp = (SLDataType*)realloc(ps->a, newcapacity * sizeof(SLDataType));
//开劈一个空间
if (tmp == 0)
{
printf("realloc fail\n");
exit(-1);//终止程序
}
ps->a = tmp;
ps->capacity = newcapacity;
}
}
void SeqListDestory(SL* ps)//释放前面开辟的空间
{
free(ps->a);
ps->a = NULL;
ps->capacity = ps->size = 0;
}
void SeqListPushBack(SL* ps, SLDataType x)//在顺序表后面增加一个数
{
SeqListnewcapacity(ps);
ps->a[ps->size] = x;
ps -> size++;
}
void SeqListPopBack(SL* ps)//删除末尾数
{
if (ps->size != 0)
{
ps->size--;
}
}
void SeqListPushFront(SL* ps, SLDataType x)//在顺序表前面增加一个数
{
SeqListnewcapacity(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(SL* ps)
{
if (ps->size != 0)
{
int begin = 1;
while (begin < ps->size)
{
ps->a[begin - 1] = ps->a[begin];
begin++;
}
ps->size--;
}
}
Test.c文件下的代码:
#define _CRT_SECURE_NO_WARNINGS 1
#include"SeqList.h"
TestSeqList1()
{
SL s1;//定义一个s1
SeqListPushInit(&s1);
SeqListPushBack(&s1, 1);
SeqListPushBack(&s1, 2);
SeqListPushBack(&s1, 3);
SeqListPushBack(&s1, 4);
SeqListPushBack(&s1, 5);
SeqListPrint(&s1);
SeqListPopBack(&s1);
SeqListPopBack(&s1);
SeqListPopBack(&s1);
SeqListPrint(&s1);
SeqListDestory(&s1);
}
TestSeqList2()
{
SL s1;//定义一个s1
SeqListPushInit(&s1);
SeqListPushBack(&s1, 1);
SeqListPushBack(&s1, 2);
SeqListPushBack(&s1, 3);
SeqListPushBack(&s1, 4);
SeqListPushBack(&s1, 5);
SeqListPrint(&s1);
SeqListPushFront(&s1, 10);
SeqListPushFront(&s1, 40);
SeqListPrint(&s1);
SeqListPopFront(&s1);
SeqListPopFront(&s1);
SeqListPopFront(&s1);
SeqListPrint(&s1);
SeqListDestory(&s1);
}
int main()
{
//TestSeqList1();//顺序表的尾增删
TestSeqList2();//顺序表的前增删
//为了测试方便前后的增删分开
return 0;
}
三、顺序表的优缺点
3.1缺点
- 空间不够了,需要扩容,扩容是有消耗的。
- 头部或者中间位置插入删除,需要挪动,挪动数据也是有消耗的。
- 避免频繁扩容,一次一般都是按倍数(2倍)去扩的,可能存在一定的空间浪费。
3.2优点
- 支持随机访问,有些算法需要结构支持随机访问。比如:二分查找、、优化的快排等等。