本期是用于记录一下我个人了解下的顺序表。
首先,我们从顺序表的概念上来理解:即为物理地址连续的存储空间依次存储数据的一种线性结构,一般采用数组存储,并且在数组上完成数据的增删查改。根据不同的空间开辟方式,我们可以分为:静态顺序表和动态顺序表。
1:静态顺序表:即使用定长的数组存储元素。个人理解:我认为可以直接理解成空间大小固定的数组,更容易理解。我们可以将静态顺序表看作一个火车,在这个火车(静态顺序表)上的最大承载人员数量固定(内容存储空间大小固定)。
例如当前这幅图的火车,我们就可以看作一个静态顺序表,仅有四个车厢(4个内存大小)仅可存放4个游客(4个类型相同的数据),上完即止,无法增加。这种时候我们如果要扩容,就得换一辆空间更大的火车(用realloc重新申请一块更大空间来存储数据)。
2:动态顺序表:即使用动态开辟的数组存储。个人理解:我认为就是将一个用malloc动态空间的数组。可以比喻成一个可以添加车厢的火车,每当我们当前的车厢已满(存储空间已满),我们就给我们的火车加装车厢。
这一趟火车如果无法满足我们当前的载客量需求,我们可以给他加车厢,直到满足为止。其实我认为可以说两者就是静态数组和动态数组的差别。
应用场景:一般采用动态顺序表,因为静态顺序表的使用场景为已知固定大小,所以我们在实际情况中会使用动态顺序表。接下来,我们来完成一次动态顺序表的实现。
首次,我们创建一个工程,这个工程组成如下:源文件:SeqList.c和test.c 头文件:SeqList.h
SeqList.h:声明函数和应用库函数
SeqList.c:存放函数内容
test.c:调试内容
接下来,我们在SeqList.h中先构建一个结构体(SeqList)这个结构体由动态顺序表(array),顺序表当前存储数量:size还有顺序表当前最大存储量(capicity)构成,内容如下:
一个顺序表我们必须拥有的基本功能函数是顺序表的初始化,顺序表的尾插,顺序表的内存清理,为了检测我们当前的顺序表建立是否正常,我们还需要一个函数将我们顺序表的内容输出。由此我们可以构建出这几个函数:
我们先完成顺序表的初始化(SeqListInit ):因为我们申请的是动态顺序表,所以我们的结构体中的2顺序表是一个数组指针,所以我们先将指针指向NULL,剩下的已经存储数量(size)和当前最大容量(capicity)我们直接赋值为0即可。
然后我们完成一下清空函数(SeqListDestory):在内存中,我们需要将我们的动态顺序表的内容释放,然后将指针置为空,将我们的size和capicity变为0即可。这其中为了防止我们仅仅传输了一个未开辟的动态顺序表,我们使用一个if判断一下,满足条件我们才释放空间。
接下来,来到我们较为重要的尾插函数(SeqListPushBack):我们尾插时,就是将我们顺序表的最后一位设置为我们添加的函数即可,并且将当前存储数量(size)增加,在这里我们就可以直接使用:psl -> array[ psl -> size ] 因为当前我们的size就是我们顺序表的最后一个位置。不光以上内容我们就可以完成,我们还需要判断我们的空间是否足够,这时我们后续可能还有函数需要使用的情况下,我们将空间判断写成一个功能函数:ChechCapicity。
在检查空间是否足够中,我们只需要将size和capicity对比即可,当我们的capicity与size相等,那么我们需要扩容。但是我们在初始化时,将capicity设置为0,所以我们还需要一个初始的空间大小来申请。
在这个函数中,我们初始申请空间为4,后续申请空间翻倍,每次使用realloc函数来申请空间。
在我们添加上判断内存是否充足函数(CheckCapicity)之后,我们的尾插函数其实也完成啦。
随即我们只剩下一个打印顺序表的函数(SeqListPrint)函数:打印顺序表,我们可以先定义一个size_t i 使它等于我们的size,然后使用一个while循环,每次i--,i = 0时打印完成即可。
完成上述的函数之后,我们可以先进行调试,我这里进行了4个数据的尾插查看我们的函数是否出现了问题,内容和结果如下:
在上述功能的完成且无误的情况下,我们来进行扩展功能函数。
我们添加一个尾删,头删,头插,查找,在固定位置插入x,删除固定位置的值
接下来,我们就根据上述图片的顺序来逐一完善我们的动态顺序表。
首先是尾删函数(SeqListPopBack):我们仅仅需要将我们的size--即可,这样后续在尾部的修改会将值覆盖,我们不需要过多修改。
头插(SeqListPushFront):因为这是一个顺序表,我们可以将我们全部数据从后往前,将数据后移1个单位,然后将首位数据覆盖即可。
头删(SeqListPopFront):我们直接从顺序表下标为1的地方开始,将后续的数据将前面覆盖即可,然后将size--。
查找(SeqListFind):我们使用while循环将顺序表遍历,当出现我们所寻找的值时,返回下标即可。
在pos位置插入数据(SeqListInsert):我们先将pos之后的值全部后移一位,然后将数据直接赋值即可。
删除pos位置的值(SeqListErase):我们直接将pos之后的所有值,向前覆盖即可,然后将
size--。
通过以上补充,我们就得到了一个动态的顺序表啦,大家在每一个函数写完后一定要调试一下,防止错误产生。
感谢您花费宝贵的时间观看,代码我放在下面啦,欢迎各位大佬指导修改!!!!
//SeqList.h #pragma once #include#include #include typedef int SLDataType; typedef struct SeqList { SLDataType* array; size_t size; size_t capicity; }SeqList; //初始化 void SeqListInit(SeqList* psl); //内存清理 void SeqListDestory(SeqList* psl); //尾插 void SeqListPushBack(SeqList* psl, SLDataType x); //输出 void SeqListPrint(SeqList* psl); //尾删 void SeqListPopBack(SeqList* psl); //头插 void SeqListPushFront(SeqList* psl, SLDataType x); //头删 void SeqListPopFront(SeqList* psl); //查找 size_t SeqListFind(SeqList* psl, SLDataType x); //在pos位置插入x void SeqListInsert(SeqList* psl, size_t pos, SLDataType x); //删除pos位置的值 void SeqListErase(SeqList* psl, size_t pos);
//SeqList.c #define _CRT_SECURE_NO_WARNINGS #include"SeqList.h" //初始化 void SeqListInit(SeqList* psl) { assert(psl); psl->array = NULL; psl->size = 0; psl->capicity = 0; } //清空 void SeqListDestory(SeqList* psl) { assert(psl); if (psl->array != NULL) { free(psl->array); psl->array = NULL; psl->size = psl->capicity = 0; } } void ChechCapicity(SeqList* psl) { if (psl->size == psl->capicity) { size_t newcapicity = psl->capicity == 0 ? 4 : psl->capicity * 2; SeqList* tmp = (SeqList*)realloc(psl->array, sizeof(SeqList) * newcapicity); if (tmp == NULL) { perror("realloc"); exit(-1); } psl->array = tmp; psl->capicity = newcapicity; } } //尾插 void SeqListPushBack(SeqList* psl, SLDataType x) { assert(psl); ChechCapicity(psl); psl->array[psl->size] = x; psl->size++; } void SeqListPrint(SeqList* psl) { assert(psl); SLDataType* data = psl->array; size_t i = psl->size; while (i > 0) { printf("%d -> ", *data); data++; i--; } printf("NULL\n"); } //尾删 void SeqListPopBack(SeqList* psl) { assert(psl); psl->size--; } //头插 void SeqListPushFront(SeqList* psl, SLDataType x) { assert(psl); ChechCapicity(psl); size_t i = psl->size; while (i > 0) { SLDataType prev = psl->array[i - 1]; psl->array[i] = prev; i--; } psl->array[0] = x; psl->size++; } //头删 void SeqListPopFront(SeqList* psl) { assert(psl); int begin = 1; while (begin < psl->size) { psl->array[begin - 1] = psl->array[begin]; ++begin; } psl->size--; } //查找 size_t SeqListFind(SeqList* psl, SLDataType x) { assert(psl); size_t tmp = 0; while (tmp < psl -> size) { if (psl->array[tmp] == x) { return tmp; } tmp++; } return -1; } //在pos位置插入x void SeqListInsert(SeqList* psl, size_t pos, SLDataType x) { assert(psl); ChechCapicity(&psl); size_t i = psl->size; while (i >= pos) { SLDataType prev = psl->array[i - 1]; psl->array[i] = prev; i--; } psl->array[pos] = x; psl->size++; } //删除pos位置的值 void SeqListErase(SeqList* psl, size_t pos) { assert(psl); while (pos < psl->size - 1) { psl->array[pos] = psl->array[pos + 1]; pos++; } psl->size--; }
//test.c #define _CRT_SECURE_NO_WARNINGS #include"SeqList.h" void Test1() { SeqList sl; SeqListInit(&sl); SeqListPushBack(&sl, 1); SeqListPushBack(&sl, 2); SeqListPushBack(&sl, 3); SeqListPushBack(&sl, 4); SeqListPrint(&sl); SeqListPopBack(&sl); SeqListPrint(&sl); SeqListDestory(&sl); } void Test2() { SeqList sl; SeqListInit(&sl); SeqListPushBack(&sl, 1); SeqListPushBack(&sl, 2); SeqListPushBack(&sl, 3); SeqListPushBack(&sl, 4); SeqListPushFront(&sl, 5); SeqListPrint(&sl); SeqListPopFront(&sl); SeqListPrint(&sl); SeqListDestory(&sl); } void Test3() { SeqList sl; SeqListInit(&sl); SeqListPushBack(&sl, 1); SeqListPushBack(&sl, 2); SeqListPushBack(&sl, 3); SeqListPushBack(&sl, 4); SeqListPrint(&sl); size_t pos = SeqListFind(&sl, 3); SeqListInsert(&sl, pos, 8); SeqListPrint(&sl); SeqListErase(&sl, pos); SeqListPrint(&sl); SeqListDestory(&sl); } int main() { Test3(); return 0; }
test.c运行结果如图: