文章目录
- 一、前言
- 二、顺序表的概念与结构
- 2.1顺序表的概念
- 2.2顺序表的结构
- 三、顺序表的分类
- 3.1静态顺序表
- 3.1.1静态顺序表的弊端
- 3.2动态顺序表
- 3.2.1动态顺序表的相对利弊
- 3.2.2动态顺序表的增容方式
- 四、顺序表的增、插、删、查、印、毁
- 4.1 顺序表的增容
- 4.2顺序表的尾插和头插
- 4.2.1尾插
- 4.2.2头插
- 4.2.3指定位置插入
- 4.3顺序表的尾删和头删
- 4.3.1尾删
- 4.3.2头删
- 4.3.3指定位置删除
- 4.4顺序表的查找
- 4.5顺序表的打印
- 4.6顺序表的销毁
- 五、整体代码分析
- 5.1头文件——SeList.h
- 5.1.1头文件的作用
- 5.1.2头文件代码展示
- 5.2主体代码文件——SeList.c
- 5.3测试文件——test.c
- 5.3.1测试文件的作用
- 5.3.2测试文件具体演示
- 5.3.2.1尾插演示
- 5.3.2.2头插演示
- 5.3.2.3尾删演示
- 5.3.2.4头删演示
- 5.3.2.5指定位置插入演示
- 5.3.2.6指定位置删除演示
- 5.3.2.7元素查找演示
- 5.3.2.8空间销毁演示
- 5.3.3测试文件代码展示
- 六、总结
一、前言
Hello啊,各位老铁们,今天的你是否在继续学习呢?up呢最近也是在学习数据结构的时候被其魅力冲昏了头脑,也是沉淀了大概10天左右吧?这10天你们有没有想念up呢?其实有时候,我们也是需要做减法,一味的累计而不去消化,最后可能被撑死。所以大家在学完知识过后,也要去沉淀沉淀哦。好啦我们回归今天的的主题,up今天给大家分享的是数据结构——顺序表。
二、顺序表的概念与结构
2.1顺序表的概念
顺序表:用一段物理地址连续的储存单元依次存储数据元素的线性结构,它的本质是用数组存储。
2.2顺序表的结构
三、顺序表的分类
顺序表可以分为静态顺序表和动态顺序表两类。
3.1静态顺序表
3.1.1静态顺序表的弊端
静态顺序表相当于有一种“一锤定音”的效果,那肯定也有着非常明显的弊端:空间给少了不够用,给大了容易造成浪费。
3.2动态顺序表
刚刚呢up介绍了静态顺序表,那么从逆向思维的角度来看,是不是也存在动态顺序表呢?答案是肯定的。
3.2.1动态顺序表的相对利弊
动态顺序表在一定程度上减少了空间的浪费,但是这只是相对的,也不排除造成空间浪费的可能。
3.2.2动态顺序表的增容方式
顾名思义,动态顺序表那么它的内存空间大小肯定是动态的,在空间不够的同时回自动增容——成倍数增容,一般情况下是2倍增容。
四、顺序表的增、插、删、查、印、毁
4.1 顺序表的增容
在我们创建顺序表的时候,为了方便之后的使用,我们肯定会判断空间是否为满的情况,如果空间满了,那我们则需要实现增容。
画图展示:
代码展示
4.2顺序表的尾插和头插
4.2.1尾插
画图展示:
代码展示:
4.2.2头插
画图展示
代码展示
4.2.3指定位置插入
画图展示
代码展示:
4.3顺序表的尾删和头删
4.3.1尾删
画图展示·
代码展示:
4.3.2头删
画图展示
代码展示:
4.3.3指定位置删除
画图展示:
代码展示:
4.4顺序表的查找
查找方法:从顺序表第一个元素开始依次遍历,判断每一个元素和要查找的元素是否相同,相同则返回
代码展示:
4.5顺序表的打印
打印方法:从顺序表第一个元素开始,依次遍历,打印每一个元素
代码展示:
4.6顺序表的销毁
代码展示:
五、整体代码分析
OK啊up刚刚已经给大家讲解完毕了顺序表的全部情况。但是有的兄弟就问:“up up,我还是觉得这样有点太生硬了,有整体分析一波的步骤吗?"作为一个非常宠粉的up,我只能说:有点,兄弟,有的。那我们现在就来整体分析一波。
我们顺序表的代码为了方便并且清晰地实现,实际上需要创建3个文件,一个头文件(SeList.h)和两个源文件(Selist.c 和 test.c)。这个时候又有宝子疑问了——明明可以只写一个源文件就解决了,为什么还要分为3个文件呢?不急,请往下看。
5.1头文件——SeList.h
5.1.1头文件的作用
我们之前在C语言的学习中,已经非常清晰地了解到了头文件的作用,具体由以下7点:
1、声明接口和模块化代码;
2、减少重复代码;
3、提高代码复用性;
4、加强类型安全检查;
5、防止重复包含;
6、支持库功能调用;
7、组织项目结构。
5.1.2头文件代码展示
//头文件SeList.h
#pragma once
#include <stdio.h>
#include <stdlib.h>
#include <assert.h>
typedef int SLDataType;
struct Sequelist
{SLDataType* arr;int size;int capacity;
};
typedef struct Sequelist 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);//头删
void SLInsert(SL* ps, int pos, SLDataType x);//指定位置插入
void SLErase(SL* ps, int pos);//指定位置删除
int SLFind(SL* ps, SLDataType x);//查找
5.2主体代码文件——SeList.c
主体代码就是我们程序中用来实现功能的代码。我们将所有实现功能的代码放在一起,也更加的条理清晰。
//主体文件SeList.c
#include "SeList.h"
void SLInit(SL* ps)//初始化
{ps->arr = NULL;ps->size = 0;ps->capacity = 0;
}
void SLCheckCapacity(SL* ps)//增容
{if (ps->size == ps->capacity)//空间已满{SLDataType newcapacity = ps->capacity == 0 ? 4 : 2 * ps->capacity;//三目操作符判断原本空间是否为空,是则增容4个空间,不是则进行两倍增容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)//尾插
{assert(ps);SLCheckCapacity(ps);ps->arr[ps->size++] = x;
}
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];}ps->arr[0] = x;++ps->size;
}
void SLPopBack(SL* ps)//尾删
{assert(ps && ps->size);--ps->size;
}
void SLPopFront(SL* ps)//头删
{assert(ps && ps->size);for (int i = 0;i< ps->size-1;i++)//从第二个元素开始依次往前移动{ps->arr[i] = ps->arr[i + 1];}--ps->size;
}
void SLInsert(SL* ps, int pos, SLDataType x)//指定位置插入
{assert(ps);assert(pos >= 0 && pos < ps->size);//前提条件判断SLCheckCapacity(ps);for (int i = ps->size;i > pos;i--)//从最后一个元素往后移,直到pos位置{ps->arr[i] = ps->arr[i - 1];}ps->arr[pos] = x;++ps->size;
}
void SLErase(SL* ps, int pos)//指定位置删除
{assert(ps);assert(pos >= 0 && pos < ps->size);//前提条件判断for (int i = pos;i < ps->size - 1;i++)//从pos位置后一个元素依次往前移动,直到最后一个元素{ps->arr[i] = ps->arr[i + 1];}--ps->size;
}
int SLFind(SL* ps, SLDataType x)//查找元素
{for (int i = 0;i < ps->size;i++)//依次遍历{if (ps->arr[i] == x)return i; //找到则返回i}return -1; //找不到则返-1
}
void SLDestroy(SL* ps)//销毁
{assert(ps);if (ps->arr)free(ps->arr);ps->arr = NULL;ps->size = 0;ps->capacity = 0;
}
void SLPrint(SL* ps)//打印
{for (int i = 0;i < ps->size;i++)//遍历打印{printf("%d ", ps->arr[i]);}printf("\n");
}
5.3测试文件——test.c
5.3.1测试文件的作用
最后就来到了我们的测试文件了,那么测试文件又有什么好处呢?
1、验证程序的正确性;
2、提高代码之路;
3、优化性能;
4、文档作用。
5.3.2测试文件具体演示
5.3.2.1尾插演示
5.3.2.2头插演示
5.3.2.3尾删演示
5.3.2.4头删演示
5.3.2.5指定位置插入演示
5.3.2.6指定位置删除演示
5.3.2.7元素查找演示
5.3.2.8空间销毁演示
5.3.3测试文件代码展示
//text.c
#include "SeList.h"
test01()
{SL s1;SLInit(&s1);//初始化//SLPushBack(&s1, 1);//SLPushBack(&s1, 2);//SLPushBack(&s1, 3);//SLPushBack(&s1, 4);//SLPrint(&s1);//尾插SLPushFront(&s1, 1);SLPushFront(&s1, 2);SLPushFront(&s1, 3);SLPushFront(&s1, 4);//SLPrint(&s1);//头插//SLPopBack(&s1);//SLPrint(&s1);//尾删//SLPopFront(&s1);//SLPrint(&s1);//SLInsert(&s1, 2, 5);//指定位置插入//SLPrint(&s1);//SLErase(&s1, 2);//指定位置删除//SLPrint(&s1);//int find = SLFind(&s1, 2);//元素查找//{// if (find != -1)// printf("找到了!\n");// else// printf("找不到!\n");//}//SLPrint(&s1);SLDestroy(&s1);//SLPrint(&s1);
}
int main()
{test01();return 0;
}
六、总结
以上就是关于数据结构——顺序表的全部知识。up在最后演示的部分可能注释的代码有一点多,也是麻烦各位宝子们在阅读的时候耐心一点。最后也希望各位宝子学有所获,精益求精。当然也希望大家可以一键三连,嘿嘿嘿。
时间的沉淀,会让努力变得更加珍贵。