一、顺序表的概念及结构
(一)线性表
线性表(linear list)是n个具有相同特性的数据元素的有限序列。线性表是一种在实际中广泛使用的数据结构,常见的线性表:顺序表、链表、栈、队列、字符串...
线性表在逻辑上是线性结构,也就说是连续的一条直线。但是在物理结构上并不一定是连续的,线性表在物理上存储时,通常以数组和链式结构的形式存储。
案例:蔬菜分为绿叶类、瓜类、菌菇类。线性表指的是具有部分相同特性的一类数据结构的集合。
如何理解逻辑结构和物理结构?
二、顺序表分类
(一)顺序表和数组的区别
顺序表的底层结构是数组,对数组的封装,实现了常用的增删查改等接口。
(二)顺序表分类
1.静态顺序表
概念:使用定长数组储存元素

静态顺序表缺陷:空间给少了不够用,给多了造成空间浪费。
2.动态顺序表

可以按需申请空间,可增容。
三、顺序表的实现
(一)头文件与源文件的创建
1.Seqlish.h
首先,我们要创建一个头文件Seqlist.h。在这个头文件里面,我们主要来实现函数的声明,把所有的头文件和函数集中到同一个头文件中。
2.Seqlist.c
然后,我们需要创建一个源文件Seqlist.h。在这个源文件里面,我们主要来实现顺序表函数的定义。
3.test.c
最后,我们还应该创建一个源文件test.c。在这个源文件里面,我们主要来实现顺序表的测试。
(二)定义顺序表的结构
我们先在Seqlist.h的头文件中:
cpp
#pragma once
#include<stdio.h>
#include<stdlib.h>
#include<assert.h>
typedef int SLDataType;//对整型重命名
//动态顺序表
typedef struct SeqList
{
SLDataType* arr;
SLDataType size;//有效数据的个数
SLDataType capacity;//空间大小
}SL;
(三)顺序表的初始化
在Seqlist.c的源文件中:
cpp
#define _CRT_SECURE_NO_WARNINGS 1
#include"Seqlist.h"
//顺序表的初始化
void SLInit(SL* ps)
{
ps->arr = NULL;
ps->size = ps->capacity = 0;
}
在Seqlist.h的头文件中:
cpp
//顺序表初始化
void SLInit(SL* ps);
在test.c的源文件中:
cpp
#define _CRT_SECURE_NO_WARNINGS 1
#include"Seqlist.h"
void SLTest01()
{
SL sl;
SLInit(&sl);
}
int main()
{
SLTest01();
return 0;
}
(四)顺序表的销毁
在Seqlist.c的源文件中:
cpp
//顺序表的销毁
void SLDestroy(SL* ps)
{
if (ps->arr)
{
free(ps->arr);
}
ps->arr = NULL;
ps->size = ps->capacity = 0;
}
//顺序表的打印
void SLPrint(SL s)
{
for (int i = 0; i < s.size; i++)
{
printf(" %d", s.arr[i]);
}
printf("\n");
}
在Seqlist.h的头文件中:
cpp
void SLPrint(SL ps);//顺序表的打印
void SLDestroy(SL* ps);//顺序表的销毁
在test.c的源文件中:
cpp
void SLTest01()
{
SL sl;
SLInit(&sl);
SLDestroy(&sl);
}
(五)头插的实现
在Seqlist.c的源文件中:
cpp
void SLCheckCapacity(SL* ps)
{
if (ps->capacity == ps->size)
{
//申请空间
//三目表达式
int newCapacity = ps->capacity == 0 ? 4 : ps->capacity * 2;
SLDataType* tmp = (SLDataType*)realloc(ps->arr, newCapacity * sizeof(SLDataType));
if (tmp == NULL)
{
perror("realloc fail!");
exit(1);
}
//空间申请成功
ps->arr = tmp;
ps->capacity = newCapacity;
}
}
void SLPushFront(SL* ps, SLDataType x)
{
assert(ps);
SLCheckCapacity(ps);
for (int i = ps->size; i>0; i--)
{
ps->arr[i] = ps->arr[i - 1];//arr[1]=arr[0];
}
ps->arr[0] = x;
ps->size++;
}
在Seqlist.h的头文件中:
cpp
void SLPushFront(SL* ps, SLDataType x);
在test.c的源文件中:
cpp
void SLTest01()
{
SL sl;
SLInit(&sl);
//测试头插
SLPushFront(&sl, 5);
SLPushFront(&sl, 6);
SLDestroy(&sl);
}
(六)尾插的实现
在Seqlist.c的源文件中:
cpp
void SLCheckCapacity(SL* ps)
{
if (ps->capacity == ps->size)
{
//申请空间
//三目表达式
int newCapacity = ps->capacity == 0 ? 4 : ps->capacity*2;
SLDataType* tmp = (SLDataType*)realloc(ps->arr, newCapacity * sizeof(SLDataType));
if (tmp == NULL)
{
perror("realloc fail!");
exit(1);
}
//空间申请成功
ps->arr = tmp;
ps->capacity = newCapacity;
}
}
//尾插
void SLPushBack(SL* ps, SLDataType x)
{
/*温柔的解决条件*/
//if (ps == NULL)
//{
// return;
assert(ps);//等价于assert(ps != NULL)
//}
//插入数据之前先看空间够不够
SLCheckCapacity(ps);
ps->arr[ps->size++] = x;
/*ps->arr[ps->size] = x;
++ps->size;*/
}
在Seqlist.h的头文件中:
cpp
void SLPushBack(SL* ps, SLDataType x);
在test.c的源文件中:
cpp
void SLTest01()
{
SL sl;
SLInit(&sl);
//增删查改操作
//测试尾插
SLPushBack(&sl, 1);
SLPushBack(&sl, 2);
SLPushBack(&sl, 3);
SLPushBack(&sl,4);
SLDestroy(&sl);
}
(七)尾删的实现
在Seqlist.c的源文件中
cpp
void SLPopBack(SL* ps)
{
assert(ps);
assert(ps->size);
//ps->arr[ps->size-1] = -1;
--ps->size;
}
在Seqlist.h的头文件中:
cpp
void SLPopBack(SL* ps);
在test.c的源文件中:
cpp
void SLTest01()
{
SL sl;
SLInit(&sl);
//测试头删
SLPopBack(&sl);
SLPrint(sl);//1 2 3
SLPopBack(&sl);
SLPrint(sl);//1 2
SLPopBack(&sl);
SLPrint(sl);//1
SLPopBack(&sl);
//SLPopBack(&sl);//size为0,不能继续删除;
SLDestroy(&sl);
}
(八)头删的实现
在Seqlist.c的源文件中
cpp
//头删
void SLPopFront(SL* ps)
{
assert(ps);
assert(ps->size);
//数据整体往前挪动一位
for (int i = 0; i < ps->size-1; i++)
{
ps->arr[i] = ps->arr[i + 1];
//arr[size-2] = arr[size-1]
}
ps->size--;
}
在Seqlist.h的头文件中:
cpp
void SLPopFront(SL* ps);
在test.c的源文件中:
cpp
void SLTest01()
{
SL sl;
SLInit(&sl);
////测试头删
//SLPopFront(&sl);
//SLPrint(sl);//2 3 4
//SLPopFront(&sl);
//SLPrint(sl);//3 4
SLDestroy(&sl);
}
(九)顺序表的整体实现代码
1.Seqlist.c
cpp
#define _CRT_SECURE_NO_WARNINGS 1
#include"Seqlist.h"
//顺序表的初始化
void SLInit(SL* ps)
{
ps->arr = NULL;
ps->size = ps->capacity = 0;
}
//顺序表的销毁
void SLDestroy(SL* ps)
{
if (ps->arr)
{
free(ps->arr);
}
ps->arr = NULL;
ps->size = ps->capacity = 0;
}
void SLCheckCapacity(SL* ps)
{
if (ps->capacity == ps->size)
{
//申请空间
//三目表达式
int newCapacity = ps->capacity == 0 ? 4 : ps->capacity*2;
SLDataType* tmp = (SLDataType*)realloc(ps->arr, newCapacity * sizeof(SLDataType));
if (tmp == NULL)
{
perror("realloc fail!");
exit(1);
}
//空间申请成功
ps->arr = tmp;
ps->capacity = newCapacity;
}
}
//尾插
void SLPushBack(SL* ps, SLDataType x)
{
/*温柔的解决条件*/
//if (ps == NULL)
//{
// return;
assert(ps);//等价于assert(ps != NULL)
//}
//插入数据之前先看空间够不够
SLCheckCapacity(ps);
ps->arr[ps->size++] = x;
/*ps->arr[ps->size] = x;
++ps->size;*/
}
//头插
void SLPushFront(SL* ps, SLDataType x)
{
assert(ps);
SLCheckCapacity(ps);
for (int i = ps->size; i>0; i--)
{
ps->arr[i] = ps->arr[i - 1];//arr[1]=arr[0];
}
ps->arr[0] = x;
ps->size++;
}
//顺序表的打印
void SLPrint(SL s)
{
for (int i = 0; i < s.size; i++)
{
printf(" %d", s.arr[i]);
}
printf("\n");
}
//尾删
void SLPopBack(SL* ps)
{
assert(ps);
assert(ps->size);
//ps->arr[ps->size-1] = -1;
--ps->size;
}
//头删
void SLPopFront(SL* ps)
{
assert(ps);
assert(ps->size);
//数据整体往前挪动一位
for (int i = 0; i < ps->size-1; i++)
{
ps->arr[i] = ps->arr[i + 1];
//arr[size-2] = arr[size-1]
}
ps->size--;
}
2.Seqlist.h
cpp
#pragma once
#include<stdio.h>
#include<stdlib.h>
#include<assert.h>
//定义顺序表的结构
#define N 100
//静态顺序表
//struct SeqList
//{
// int arr[N];
// int size;//有效数据个数
//};
typedef int SLDataType;//对整型重命名
//动态顺序表
typedef struct SeqList
{
SLDataType* arr;
SLDataType size;//有效数据的个数
SLDataType capacity;//空间大小
}SL;
//typedef struct Seqlist SL;
//
//顺序表初始化
void SLInit(SL* ps);
//顺序表的销毁
void SLPrint(SL ps);
void SLDestroy(SL* ps);
//头部插入删除 尾部插入删除
void SLPushBack(SL* ps, SLDataType x);
void SLPushFront(SL* ps, SLDataType x);
void SLPopBack(SL* ps);
void SLPopFront(SL* ps);
3.test.c
cpp
#define _CRT_SECURE_NO_WARNINGS 1
#include"Seqlist.h"
void SLTest01()
{
SL sl;
SLInit(&sl);
//增删查改操作
//测试尾插
SLPushBack(&sl, 1);
SLPushBack(&sl, 2);
SLPushBack(&sl, 3);
SLPushBack(&sl,4);
/*SLPushBack(NULL,5);*/
SLPrint(sl);
//SLPushFront(&sl, 5);
//SLPushFront(&sl, 6);
////测试头删
//SLPopFront(&sl);
//SLPrint(sl);//2 3 4
//SLPopFront(&sl);
//SLPrint(sl);//3 4
//测试尾删
SLPopBack(&sl);
SLPrint(sl);//1 2 3
SLPopBack(&sl);
SLPrint(sl);//1 2
SLPopBack(&sl);
SLPrint(sl);//1
SLPopBack(&sl);
//SLPopBack(&sl);//size为0,不能继续删除;
SLDestroy(&sl);
}
int main()
{
SLTest01();
return 0;
}