1.顺序表的介绍
顺序表是数据结构线性表的一种,其在物理结构和逻辑结构上都是连续的。
顺序表和数组有什么关联呢
顺序表的底层结构是数组,其本质上是对数组进行更加豪华的包装
如果拿路边的小饭店比作数组,那么顺序表就相当于米其林五星级酒店,他们对饭菜的加工和味道等都不一样,五星级的看起来就更加的豪华。
2.顺序表的分类
顺序表也是有分类的
分为:静态顺序表和动态顺序表两大类
静态顺序表
从字面意思上能看出,能够储存的数据是固定大小的,无法改变
其实现的代码:
struct std {
int arr[100]; // 当然这里不一定是int类型的,也可以是其他类型的
int size;
};
很明显的能够看出静态顺序表的缺点,因为其空间大小是固定的,所以会造成空间大小不足或者是空间大小过剩等情况,而动态顺序表就能很好的避免这些问题。
动态顺序表可以按需向系统申请空间,当空间不足时自主的向系统申请空间,申请内存空间时通常会以原有空间的2-3倍来申请空间,下面就自主实现一个动态顺序表
3.动态顺序表的实现
实现动态顺序表需要我们有一个头文件和两个源文件
对使用函数进行声明的头文件--seqlist.h
实现需要使用的函数的源文件--seqlist.c
对编写的动态顺序表进行测试的源文件--test.c
首先先在 seqlist.h 文件中创造出动态顺序表的主体
typedef int SLDataType;
//顺序表储存的数据类型不一定是int类型,typedef 可以帮助我们后续修改储存的数据类型
struct SeqList {
SLDataType* arr; // 用来储存数据
int data_size; // 顺序表中储存数据的有效个数
int space_size; // 顺序表空间的大小
};
接下来我们要对顺序表进行操作,让其更加完善:
顺序表的初始化
对顺序表进行扩容
从尾部插入删除数据
从头部插入删除数据
从指定位置插入删除数据
打印顺序表
顺序表的销毁
先在 test.c 中创建需要的代码
void test_01()
{
SL sl;
}
int main()
{
test_01();
return 0;
}
(1)顺序表的初始化
void SL_init(SL* ps) {
ps->arr = NULL;
ps->data_size = ps->space_size = 0;
}
(2)对顺序表进行扩容
void SL_extend(SL* ps) {
//先检查空间是否足够,不够就申请增加空间
if (ps->data_size == ps->space_size) {
int new_space_size = ps->space_size == 0 ? 4 : 2 * ps->space_size;
SLDataType* tmp = (SLDataType*)realloc(ps->arr, new_space_size * sizeof(SLDataType));
//检查空间是否成功申请
//这里也可以直接使用assert断言
if (tmp == NULL) {
perror("realloc");// 未成功申请就报错
exit(1);//并退出
}
//申请成功后就使用
ps->arr = tmp;
ps->space_size = new_space_size;
}
}
(3)插入数据
①从头部插入数据:
从头部插入数据需要将所有的数据都向后移一位再插入
void SL_addfront(SL* ps, SLDataType x) {
assert(ps);
SL_extend(ps);
// 先让整体数据都向后移动一位
for (int i = ps->data_size; i > 0; i--) {
ps->arr[i] = ps->arr[i - 1];
}
ps->arr[0] = x;
ps->data_size++;
}
②从尾部插入数据 :
直接从尾部插入数据就行
void SL_addback(SL* ps, SLDataType x) {
assert(ps);
SL_extend(ps);//检查空间是否足够
ps->arr[ps->data_size] = x;//把x放到尾部位置
ps->data_size++;//插入数据后有效数据也加1
}
③从指定位置插入数据:
插入位置及后面的数据都要向后移一位
void SL_addcust(SL* ps, int pos, SLDataType x) {
assert(ps);
SL_extend(ps);
//插入位置及后面的数据都要向后移一位
for (int i = ps->data_size; i > pos; i--) {
ps->arr[i] = ps->arr[i - 1];
}
ps->arr[pos] = x;
ps->data_size++;
}
(4)删除数据:
①从头部删除数据:
删除第一个数据后,需要把后面的数据都向前移一位
void SL_delfront(SL* ps) {
assert(ps);
assert(ps->data_size);//删除数据时数据表不能为空
for (int i = 0; i < ps->data_size - 2; i++) {
ps->arr[i] = ps->arr[i + 1];
}
ps->data_size--;
}
②从尾部删除数据
void SL_delback(SL* ps) {
assert(ps);
assert(ps->data_size);
ps->data_size--;
}
③从指定位置删除数据:
删除后需要把删除的数据后面的数据全部向前移动一位
void SL_delcust(SL* ps, int pos) {
assert(ps);
assert(ps->data_size);
for (int i = pos; i < ps->data_size - 1; i++) {
ps->arr[i] = ps->arr[i + 1];
}
ps->data_size--;
}
(5)打印顺序表中的数据
void SL_print(SL* ps) {
assert(ps);
for (int i = 0; i < ps->data_size; i++) {
printf("%d ", ps->arr[i]);
}
print("\n");
}
(6)顺序表的销毁
void SL_destroy(SL* ps) {
assert(ps);
free(ps->arr);
ps->arr = NULL;
ps->data_size = ps->space_size = 0;
}
这样一来,我们一整个完整的顺序表就制作完成了
4.顺序表的测试
(1)添加元素的测试
void test_01()
{
SL sl;
//初始化
SL_init(&sl);
//添加元素(这里是从尾部添加元素)
SL_addback(&sl, 1);
SL_addback(&sl, 2);
SL_addback(&sl, 3);
SL_addback(&sl, 4);
SL_print(&sl);
//销毁
SL_destroy(&sl);
}
int main()
{
test_01();
return 0;
}
打印的结果
1 2 3 4
接下来我们要把先把6加在2和3之间,再把0加在首元素位置处,最后把5加在末尾处
void test_01()
{
SL sl;
//初始化
SL_init(&sl);
//添加元素(这里是从尾部添加元素)
SL_addback(&sl, 1);
SL_addback(&sl, 2);
SL_addback(&sl, 3);
SL_addback(&sl, 4);
SL_print(&sl);
SL_addcust(&sl, 2, 6);
SL_addfront(&sl, 0);
SL_addback(&sl, 5);
SL_print(&sl);
//销毁
SL_destroy(&sl);
}
打印的结果为
1 2 3 4
0 1 2 6 3 4 5
(2)删除元素的测试
接着上面的代码,分别吧0 6 5删除
void test_01()
{
SL sl;
//初始化
SL_init(&sl);
//添加元素(这里是从尾部添加元素)
SL_addback(&sl, 1);
SL_addback(&sl, 2);
SL_addback(&sl, 3);
SL_addback(&sl, 4);
SL_print(&sl);
SL_addcust(&sl, 2, 6);
SL_addfront(&sl, 0);
SL_addback(&sl, 5);
SL_print(&sl);
SL_delfront(&sl);
SL_delback(&sl);
SL_delcust(&sl, 2);
SL_print(&sl);
//销毁
SL_destroy(&sl);
}
打印的结果
1 2 3 4
0 1 2 6 3 4 5
1 2 3 4
这样一来,我们整个代码的就完成了,测试也没有问题,
5.顺序表的全部代码
(1)Seqlist.h
#pragma once #include<stdio.h> #include<string.h> #include<stdlib.h> #include<assert.h> typedef int SLDataType; //顺序表储存的数据类型不一定是int类型,typedef 可以帮助我们后续修改储存的数据类型 struct SeqList { SLDataType* arr; // 用来储存数据 int data_size; // 顺序表中储存数据的有效个数 int space_size; // 顺序表空间的大小 }; typedef struct SeqList SL; // 对顺序表进行初始化 void SL_init(SL* ps); // 对顺序表进行空间扩容 void SL_extend(SL* ps); // 从尾部对顺序表添加元素 void SL_addback(SL* ps, SLDataType x); // 从头部对顺序表添加元素 void SL_addfront(SL* ps, SLDataType x); // 从指定位置对顺序表添加元素 void SL_addcust(SL* ps, int pos, SLDataType x); // 删除头部元素 void SL_delfront(SL* ps); // 删除尾部元素 void SL_delback(SL* ps); // 删除指定位置的元素 void SL_delcust(SL* ps, int pos); // 打印顺序表中的元素 void SL_print(SL* ps); // 销毁顺序表 void SL_destroy(SL* ps);
(2)Seqlist.c
#define _CRT_SECURE_NO_WARNINGS 1 #include"Seqlist.h" void SL_init(SL* ps) { ps->arr = NULL; ps->data_size = ps->space_size = 0; } void SL_extend(SL* ps) { //先检查空间是否足够,不够就申请增加空间 if (ps->data_size == ps->space_size) { int new_space_size = ps->space_size == 0 ? 4 : 2 * ps->space_size; SLDataType* tmp = (SLDataType*)realloc(ps->arr, new_space_size * sizeof(SLDataType)); //检查空间是否成功申请 if (tmp == NULL) { perror("realloc");// 未成功申请就报错 exit(1);//并退出 } //申请成功后就使用 ps->arr = tmp; ps->space_size = new_space_size; } } void SL_addback(SL* ps, SLDataType x) { assert(ps); SL_extend(ps);//检查空间是否足够 ps->arr[ps->data_size] = x;//把x放到尾部位置 ps->data_size++;//插入数据后有效数据也加1 } void SL_addfront(SL* ps, SLDataType x) { assert(ps); SL_extend(ps); // 先让整体数据都向后移动一位 for (int i = ps->data_size; i > 0; i--) { ps->arr[i] = ps->arr[i - 1]; } ps->arr[0] = x; ps->data_size++; } void SL_addcust(SL* ps, int pos, SLDataType x) { assert(ps); SL_extend(ps); //插入位置及后面的数据都要向后移一位? for (int i = ps->data_size; i > pos; i--) { ps->arr[i] = ps->arr[i - 1]; } ps->arr[pos] = x; ps->data_size++; } void SL_delfront(SL* ps) { assert(ps); assert(ps->data_size);//删除数据时数据表不能为空 for (int i = 0; i < ps->data_size - 2; i++) { ps->arr[i] = ps->arr[i + 1]; } ps->data_size--; } void SL_delback(SL* ps) { assert(ps); assert(ps->data_size); ps->data_size--; } void SL_delcust(SL* ps, int pos) { assert(ps); assert(ps->data_size); for (int i = pos; i < ps->data_size - 1; i++) { ps->arr[i] = ps->arr[i + 1]; } ps->data_size--; } void SL_print(SL* ps) { assert(ps); for (int i = 0; i < ps->data_size; i++) { printf("%d ", ps->arr[i]); } printf("\n"); } void SL_destroy(SL* ps) { assert(ps); free(ps->arr); ps->arr = NULL; ps->data_size = ps->space_size = 0; }
(3)test.c
#define _CRT_SECURE_NO_WARNINGS 1 #include"Seqlist.h" void test_01() { SL sl; //初始化 SL_init(&sl); //添加元素(这里是从尾部添加元素) SL_addback(&sl, 1); SL_addback(&sl, 2); SL_addback(&sl, 3); SL_addback(&sl, 4); SL_print(&sl); SL_addcust(&sl, 2, 6); SL_addfront(&sl, 0); SL_addback(&sl, 5); SL_print(&sl); SL_delfront(&sl); SL_delback(&sl); SL_delcust(&sl, 2); SL_print(&sl); //销毁 SL_destroy(&sl); } int main() { test_01(); return 0; }