1.顺序表的概念及其结构
顺序表是用一段物理地址连续的存储单元依次存储数据元素的线性结构,一般情况下采用数组存储。在数组上完成数据的增删查改。
顺序表一般可以分为:
1. 静态顺序表:使用定长数组存储。
#define N 100
typedef int SLDataType;
typedef struct SeqList
{
SLDataType array[N]; // 定长数组
size_t size; // 有效数据的个数
}SeqList;
2. 动态顺序表:使用动态开辟的数组存储。
typedef struct SeqList
{
SLDataType* array; // 指向动态开辟的数组
size_t size ; // 有效数据个数
size_t capicity ; // 容量空间的大小
}SeqList;
我们将实现动态顺序表
当数据存满的时候可以再开辟空间 不会有存满的情况
2.准备工作
VS2022下首先创建三个项目
SeqList.h:
进行相关函数的声明和头文件的引用
SeqList.c:
进行相关函数的实现
test.c:
进行相关函数功能的测试
我们要实现增删查改的功能
初始化 打印 销毁 检查扩容
尾部插入 尾部删除 头部插入 头部删除 找数据
指定下标插入 指定下标删除
首先要先定义一个结构体
这个结构体内部需要
1°放相关数据
正常存数据
2°数组存了多少个有效数据
存了多少个 看是否满了 满了就再开辟空间
3°数组实际能存数据的空间容量
与2°进行比较 实现开辟空间的功能
这个结构体需要写入SeqList.h
SeqList.c和test.c引入#include "Seqlist.h"即可用相关头文件和结构体
#pragma once
#include<stdio.h>
#include<stdlib.h>
#include<assert.h>
typedef int SLDateType;
typedef struct SeqList
{
SLDateType* a;
int size;//表示数组中存储了多少个有效数据
int capacity; //数组实际能存数据的空间容量
}SL;
将结构体简写成SL 方便后续定义结构体的相关指针
3.初始化
初始化应该把a置空
同时存储的数据和容量都为0
SeqList.h进行函数声明
//初始化
void SeqListInit(SL* ps);
SeqList.c实现函数功能
//初始化
void SeqListInit(SL* ps)
{
ps->a = NULL;
ps->size = ps->capacity = 0;
}
4.打印
我们要将这个顺序表中的数据都打印出来
SeqList.h进行函数声明
//打印
void SeqListPrint(SL* ps);
可以通过结构体的指针访问size 也就可以得到存储的数据个数
再通过下标访问打印即可
SeqList.c实现函数功能
//打印
void SeqListPrint(SL* ps)
{
for (int i = 0; i < ps->size; ++i)
{
printf("%d ", ps->a[i]);
}
printf("\n");
}
5.扩容
当数据存储满了的时候
我们需要再开辟空间来存储数据
需要检查是否需要扩容
SeqList.h进行函数声明
//检查扩容
void SeqListCheckCapacity(SL* ps);
SeqList.c实现函数功能
//检查是否需要扩容
void SeqListCheckCapacity(SL* ps)
{
//如果没有空间或者空间不足就扩容
if (ps->size == ps->capacity)
{
int newcapacity = ps->capacity == 0 ? 4 : ps->capacity * 2;
SLDateType* tmp = (SLDateType*)realloc(ps->a, newcapacity*sizeof(SLDateType));
if (tmp == NULL)
{
printf("realloc fail\n");
exit(-1);
}
ps->a = tmp;
ps->capacity = newcapacity;
}
}
当size和capacity相等的时候
说明数据存储满了
这个时候需要扩容
先用newcapacity存起来
因为有两种情况
a. capacity是初始化之后为0 那么就给4个容量
b. capacity如果不等于0 说明是存储数据后满了 就扩容2倍
int newcapacity = ps->capacity == 0 ? 4 : ps->capacity * 2;
接下来用realloc函数进行开辟
这篇博客中介绍了realloc函数
这里展示出来
*ptr即为结构体内部中的a
size即为新的容量(个数)*sizeof(SLDateType)
注意这里的size指的是字节数 所以要用个数*每个数据的大小
用一个临时变量存起来 因为还要根据返回值来写后续代码
SLDateType* tmp = (SLDateType*)realloc(ps->a, newcapacity*sizeof(SLDateType));
如果返回值为空指针 那么说明开辟失败 直接结束程序
加一个判断条件就可以
if (tmp == NULL)
{
printf("realloc fail\n");
exit(-1);
}
如果没有返回空指针 那么说明开辟成功
把开辟的空间给到a
再把新容量给到原来的容量
ps->a = tmp;
ps->capacity = newcapacity;
6.尾部插入
需要有对应的下标 再通过ps->a[下标]=x进行实现
SeqList.h进行函数声明
//尾部插入
void SeqListPushBack(SL* ps, SLDateType x);
SeqList.c实现函数功能
void SeqListPushBack(SL* ps, SLDateType x)
{
SeqListCheckCapacity(ps);
ps->a[ps->size] = x;
ps->size++;
}
下标可以通过size得知 size就是下标 从0开始 每插入一次 下标自加往后走
ps->a[ps->size] = x;
ps->size++;
但是要注意 可能插着插着就满了 所以也需要检查扩容 用检查扩容的函数就可以
SeqListCheckCapacity(ps);
我们已经实现了一些相关函数 可以测试一下功能
test.c测试功能
#include "SeqList.h"
void TestSeqList1()
{
//定义一个结构体
SL s1;
//传址初始化结构体
SeqListInit(&s1);
//1 2 3 4 5尾插
SeqListPushBack(&s1, 1);
SeqListPushBack(&s1, 2);
SeqListPushBack(&s1, 3);
SeqListPushBack(&s1, 4);
SeqListPushBack(&s1, 5);
//打印 1 2 3 4 5
SeqListPrint(&s1);
}
int main()
{
TestSeqList1();
return 0;
}
运行结果
这里打印出来了1 2 3 4 5 说明初始化 打印 扩容 尾部函数的实现成功了
结构体传地址初始化要好于传值初始化
如果结构体比较大并且成员很多的话,会大大地浪费空间和时间,而传地址恰好能够完美的解决这点,因此当遇到函数传参数问题时,优先选择传地址。
尾部插入和打印函数参数中都是指针 所以传地址
7.头部插入
尾部插入已经实现 接下来试着实现一下头部插入
头部插入该如何实现?
我们只需要把数据全部往后挪一格
再把想要插入的数据放到最前面的可以了
比如说我想头部插入一个10
那么代码如何实现呢?
我们知道下标 通过遍历就可以把数据往后挪
SeqList.h进行函数声明
//头部插入
void SeqListPushFront(SL* ps, SLDateType x);
SeqList.c实现函数功能
//头部插入
void SeqListPushFront(SL* ps, SLDateType 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++;
}
和尾部插入一样 需要检查扩容
//检查需不需要扩容
SeqListCheckCapacity(ps);
当有n的数据需要挪动
循环n次
后一个数据被前一个数据覆盖
//挪动数据
int end = ps->size - 1;
while (end >= 0)
{
ps->a[end + 1] = ps->a[end];
--end;
}
最后将x给到ps->a[0]
不要忘记size++ 记录存储数据的个数
ps->a[0] = x;
ps->size++;
test.c测试功能
#include "SeqList.h"
void TestSeqList2()
{
//定义一个结构体
SL s1;
//传址初始化结构体
SeqListInit(&s1);
//1 2 3 4 5头插
SeqListPushFront(&s1, 1);
SeqListPushFront(&s1, 2);
SeqListPushFront(&s1, 3);
SeqListPushFront(&s1, 4);
SeqListPushFront(&s1, 5);
//打印 5 4 3 2 1
SeqListPrint(&s1);
}
int main()
{
TestSeqList2();
return 0;
}
运行结果
8.尾部删除
只需要把size--就可以了
SeqList.h进行函数声明
void SeqListPopBack(SL* ps);
SeqList.c实现函数功能
void SeqListPopBack(SL* ps)
{
assert(ps->size > 0);
ps->size--;
}
assert断言一下 防止顺序表删空了再删 再删的话报错
test.c测试功能
#include "SeqList.h"
void TestSeqList3()
{
//定义一个结构体
SL s1;
//传址初始化结构体
SeqListInit(&s1);
//1 2 3 4 5尾插
SeqListPushBack(&s1, 1);
SeqListPushBack(&s1, 2);
SeqListPushBack(&s1, 3);
SeqListPushBack(&s1, 4);
SeqListPushBack(&s1, 5);
//尾部删除2次
SeqListPopBack(&s1);
SeqListPopBack(&s1);
//打印 1 2 3
SeqListPrint(&s1);
//尾部再删除4次 会assert报错
SeqListPopBack(&s1);
SeqListPopBack(&s1);
SeqListPopBack(&s1);
SeqListPopBack(&s1);
}
int main()
{
TestSeqList3();
return 0;
}
运行结果
9.头部删除
相当于把后面的数往前挪一格 再size--就可以了
SeqList.h进行函数声明
void SeqListPopFront(SL* ps);
SeqList.c实现函数功能
//头部删除
void SeqListPopFront(SL* ps)
{
//往前挪再size--
assert(ps->size > 0);
int begin = 1;
while (begin < ps->size)
{
ps->a[begin - 1] = ps->a[begin];
++begin;
}
ps->size--;
}
assert断言 当顺序表为空的时候就不能再删了
assert(ps->size > 0);
用begin-1和begin begin从1开始往后走
不用begin和begin+1是因为判断条件如果没写好 最后会导致数组越界
所以说为了避免 使用begin-1和begin就不会有这种情况
最后不要忘记size--
int begin = 1;
while (begin < ps->size)
{
ps->a[begin - 1] = ps->a[begin];
++begin;
}
ps->size--;
test.c测试功能
#include "SeqList.h"
void TestSeqList4()
{
//定义一个结构体
SL s1;
//传址初始化结构体
SeqListInit(&s1);
//1 2 3 4 5尾插
SeqListPushBack(&s1, 1);
SeqListPushBack(&s1, 2);
SeqListPushBack(&s1, 3);
SeqListPushBack(&s1, 4);
SeqListPushBack(&s1, 5);
//头部删除2次
SeqListPopFront(&s1);
SeqListPopFront(&s1);
//打印 3 4 5
SeqListPrint(&s1);
//头部再删除4次 assert报错
SeqListPopFront(&s1);
SeqListPopFront(&s1);
SeqListPopFront(&s1);
SeqListPopFront(&s1);
}
int main()
{
TestSeqList4();
return 0;
}
运行结果
10.查找/修改
跟打印实现差不多
遍历一遍加判断条件
SeqList.h声明函数
//找到了返回x位置下标 没有找到返回-1
int SeqListFind(SL* ps, SLDateType x);
SeqList.c实现函数
//查找 返回下标
int SeqListFind(SL* ps, SLDateType x)
{
for (int i = 0; i < ps->size; i++)
{
if (ps->a[i] == x)
{
return i;
}
}
return -1;
}
test.c测试功能
#include "SeqList.h"
void TestSeqList5()
{
//定义一个结构体
SL s1;
//传址初始化结构体
SeqListInit(&s1);
//1 2 3 4 5尾插
SeqListPushBack(&s1, 1);
SeqListPushBack(&s1, 2);
SeqListPushBack(&s1, 3);
SeqListPushBack(&s1, 4);
SeqListPushBack(&s1, 5);
//查找3
int pos = SeqListFind(&s1, 3);
if (pos != -1)
printf("该数据的下标为%d\n", pos);
else
printf("没有该数据\n");
//查找6
pos = SeqListFind(&s1, 6);
if (pos != -1)
printf("该数据的下标为%d\n", pos);
else
printf("没有该数据\n");
//找到3并改成30
pos = SeqListFind(&s1, 3);
if (pos != -1)
{
//定义一个结构体指针
SL* Find = &s1;
//访问
Find->a[pos] = 30;
}
else
printf("没有该数据");
//打印1 2 30 4 5
SeqListPrint(&s1);
}
int main()
{
TestSeqList5();
return 0;
}
返回值用pos接收
pos=-1说明数据不存在
pos!=-1 此时的pos就是下标 打印pos即可
如果需要修改的话 通过pos改就可以了
如果有两个相同的数 会优先返回下标小的那一个
运行结果
3找到了 返回下标2
6没有找到
3找到了 改成30
11.指定pos下标位置插入
实现了头插和尾插 能不能在某个位置插入
只要用找数据的函数先找到下标 再把数据往后挪一个就可以了
a.比如说我想在3的前面插入30
先找到3的下标 再3以后的数据全部往后挪
b.或者是你自己指定一个下标
在那个下标位置插入数据
SeqList.h声明函数
//指定pos下标位置插入
void SeqListInsert(SL* ps,int pos, SLDateType x);
SeqList.c实现函数
//指定pos下标位置插入
void SeqListInsert(SL* ps, int pos, SLDateType x)
{
assert(ps->size > 0);
assert(pos >= 0 && pos <= ps->size);
//考虑扩容
SeqListCheckCapacity(ps);
int end = ps->size - 1;
while (end >= pos)
{
ps->a[end + 1] = ps->a[end];
--end;
}
ps->a[pos] = x;
ps->size++;
}
首先pos必须在0-size之间 assert断言 不可能越界
而且顺序表为空肯定不能删
assert(pos >= 0 && pos <= ps->size);
插入 要考虑扩容
SeqListCheckCapacity(ps);
从后面往后挪 然后往前走
如果你从前面往后走的话 会把后面的数据覆盖
所以必须从最后面开始挪
int end = ps->size - 1;
while (end >= pos)
{
ps->a[end + 1] = ps->a[end];
--end;
}
最后把数据放到pos下标处
别忘记了size++
ps->a[pos] = x;
ps->size++;
如果实现某个位置插入的话
头插和尾插可以简化了
头插
//头部插入
void SeqListPushFront(SL* ps, SLDateType x)
{
SeqListInsert(ps, 0, x);
}
下标为0插入x
尾插
void SeqListPushBack(SL* ps, SLDateType x)
{
SeqListInsert(ps, ps->size, x);
}
size就是最后一个数据的下标 size处插入x
test.c功能测试
先测试头插尾插简化后的功能
#include "SeqList.h"
TestSeqList6()
{
//定义一个结构体
SL s1;
//传址初始化结构体
SeqListInit(&s1);
//尾插1 2 3
SeqListPushBack(&s1, 1);
SeqListPushBack(&s1, 2);
SeqListPushBack(&s1, 3);
//打印1 2 3
SeqListPrint(&s1);
//头插1 2 3
SeqListPushFront(&s1, 1);
SeqListPushFront(&s1, 2);
SeqListPushFront(&s1, 3);
//打印3 2 1 1 2 3
SeqListPrint(&s1);
}
int main()
{
TestSeqList6();
return 0;
}
运行结果
再测试插入pos下标位置的功能
#include "SeqList.h"
TestSeqList7()
{
//定义一个结构体
SL s1;
//传址初始化结构体
SeqListInit(&s1);
//1 2 3 4 5尾插
SeqListPushBack(&s1, 1);
SeqListPushBack(&s1, 2);
SeqListPushBack(&s1, 3);
SeqListPushBack(&s1, 4);
SeqListPushBack(&s1, 5);
//在下标为2的位置插入20
//也就是3的前面插入20
SeqListInsert(&s1, 2, 20);
//打印1 2 20 3 4 5
SeqListPrint(&s1);
//如果越界
SeqListInsert(&s1, 7, 20);
//打印
SeqListPrint(&s1);
}
int main()
{
TestSeqList7();
return 0;
}
运行结果
越界会assert报错
不越界正常插入
最后测试在某个数据前插入新的数据的功能
#include "SeqList.h"
TestSeqList8()
{
//定义一个结构体
SL s1;
//传址初始化结构体
SeqListInit(&s1);
//1 2 3 4 5尾插
SeqListPushBack(&s1, 1);
SeqListPushBack(&s1, 2);
SeqListPushBack(&s1, 3);
SeqListPushBack(&s1, 4);
SeqListPushBack(&s1, 5);
//在4的前面插入40
//先用pos接收4的下标
int pos = SeqListFind(&s1, 4);
if (pos != -1)
SeqListInsert(&s1, pos, 40);
else
printf("无此数据 插入失败\n");
//打印1 2 3 40 4 5
SeqListPrint(&s1);
//在7的前面插入70
//顺序表中没有7
pos = SeqListFind(&s1, 7);
if (pos != -1)
SeqListInsert(&s1, pos, 70);
else
printf("无此数据 插入失败\n");
//打印1 2 3 40 4 5
SeqListPrint(&s1);
}
int main()
{
TestSeqList8();
return 0;
}
运行结果
12.删除pos下标位置的数据
找到对应的下标
把后面的数据全部往前挪一格就可以实现
a.你可以指定一个下标删除
b.或者通过查找函数找到一个数据得到这个数据的下标 最后删除这个数据
SeqList.h声明函数
//删除pos位置的数据
void SeqListErase(SL* ps, int pos);
SeqList.c实现函数
//删除pos位置的数据
void SeqListErase(SL* ps, int pos)
{
assert(pos >= 0 && pos <= ps->size);
int begin = pos + 1;
while (begin < ps->size)
{
ps->a[begin - 1] = ps->a[begin];
++begin;
}
ps->size--;
}
assert断言 防止越界
assert(pos >= 0 && pos <= ps->size);
从pos后一个开始往前挪一格 然后往后走
如果从最后开始挪 会覆盖前面的数据
int begin = pos + 1;
while (begin < ps->size)
{
ps->a[begin - 1] = ps->a[begin];
++begin;
}
最后不要忘记了size--
ps->size--;
这样实现了某个位置删除
头删可以简化
尾删只有size-- 已经最简化了 所以不需要调用这个函数
test.c测试功能
先测试头删功能
#include "SeqList.h"
TestSeqList9()
{
//定义一个结构体
SL s1;
//传址初始化结构体
SeqListInit(&s1);
//1 2 3 4 5尾插
SeqListPushBack(&s1, 1);
SeqListPushBack(&s1, 2);
SeqListPushBack(&s1, 3);
SeqListPushBack(&s1, 4);
SeqListPushBack(&s1, 5);
//头删2次
SeqListPopFront(&s1);
SeqListPopFront(&s1);
//打印3 4 5
SeqListPrint(&s1);
//再头删4次
SeqListPopFront(&s1);
SeqListPopFront(&s1);
SeqListPopFront(&s1);
SeqListPopFront(&s1);
}
int main()
{
TestSeqList9();
return 0;
}
运行结果
再测试pos下标位置的删除
#include "SeqList.h"
TestSeqList10()
{
//定义一个结构体
SL s1;
//传址初始化结构体
SeqListInit(&s1);
//1 2 3 4 5尾插
SeqListPushBack(&s1, 1);
SeqListPushBack(&s1, 2);
SeqListPushBack(&s1, 3);
SeqListPushBack(&s1, 4);
SeqListPushBack(&s1, 5);
//删除下标为2的数据
//也就是删除3
SeqListErase(&s1, 2);
//打印1 2 4 5
SeqListPrint(&s1);
//删除下标为7的数据
//越界
SeqListErase(&s1, 7);
}
int main()
{
TestSeqList10();
return 0;
}
运行结果
越界assert报错
不越界正常删除
最后测试删除某个数据的功能
#include "SeqList.h"
TestSeqList11()
{
//定义一个结构体
SL s1;
//传址初始化结构体
SeqListInit(&s1);
//1 2 3 4 5尾插
SeqListPushBack(&s1, 1);
SeqListPushBack(&s1, 2);
SeqListPushBack(&s1, 3);
SeqListPushBack(&s1, 4);
SeqListPushBack(&s1, 5);
//删除4
int pos = SeqListFind(&s1, 4);
if (pos != -1)
SeqListErase(&s1, pos);
else
printf("无此数据 删除失败\n");
//打印1 2 3 5
SeqListPrint(&s1);
//删除7
pos = SeqListFind(&s1, 7);
if (pos != -1)
SeqListErase(&s1, pos);
else
printf("无此数据 删除失败\n");
//打印1 2 3 5
SeqListPrint(&s1);
}
int main()
{
TestSeqList11();
return 0;
}
运行结果
13.销毁
free(ps->a)
再初始化
size和capacity就可以
SeqList.h声明函数
//销毁
void SeqListDestory(SL* ps);
SeqList.c实现函数
//销毁
void SeqListDestroy(SL* ps)
{
free(ps->a);
ps->a = NULL;
ps->capacity = ps->size = 0;
}
test.c测试功能
#include "SeqList.h"
TestSeqList12()
{
//定义一个结构体
SL s1;
//传址初始化结构体
SeqListInit(&s1);
//1 2 3 4 5尾插
SeqListPushBack(&s1, 1);
SeqListPushBack(&s1, 2);
SeqListPushBack(&s1, 3);
SeqListPushBack(&s1, 4);
SeqListPushBack(&s1, 5);
//打印1 2 3 4 5
SeqListPrint(&s1);
//销毁
SeqListDestroy(&s1);
//只打印\n
SeqListPrint(&s1);
}
int main()
{
TestSeqList12();
return 0;
}
运行结果
14.完整代码
SeqList.h
#pragma once
#include<stdio.h>
#include<stdlib.h>
#include<assert.h>
typedef int SLDateType;
//静态顺序表
typedef struct SeqList
{
SLDateType* a;
int size;//表示数组中存储了多少个有效数据
int capacity; //数组实际能存数据的空间容量
}SL;
//接口函数--命名风格是跟着STL走的
//初始化
void SeqListInit(SL* ps);
//打印
void SeqListPrint(SL* ps);
//静态特点:如果满了就不让插入 缺点:给多少的合适呢?这个很难确定
//N给小了不够 N给大了浪费
//销毁
void SeqListDestroy(SL* ps);
//尾部插入
void SeqListPushBack(SL* ps, SLDateType x);
//尾部删除
void SeqListPopBack(SL* ps);
//头部插入
void SeqListPushFront(SL* ps, SLDateType x);
//头部删除
void SeqListPopFront(SL* ps);
//检查扩容
void SeqListCheckCapacity(SL* ps);
//找到了返回x位置下标 没有找到返回-1
int SeqListFind(SL* ps, SLDateType x);
//指定pos下标位置插入
void SeqListInsert(SL* ps,int pos, SLDateType x);
//删除pos位置的数据
void SeqListErase(SL* ps, int pos);
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 SeqListInit(SL* ps)
{
ps->a = NULL;
ps->size = ps->capacity = 0;
}
//销毁
void SeqListDestroy(SL* ps)
{
free(ps->a);
ps->a = NULL;
ps->capacity = ps->size = 0;
printf("销毁成功\n");
}
//检查是否需要扩容
void SeqListCheckCapacity(SL* ps)
{
//如果没有空间或者空间不足就扩容
if (ps->size == ps->capacity)
{
int newcapacity = ps->capacity == 0 ? 4 : ps->capacity * 2;
SLDateType* tmp = (SLDateType*)realloc(ps->a, newcapacity*sizeof(SLDateType));
if (tmp == NULL)
{
printf("realloc fail\n");
exit(-1);
}
ps->a = tmp;
ps->capacity = newcapacity;
}
}
//尾部插入
void SeqListPushBack(SL* ps, SLDateType x)
{
//SeqListCheckCapacity(ps);
//ps->a[ps->size] = x;
//ps->size++;
//尾插可以简化成
SeqListInsert(ps, ps->size, x);
}
//尾部删除
void SeqListPopBack(SL* ps)
{
assert(ps->size > 0);
ps->size--;
}
//头部插入
void SeqListPushFront(SL* ps, SLDateType 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++;
//头插可以简化成
SeqListInsert(ps, 0, x);
}
//头部删除
void SeqListPopFront(SL* ps)
{
往前挪再size--
//assert(ps->size > 0);
//int begin = 1;
//while (begin < ps->size)
//{
// ps->a[begin - 1] = ps->a[begin];
// ++begin;
//}
//ps->size--;
SeqListErase(ps, 0);
}
//查找 返回下标
int SeqListFind(SL* ps, SLDateType x)
{
for (int i = 0; i < ps->size; i++)
{
if (ps->a[i] == x)
{
return i;
}
}
return -1;
}
//指定pos下标位置插入
void SeqListInsert(SL* ps, int pos, SLDateType x)
{
assert(pos >= 0 && pos <= ps->size);
//考虑扩容
SeqListCheckCapacity(ps);
int end = ps->size - 1;
while (end >= pos)
{
ps->a[end + 1] = ps->a[end];
--end;
}
ps->a[pos] = x;
ps->size++;
}
//删除pos位置的数据
void SeqListErase(SL* ps, int pos)
{
assert(ps->size > 0);
assert(pos >= 0 && pos <= ps->size);
int begin = pos + 1;
while (begin < ps->size)
{
ps->a[begin - 1] = ps->a[begin];
++begin;
}
ps->size--;
}
test.c
1°无菜单 测试用
#include "SeqList.h"
void TestSeqList1()
{
//定义一个结构体
SL s1;
//传址初始化结构体
SeqListInit(&s1);
//1 2 3 4 5尾插
SeqListPushBack(&s1, 1);
SeqListPushBack(&s1, 2);
SeqListPushBack(&s1, 3);
SeqListPushBack(&s1, 4);
SeqListPushBack(&s1, 5);
//打印 1 2 3 4 5
SeqListPrint(&s1);
}
void TestSeqList2()
{
//定义一个结构体
SL s1;
//传址初始化结构体
SeqListInit(&s1);
//1 2 3 4 5头插
SeqListPushFront(&s1, 1);
SeqListPushFront(&s1, 2);
SeqListPushFront(&s1, 3);
SeqListPushFront(&s1, 4);
SeqListPushFront(&s1, 5);
//打印 5 4 3 2 1
SeqListPrint(&s1);
}
void TestSeqList3()
{
//定义一个结构体
SL s1;
//传址初始化结构体
SeqListInit(&s1);
//1 2 3 4 5尾插
SeqListPushBack(&s1, 1);
SeqListPushBack(&s1, 2);
SeqListPushBack(&s1, 3);
SeqListPushBack(&s1, 4);
SeqListPushBack(&s1, 5);
//尾部删除2次
SeqListPopBack(&s1);
SeqListPopBack(&s1);
//打印 1 2 3
SeqListPrint(&s1);
//尾部再删除4次 会assert报错
SeqListPopBack(&s1);
SeqListPopBack(&s1);
SeqListPopBack(&s1);
SeqListPopBack(&s1);
}
void TestSeqList4()
{
//定义一个结构体
SL s1;
//传址初始化结构体
SeqListInit(&s1);
//1 2 3 4 5尾插
SeqListPushBack(&s1, 1);
SeqListPushBack(&s1, 2);
SeqListPushBack(&s1, 3);
SeqListPushBack(&s1, 4);
SeqListPushBack(&s1, 5);
//头部删除2次
SeqListPopFront(&s1);
SeqListPopFront(&s1);
//打印3 4 5
SeqListPrint(&s1);
//头部再删除4次 assert报错
SeqListPopFront(&s1);
SeqListPopFront(&s1);
SeqListPopFront(&s1);
SeqListPopFront(&s1);
}
void TestSeqList5()
{
//定义一个结构体
SL s1;
//传址初始化结构体
SeqListInit(&s1);
//1 2 3 4 5尾插
SeqListPushBack(&s1, 1);
SeqListPushBack(&s1, 2);
SeqListPushBack(&s1, 3);
SeqListPushBack(&s1, 4);
SeqListPushBack(&s1, 5);
//查找3
int pos = SeqListFind(&s1, 3);
if (pos != -1)
printf("该数据的下标为%d\n", pos);
else
printf("没有该数据\n");
//查找6
pos = SeqListFind(&s1, 6);
if (pos != -1)
printf("该数据的下标为%d\n", pos);
else
printf("没有该数据\n");
//找到3并改成30
pos = SeqListFind(&s1, 3);
if (pos != -1)
{
//定义一个结构体指针
SL* Find = &s1;
//访问
Find->a[pos] = 30;
}
else
printf("没有该数据");
//打印1 2 30 4 5
SeqListPrint(&s1);
}
TestSeqList6()
{
//定义一个结构体
SL s1;
//传址初始化结构体
SeqListInit(&s1);
//尾插1 2 3
SeqListPushBack(&s1, 1);
SeqListPushBack(&s1, 2);
SeqListPushBack(&s1, 3);
//打印1 2 3
SeqListPrint(&s1);
//头插1 2 3
SeqListPushFront(&s1, 1);
SeqListPushFront(&s1, 2);
SeqListPushFront(&s1, 3);
//打印3 2 1 1 2 3
SeqListPrint(&s1);
}
TestSeqList7()
{
//定义一个结构体
SL s1;
//传址初始化结构体
SeqListInit(&s1);
//1 2 3 4 5尾插
SeqListPushBack(&s1, 1);
SeqListPushBack(&s1, 2);
SeqListPushBack(&s1, 3);
SeqListPushBack(&s1, 4);
SeqListPushBack(&s1, 5);
//在下标为2的位置插入20
//也就是3的前面插入20
SeqListInsert(&s1, 2, 20);
//打印1 2 20 3 4 5
SeqListPrint(&s1);
//如果越界
SeqListInsert(&s1, 7, 20);
//打印
SeqListPrint(&s1);
}
TestSeqList8()
{
//定义一个结构体
SL s1;
//传址初始化结构体
SeqListInit(&s1);
//1 2 3 4 5尾插
SeqListPushBack(&s1, 1);
SeqListPushBack(&s1, 2);
SeqListPushBack(&s1, 3);
SeqListPushBack(&s1, 4);
SeqListPushBack(&s1, 5);
//在4的前面插入40
//先用pos接收4的下标
int pos = SeqListFind(&s1, 4);
if (pos != -1)
SeqListInsert(&s1, pos, 40);
else
printf("无此数据");
//打印1 2 3 40 4 5
SeqListPrint(&s1);
//在7的前面插入70
//顺序表中没有7
pos = SeqListFind(&s1, 7);
if (pos != -1)
SeqListInsert(&s1, pos, 70);
else
printf("无此数据 插入失败\n");
//打印1 2 3 40 4 5
SeqListPrint(&s1);
}
TestSeqList9()
{
//定义一个结构体
SL s1;
//传址初始化结构体
SeqListInit(&s1);
//1 2 3 4 5尾插
SeqListPushBack(&s1, 1);
SeqListPushBack(&s1, 2);
SeqListPushBack(&s1, 3);
SeqListPushBack(&s1, 4);
SeqListPushBack(&s1, 5);
//头删2次
SeqListPopFront(&s1);
SeqListPopFront(&s1);
//打印3 4 5
SeqListPrint(&s1);
//再头删4次
SeqListPopFront(&s1);
SeqListPopFront(&s1);
SeqListPopFront(&s1);
SeqListPopFront(&s1);
}
TestSeqList10()
{
//定义一个结构体
SL s1;
//传址初始化结构体
SeqListInit(&s1);
//1 2 3 4 5尾插
SeqListPushBack(&s1, 1);
SeqListPushBack(&s1, 2);
SeqListPushBack(&s1, 3);
SeqListPushBack(&s1, 4);
SeqListPushBack(&s1, 5);
//删除下标为2的数据
//也就是删除3
SeqListErase(&s1, 2);
//打印1 2 4 5
SeqListPrint(&s1);
//删除下标为7的数据
//越界
SeqListErase(&s1, 7);
}
TestSeqList11()
{
//定义一个结构体
SL s1;
//传址初始化结构体
SeqListInit(&s1);
//1 2 3 4 5尾插
SeqListPushBack(&s1, 1);
SeqListPushBack(&s1, 2);
SeqListPushBack(&s1, 3);
SeqListPushBack(&s1, 4);
SeqListPushBack(&s1, 5);
//删除4
int pos = SeqListFind(&s1, 4);
if (pos != -1)
SeqListErase(&s1, pos);
else
printf("无此数据 删除失败\n");
//打印1 2 3 5
SeqListPrint(&s1);
//删除7
pos = SeqListFind(&s1, 7);
if (pos != -1)
SeqListErase(&s1, pos);
else
printf("无此数据 删除失败\n");
//打印1 2 3 5
SeqListPrint(&s1);
}
TestSeqList12()
{
//定义一个结构体
SL s1;
//传址初始化结构体
SeqListInit(&s1);
//1 2 3 4 5尾插
SeqListPushBack(&s1, 1);
SeqListPushBack(&s1, 2);
SeqListPushBack(&s1, 3);
SeqListPushBack(&s1, 4);
SeqListPushBack(&s1, 5);
//打印1 2 3 4 5
SeqListPrint(&s1);
//销毁
SeqListDestroy(&s1);
//只打印\n
SeqListPrint(&s1);
}
int main()
{
//TestSeqList1();
//TestSeqList2();
//TestSeqList3();
//TestSeqList4();
//TestSeqList5();
//TestSeqList6();
//TestSeqList7();
//TestSeqList8();
//TestSeqList9();
//TestSeqList10();
//TestSeqList11();
//TestSeqList12();
return 0;
}
2°有菜单
#include "SeqList.h"
void Menu()
{
printf("*******************************\n");
printf("*** 1.头插 2.头删 ***\n");
printf("*** 3.尾插 4.尾删 ***\n");
printf("*** 5.pos处插 6.pos处删 ***\n");
printf("*** 7.查找 8.打印 ***\n");
printf("*** 0.退出 ***\n");
printf("*******************************\n");
printf("请选择:>");
}
enum Option
{
EXIT,//0
PUSHFRONT,//1
POPFRONT,//2
PUSHBACK,//3
POPBACK,//4
INSERT,//5
ERASE,//6
FIND,//7
PRINT//8
};
void MenuTest()
{
SL s1;
int n = 0;
int x = 0;
int pos = 0;
int num = 0;
SeqListInit(&s1);
while (1)
{
Menu();
int input = 0;
scanf("%d", &input);
switch (input)
{
case PUSHFRONT:
printf("以哪个数字作为结束标志\n");
printf("请选择:>");
scanf("%d", &n);
printf("请输入你要头插的数据 以%d结束:\n", n);
scanf("%d", &x);
while (x != n)
{
SeqListPushFront(&s1, x);
scanf("%d", &x);
}
break;
case POPFRONT:
SeqListPopFront(&s1);
break;
case PUSHBACK:
printf("以哪个数字作为结束标志\n");
printf("请选择:>");
scanf("%d", &n);
printf("请输入你要尾插的数据 以%d结束:\n", n);
scanf("%d", &x);
while (x != n)
{
SeqListPushBack(&s1, x);
scanf("%d", &x);
}
break;
case POPBACK:
SeqListPopBack(&s1);
break;
case PRINT:
SeqListPrint(&s1);
break;
case INSERT:
printf("两种模式:1.输入数据 在这个数据前插入 2.输入下标 在这个下标处插入\n");
printf("请选择(1或者2)>:");
scanf("%d", &n);
while (1)
{
if (n == 1)
{
printf("请输入数据\n");
printf("请选择:>");
scanf("%d", &num);
int pos = SeqListFind(&s1, num);
if (pos != -1)
{
printf("请输入要插入的数据\n");
printf("请选择:>");
scanf("%d", &x);
SeqListInsert(&s1, pos, x);
break;
}
else
{
printf("未找到该数据\n");
printf("请重新选择\n");
}
}
else
{
SL* ps = &s1;
printf("要插入数据的下标\n");
printf("请选择>:");
scanf("%d", &pos);
if (pos >= 0 && pos <= ps->size)
{
printf("请输入要插入的数据\n");
printf("请选择>:");
scanf("%d", &x);
SeqListInsert(&s1, pos, x);
break;
}
else
printf("该下标不存在 请重新输入\n");
}
}
break;
case ERASE:
printf("两种模式:1.输入数据 删除这个数据 2.输入下标 删除这个下标对应的数据\n");
printf("请选择(1或者2)>:");
scanf("%d", &n);
while (1)
{
if (n == 1)
{
printf("请输入想要删除的数据\n");
printf("请选择>:");
scanf("%d", &num);
int pos = SeqListFind(&s1, num);
if (pos != -1)
{
SeqListErase(&s1, pos);
break;
}
else
{
printf("未找到该数据\n");
printf("请重新选择>:");
}
}
else
{
SL* ps = &s1;
printf("请输入想要删除数据的下标\n");
printf("请选择>:");
scanf("%d", &pos);
if (pos >= 0 && pos <= ps->size)
{
SeqListErase(&s1, pos);
break;
}
else
printf("该下标不存在 请重新输入\n");
}
}
break;
case FIND:
printf("请输入你需要找的数据\n");
printf("请选择>:");
scanf("%d", &x);
int pos = SeqListFind(&s1, x);
if (pos != -1)
{
printf("需不需要修改数据(1.修改 0.不修改)\n");
printf("请选择(1/0)>:");
scanf("%d", &num);
if (num == 0)
printf("该数据的下标为%d\n", pos);
else
{
printf("该数据的下标为%d\n", pos);
printf("请输入你想要改后的数据\n");
printf("请选择>:");
scanf("%d", &x);
SL* Find = &s1;
Find->a[pos] = x;
}
}
else
printf("未找到该数据\n");
break;
case EXIT:
printf("退出程序\n");
return 0;
break;
default:
printf("无此选项 请重新输入\n");
break;
}
}
SeqListDestroy(&s1);
}
int main()
{
MenuTest();
return 0;
}
根据不同情况输入和输出以及调用函数
测试情况
1 2 3 4 7 8功能正常
头删和尾删 删完了再删会assert
测试pos处插
测试pos处删
#2顺序表的实现#完