顺序表就是数组,但是在数组的基础上,它要求数据是从头开始并且连续存储的,不能间隔存储
静态顺序表
静态顺序表中如果数据满了则不让继续存储,因此我们无法确定该给它多少内存
其头文件:
#pragma once
#define N 1000
typedef int SLDataType
//静态顺序表
typedef struct SeqList
{
SLDataType a[N];
int size;//表示数组中存储了多少个数据
}SL;
//接口函数
void SeqListInit(SL* ps);
void SeqListPushBack(SL* ps,SLDataType x);
void SeqListPopBack(SL* ps);
void SeqListPushFront(SL* ps,SLDataType x);
void SeqListPopFront(SL* ps);
动态顺序表
动态顺序表:
typedef int SLDataType;
//动态顺序表
typedef struct SeqList
{
SLDataType* a;
int size;//表示数组中存储了多少个数据
int capacity;//表示数组时间能存储多少个数据
}SL;
各接口函数实现
顺序表初始化:
void SeqListInit(SL *ps)//顺序表初始化
{
ps->a = NULL;
ps->size = ps->capacity = 0;
}
顺序表销毁:
void SeqListDestory(SL* ps)
{
free(ps->a);
ps->a = 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 SeqListPushBack(SL* ps, SLDataType x)//顺序表尾插
{
SeqListCheckCapacity(ps);
ps->a[ps->size] = x;
ps->size++;
}
顺序表尾插:
void SeqListPopBack(SL* ps)//数据表尾删
{
if(ps->size > 0)
{
ps->size--;
}
}
顺序表头插:
void SeqListPushFront(SL* ps, SLDataType x)//顺序表头插
{
SeqListCheckCapacity(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)
{
assert(ps->size > 0);//存储数据不能为零,否则会终止
int begin = 1;
while(begin < ps->size)//数据向前挪动
{
ps->a[begin-1] = ps->a[begin];
begin++;
}
ps->size--;
}
使用assert方法时需导入assert库
顺序表中查找数据位置(找到了返回数据位置下标,没有找到则返回-1):
int SeqListFind(SL* ps,SLDataType x)
{
for(int i = 0;i < ps->size;i++)
{
if(ps->a[i] == x)
{
return i;
}
}
return -1;
}
顺序表指定位置插入:
void SeqListInsert(SL* ps,int pos,SLDataType x)
{
if(pos > ps->size || pos < 0)
{
printf("pos invalid \n")
return ;
}
//assert(pos <= ps->size && pos => 0)//暴力方法不得输入非法pos
SeqListCheckCapcaity(ps);
int end = ps->size-1;
while(end >= pos)
{
ps->a[end+1] = ps->a[end];
end--;
}
ps->a[pos] = x;
ps->size++;
}
顺序表指定位置删除:
void SeqListErase(SL* ps,int pos)
{
if(pos > ps->size || pos < 0)
{
printf("pos invalid \n")
return ;
}
int begin = pos + 1;
while(begin < ps->size)
{
ps->a[begin-1] = ps->a[begin];
begin++;
}
ps->size--;
}
通过顺序表的指定位置删除我们可以改善顺序表的头删
动态顺序表(完整版)
头文件:
#pragma once
#include <stdio.h>
#include <stdlib.h>
#include <assert.h>
typedef int SLDataType;
//动态顺序表
typedef struct SeqList
{
SLDataType* a;
int size;//表示数组中存储了多少个数据
int capacity;//表示数组时间能存储多少个数据
}SL;
//接口函数
void SeqListInit(SL* ps);
void SeqListDestory(SL* ps);
void SeqListPrint(SL* ps);
void SeqListPushBack(SL* ps, SLDataType x);
void SeqListPopBack(SL* ps);
void SeqListPushFront(SL* ps, SLDataType x);
void SeqListPopFront(SL* ps);
void SeqListCheckCapcaity(SL* ps);
int SeqListFind(SL* ps,SLDataType x);
void SeqListInsert(SL* ps,int pos,SLDataType x);
void SeqListErase(SL* ps,int pos);
接口函数以及结构体的.c文件:
#include "SeqList.h"
void SeqListInit(SL* ps)//顺序表初始化
{
ps->a = NULL;
ps->size = ps->capacity = 0;
}
void SeqListDestory(SL* ps)
{
free(ps->a);
ps->a = NULL;
ps->capacity = ps->size = 0;
}
void SeqListPrint(SL* ps)//顺序表销毁
{
for(int i = 0; i < ps->size; i++)
{
printf("%d ", ps->a[i]);
}
printf("\n");
}
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 SeqListPushBack(SL* ps, SLDataType x)//顺序表尾插
{
SeqListCheckCapacity(ps);
ps->a[ps->size] = x;
ps->size++;
}
void SeqListPopBack(SL* ps)//数据表尾删
{
if(ps->size > 0)
{
ps->size--;
}
}
void SeqListPushFront(SL* ps, SLDataType x)//顺序表头插
{
SeqListCheckCapacity(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)
{
assert(ps->size > 0);//存储数据不能为零,否则会终止
int begin = 1;
while(begin < ps->size)//数据向前挪动
{
ps->a[begin-1] = ps->a[begin];
begin++;
}
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 SeqListInsert(SL* ps,int pos,SLDataType x)
{
if(pos > ps->size || pos < 0)
{
printf("pos invalid \n");
return ;
}
//assert(pos <= ps->size && pos => 0)//暴力方法不得输入非法pos
SeqListCheckCapacity(ps);
int end = ps->size-1;
while(end >= pos)
{
ps->a[end+1] = ps->a[end];
end--;
}
ps->a[pos] = x;
ps->size++;
}
void SeqListErase(SL* ps,int pos)
{
if(pos > ps->size || pos < 0)
{
printf("pos invalid \n");
return ;
}
int begin = pos + 1;
while(begin < ps->size)
{
ps->a[begin-1] = ps->a[begin];
begin++;
}
ps->size--;
}
测试顺序表的.c文件:
#include "SeqList.h"
void TestSeqList1() {
SL s1;
SeqListInit(&s1);
SeqListPushBack(&s1, 1);
SeqListPushBack(&s1, 2);
SeqListPushBack(&s1, 3);
SeqListPopBack(&s1);
SeqListPopBack(&s1);
SeqListPrint(&s1);
SeqListDestory(&s1);
}
void TestSeqList2()
{
SL s1;
SeqListInit(&s1);
SeqListPushBack(&s1,1);
SeqListPushBack(&s1,2);
SeqListPushBack(&s1,3);
SeqListPushBack(&s1,4);
SeqListPushBack(&s1,5);
SeqListPushFront(&s1,10);
SeqListPushFront(&s1,20);
SeqListPushFront(&s1,30);
SeqListPushFront(&s1,40);
SeqListPushFront(&s1,50);
SeqListPushFront(&s1,60);
SeqListPushFront(&s1,70);
SeqListPopFront(&s1);
SeqListPopFront(&s1);
SeqListPopFront(&s1);
SeqListPopFront(&s1);
SeqListPrint(&s1);
SeqListDestory(&s1);
}
void TestSeqList3()
{
SL s1;
SeqListInit(&s1);
SeqListPushBack(&s1,1);
SeqListPushBack(&s1,2);
SeqListPushBack(&s1,3);
SeqListPushBack(&s1,4);
SeqListPushBack(&s1,5);
SeqListInsert(&s1,1,10);
SeqListInsert(&s1,2,200);
SeqListErase(&s1,5);
SeqListErase(&s1,2);
SeqListPrint(&s1);
int pos = SeqListFind(&s1,5);
printf("%d",pos);
SeqListDestory(&s1);
}
int main() {
TestSeqList1();
TestSeqList2();
TestSeqList3();
return 0;
}
顺序表缺点:
- 空间不够时需要扩容,而扩容需要付出代价。扩容时当内存后面有足够空间时会原地扩容,没有足够空间时会重新找一块内存申请空间
- 为了避免频繁扩容,当内存空间满了时,基本都是扩容两倍,这就可能导致内存一定空间的浪费
- 顺序表要求从头开始连续存储数据,因此我们在头部或中间插入删除数据时就需要挪动数据,效率不高
顺序表优点:
- 存储密度大
- 可随机存取某一元素