目录
一.顺序表的简单介绍
在正式开始介绍我们的顺序表之前我先带大家认识一个数据结构中的基础概念——线性表。
线性表是多个具有相同特性的数据元素的有限序列,我们这里要理解的是线性表是一个比较宽泛的概念,线性表是一种在实际中广泛使用的数据结构。它是顺序表、链表、栈、队列、字符串等等数据结构的统称。
线性表在逻辑上是线性结构,也就说是连续的一条直线。但是在物理结构(内存中)上并不一定是连续的,所以我们在实现线性表的时候在物理结构上既可以选择连续的存储结构(顺序存储),也可以选择非连续的存储结构(链式存储)。
我们今天的重点就是实现线性表中的一种——顺序表。
顺序表又可以分为动态顺序表和静态顺序表,二者最大的差别就在于动态顺序表的可存储空间是可以变化的,可以更好的适应不同的需求。所以我们今天讲的重点也就是动态顺序表,只要能看懂今天的代码,那你再去理解静态顺序表的一定会非常容易。
提前声明一下,为了使大家可以更好的理解函数和变量,我已经按照自己的标准将函数名,变量名用自己的方法做了限制,包括用到的单词都做了翻译。
以下一段注释就是相关的翻译和限制,虽然会和网络上的其他文章有所出入,但是大同小异,而且数据结构更重要的是算法的思维,大家不必纠结于变量的名字。
//相关英语单词的翻译
/*
* list 列表
* controls 操作
* function 函数
* variate 变量
* initialization 初始化
* capacity 扩容
* specify 指定
* destruction 销毁
* Delete 删除
* clear 清空
* cycle 循环
* find 查找
* tail 尾部
* Data 数据
* Location 位置
* Address 地址
* Front 前面
* Insert 插入
*/
//函数以及变量命名规则
/*
* 顺序表(SL) :SequenceList
*
* 函数命名规则:对象+(_基础_)+功能
* 结构体对象的命名:名字前加“_”
* 宏定义常量的命名:前后均加“_”
* 定义函数(function)是所有传入的变量定义均以“f”开头
* 函数传入的参数通过"f"后“p”的数量来说明指针的级数
* 函数中非结构体有关变量必须包含该标识 variate 或其他标识说明符号
*/
接下来我们看详细的代码:
首先我们定义顺序表的结构体:
//我们这篇文章以整形为例向大家讲解
typedef int Goaltype; /*用来记录目标处理的数据类型,方变修改*/
struct SequenceList
{
Goaltype* _Orginal; /*记录顺序表的初始地址*/
int _Efficient; /*用来记录现在已经存储掉的数量*/
int _Global; /*用来记录最大可以存储的数量*/
};
typedef struct SequenceList SequenceList; /*结构体名字的定义*/
typedef struct SequenceList* pSequenceList; /*结构体指针的定义*/
二.顺序表的基础功能
1.顺序表的初始化
/*顺序表的初始化*/
/*返回值(pSequenceList):生成顺序表的地址*/
/*功能:构造并初始化一个顺序表*/
pSequenceList SLInitialization()
{
/*初始化分配一个内存空间的大小,不存储内容*/
pSequenceList goal = (pSequenceList)malloc(sizeof(SequenceList));
Goaltype* middle = (Goaltype*)malloc(sizeof(Goaltype));
if (!(middle && goal))
printf("申请内存空间失败,初始化失败\n");
else
{
goal->_Orginal = middle;
goal->_Efficient = 0;
goal->_Global = 1;
}
return goal;
}
2.顺序表的清空
/*顺序表的清空*/
/*参数:需要被清空的顺序表的地址*/
void SLClear(pSequenceList fps)
{
if (fps == NULL)
printf("您所传入的为无效操作指针,无法操作\n");
else
{
free(fps->_Orginal);
fps->_Orginal = (Goaltype*)malloc(sizeof(Goaltype));
fps->_Efficient = 0;
fps->_Global = 1;
}
}
3.顺序表的销毁
/*顺序表的销毁*/
/*参数:需要销毁的顺序表的地址*/
void SLDestruction(pSequenceList* const fpps)
{
if (fpps == NULL)
printf("您所传入的为无效操作指针,无法销毁\n");
else
{
free((*fpps)->_Orginal);/*所申请空间的释放*/
free(*fpps);
*fpps = NULL;
}
}
4.顺序表的所有内容的输出
/*顺序表中所有内容的输出*/
/*参数:需要被输出的顺序表的地址*/
void SLPrintf(pSequenceList const fps)
{
if (fps == NULL)
printf("您所传入的为无效操作指针,无法输出\n");
else
{
if (fps->_Efficient == 0)
printf("该顺序表存在但未存储相关数据");
else
{
for (int i = 0; i < fps->_Efficient; i++)
printf("%3d", *(fps->_Orginal + i));
printf("\n");
}
}
}
5.调用同一函数对顺序表的每一个元素进行同一操作
/*调用同一函数对顺序表的每一个元素进行同一操作*/
/*参数1:要操作的顺序表*/
/*参数2:调用的函数*/
void SLCycle(pSequenceList fps, void (*function)(Goaltype))
{
for (int i = 0; i < fps->_Efficient; i++)
function(*(fps->_Orginal + i));
printf("\n");
}
6.内存的扩容申请
/*内存的扩容申请*/
/*返回值:扩容成功->1,扩容失败->0 */
/*参数:需要被初始化的顺序表的地址*/
int SLCapacity(pSequenceList const fps)//每次扩容为原来可存储空间的两倍
{
if (fps == NULL)
{
printf("您所传入的为无效操作指针,无法扩容\n");
return 0;
}
else
{
Goaltype* middle = (Goaltype*)realloc(fps->_Orginal, sizeof(Goaltype) * 2 * (fps->_Global));
if (middle == NULL)
{
printf("申请内存空间失败\n");
return 0;
}
else
{
fps->_Orginal = middle;
fps->_Global = 2 * fps->_Global;
ret