当前位置:   article > 正文

【C语言数据结构(基础篇)】第二站:顺序表_1)从两个文件中分别读出流调信息记录,并按照原文件顺序建立两个线性表。 2)输出所

1)从两个文件中分别读出流调信息记录,并按照原文件顺序建立两个线性表。 2)输出所

目录

一、线性表

 二、顺序表的实现(概念以及静态顺序表)

1.创建三个工程文件

2.顺序表的概念

3.顺序表的定义

4.初始化顺序表

5.静态顺序表的尾插

三、顺序表的实现(升级为动态顺序表)

1.动态顺序表的定义

2.动态顺序表的初始化

3.动态顺序表的尾插

4.顺序表的头插

 5.顺序表的尾删

 6.顺序表的头删

 7.顺序表任意位置的增加

8.顺序表任意位置的删除

 9.顺序表的销毁

10.顺序表的查找

 11.顺序表的修改

 12.顺序表的菜单

 三、顺序表完整代码

总结


一、线性表

首先我们必须要了解的一个概念是线性表

线性表(linear list)是n个具有相同特性的数据元素的有限序列。 线性表是一种在实际中广泛使用的数据结构,常见的线性表:顺序表、链表、栈、队列、字符串...
线性表在逻辑上是线性结构,也就说是连续的一条直线。但是在物理结构上并不一定是连续的, 线性表在物理上存储时,通常以数组和链式结构的形式存储。
顺序表就是数组 ,他的内存是连续的

下面就是一个链表的结构,当然或许你现在并不知道链表是什么,但是没有关系, 我们在后面的文章中将会花费大量的笔墨去详细讲解链表,这里你只需要大概看一眼就可以了,下图什么都看不懂是没有任何关系的。

 二、顺序表的实现(概念以及静态顺序表)

对于顺序表的实现,我们采用分文件的形式来展现,在前面我们也已经利用了两个小游戏来让大家熟悉了分文件的写法,这里就不在赘述。如果还有不懂的地方,可以去C语言专栏去找到对应的文章。同样数据结构部分,为了规范我们的写法,我们全部采用大驼峰的命名风格

1.创建三个工程文件

如下图所示,我们创建好三个文件,分别是SeqList.c SeqList.h Test.c

SeqList.c用于顺序表的实现

SeqList.h用于顺序表的声明

Test.c用于测试顺序表

2.顺序表的概念

我们得先了解顺序表的概念,才能继续完成下去

顺序表是一段物理地址连续的存储单元依次存储数据元素的线性结构,一般情况下采用数组存储。在数组上完成数据的增删查改

顺序表一般可分为

静态顺序表:使用定长数组进行存储

动态顺序表:使用动态开辟的数组进行存储

3.顺序表的定义

我们先看静态顺序表是如何定义的,如下图所示,我们知道顺序表他也是用来存储数据的,既然是用来存储数据的,那么他必然要有一个数组来存储,然后还要有一个size来确定目前存储了一个数据。将这两个合并到一起就是一个结构体

 虽然说这可以当作一个静态顺序表来进行定义,但是要真是这样定义,还是会出现很多问题,比如说哪一天想要存储100个数据了,那么我们上面这个就是写死了,根本没法改。所以我们可以使用define来进行优化,如下图所示

这样的话,确实,解决了一些后续无法增加数据的问题,但是如果突然不想要整型类型了,他想要char类型的话,那这个顺序表又废了,所以我们还得再次进行优化,我们可以使用一个typedef来重定义类型,如下图所示

 当然这样其实还不够好,我们如果想要使用这个结构体的话,这个结构体类型太长了,我们写着写着都快烦死了。所以我们也可以对结构体进行typedef

如下图所示,我们让这个结构体类型变成了SL,当然这个有两种写法,一种是使用注释中的写法,另外一种就是在定义结构体的时候就typedef

最终代码如下(SeqList.h这个文件)

  1. #pragma once
  2. #define N 10
  3. typedef int SQDateType;
  4. typedef struct SeqList
  5. {
  6. SQDateType arr[N];
  7. int size;
  8. }SL;
  9. //等价于typedef struct SeqList SL;

4.初始化顺序表

我们在说顺序表的概念的时候就提到过,顺序表是要实现增删查改四大功能的,但是在这之前,我们得先初始化顺序表

于是我们在头文件先进行一次初始化函数的声明

 在SeqList.c文件中,我们就要实现这个功能了,如下图所示,我们使用一个memset函数,在这里可能有些人还不熟悉或者不太了解这个函数,我们可以现场学习一下 ,如下图所示,他是将传入的一个指针,从他开始的前num个字节都设置为value

 所以下面中的意思就是将这个数组的全部元素设置为0,并且将size也就是目前的元素个数也设置为0

而对应这个函数也有他自己的头文件,我们为了方便,可以直接全部放在SeqList.h中

 既然如此,那么我们就开始来测试一下这个函数究竟对不对

 我们打完断点以后,直接使用F5,跳转至断点处,并打开调试的监视窗口,如下图所示,我们已经将顺序表给初始化完成了

 我们开始进入我们的函数,我们发现,这块并没有将这个顺序表给初始化啊。这是为什么呢?

 其实这块已经很多人发现了这个问题,因为我们传的其实是形参,形参的改变不会影响实参。我们就不该使用这个传值调用了,我们应该使用传址调用,我们现在将我们的代码都改为指针

 

 

而此时就能够完成我们的目标了,实现初始化顺序表

 顺序表初始化接口代码为

  1. //顺序表初始化
  2. void SeqListInit(SL* ps)
  3. {
  4. memset(ps->arr, 0, sizeof(SQDateType) * N);
  5. ps->size = 0;
  6. }

5.静态顺序表的尾插

在我们将顺序表给初始化以后,我们现在需要的就是试下顺序的表的增删查改,当然我们在讲述顺序表的概念的时候,提到了这两个关键点:

1.连续的物理存储地址------数组

2.数据必须是从头开始,依次存储------不能在数组的第一个元素插入一个,然后第二个又跑到了第三个元素上

那么我们就先来定义一下我们的接口函数,如下图所示,这里我们的命名与c++的标准库一致,让我们的程序更加规范

不过既然有尾插,那么与之对应的就有头插,尾删,以及头删,不妨我们也直接定义好他们的接口吧,如下图所示

那么我们先来实现尾插,如何实现尾插呢?我们可以试着画图理解一下,如下图所示,我们假设数组已经存储了5个元素了,此时他的size就是5,那么这个5刚好就是下一个数据的下标,所以我们就想到了,有了下标了,那不就是直接插入数据了吗。插入完之后再让size++就行了吗,确实是这样的。

我们来实现一下我们的想法,如下图所示

但是这样存在一个问题,如果顺序表满了呢?我们可以实验一下

我们进行调试,如下图所示,顺序表已经初始化完成

我们使用F10不进入函数内部进行调试,我们可以发现现在即将越界

此时已经越界了,我们发现arr[10]他与size进行同步变化,size直接变成了12,而不是变成了11,这个问题,在我们之前讲解调试的时候已经提到过了,这就是数组越界所带来的风险。size的数据已经被破坏了。所以这个顺序表已经废了

那么我们该怎么办呢?我们可以在顺序表满的时候提示一句顺序表满了,然后就直接返回,直接拦截这个错误的信息,不让他插入进去,所以实现如下

 这个时候我们再次调试一下,此时我们发现,拦截成功了。

 其实到这块我们也发现一个问题,那就是静态顺序表不太好,要么消耗的空间太大,要么空间不够。总之很麻烦。而我们一般下也不会去使用静态的顺序表,我们都是使用动态的顺序表,可以进行扩容的顺序表。

所以我们在这里就不在继续进行实现静态的顺序表的,我们转而实现动态的顺序表

三、顺序表的实现(升级为动态顺序表)

想要实现一个动态的顺序表,那么我们得先将我们的思路给理清晰,然后在我们的静态顺序表上进行修改

1.动态顺序表的定义

静态的顺序表是通过一个宏来进行确定一个数组的,既然是动态,那么我们就不能用宏了,我们可以使用一个指针,当然使用指针以后,我们就没法确定总容量了,所以我们还需要一个参数capacitiy称为容量

所以新的动态顺序表的定义就如下所示

 代码如下

  1. typedef int SQDateType;
  2. typedef struct SeqList
  3. {
  4. SQDateType* a; //指向动态开辟的数组
  5. int size; //当前的有效数据个数
  6. int capacity; //容量空间的大小
  7. }SL;

2.动态顺序表的初始化

定义修改完后,我们就修改一下顺序表的初始化

因为a已经是一个指针了,所以说我们直接让a指向一个空指针就可以了。然后就让其他两个都变成0就行了。当然我们也可以一开始给他一块空间,当然这都无所谓了,因为我们可以在后面插入顺序表的时候就判断一下容量是否还有,如果没有容量,在那个时候在进行扩容即可

代码如下

  1. //顺序表初始化
  2. void SeqListInit(SL* ps)
  3. {
  4. ps->a = NULL;
  5. ps->size = 0;
  6. ps->capacity = 0;
  7. }

3.动态顺序表的尾插

我们已经初始化好了,那么现在我们就来修改一下尾插

在静态顺序表的时候,如果满了,就拦截,但是在动态版的,我们就可以进行扩容了

下面是判断是否满了

 满了就得扩容,那么如何扩容呢?我们使用realloc函数,我们去查看他的信息

 当然如果我们看不懂也没有关系,打开有道字典,选择计算机,复制粘贴翻译即可

 他的意思就是,重新分配一个内存,因为我们的内存都是一块一块的断开的片段,所以我们就先看一看在他原来的地址上够不够我们之前的内存,如果够的化,那么就在原来的地址上原地扩容,如果不够,找一块连续的空间,将原来的数据都移动到这个新的空间上,最后将这个新的空间的地址返回,这里返回的void类型,所以需要进行强制类型转换。当然也有可能因为内存不够了,导致扩容失败。此时返回的就是NULL空指针

所以由上面的分析可以得到如下所示的代码,先对其进行扩容,然后如果内存不够扩容失败,则直接退出,如果扩容成功,则将这个地址给a这个指针,并让总容量扩大二倍,注意,我们一般习惯上扩大二倍的容量

 接下来我们就是扩容成功了,然后我们需要将这个数据给放进去,然后size++

 写到这一块,细心的人已经发现这里有一个bug了。当然没发现也没要紧。我们可以测试一下

为了方便测试,我们在这里先写出打印数据的接口,这个很简单,我们就直接写出来吧

  我们运行一下吧,我们发现程序挂了

这可不行,我们得调试一下,来看一看究竟是哪里错了,一开始的初始化是没有任何问题的

但是当我们下一步的时候,我们发现capacity的值居然是0。这说明这个函数内部出现问题了,于是我们知道了问题,就要进入这个函数里面去寻找问题

 在这一步的时候,我们发现了问题,因为我们一开始capacity是0,零乘以任何数都为0,所以程序肯定会出错

 所以为了避免这个错误,我们可以在定义一个变量,就可以完美的解决了

 此时我们的运行结果为,这样结果就跟我们预期一样了

 至此,我们的尾插就实现了

代码如下

  1. //顺序表尾插
  2. void SeqListPushBack(SL* ps, SQDateType x)
  3. {
  4. //判断是否满了,如果满了,就得扩容了
  5. if (ps->size == ps->capacity)
  6. {
  7. int newcapacity = ps->capacity == 0 ? 4 : ps->capacity * 2;
  8. SQDateType* tmp = (SQDateType*)realloc(ps->a, newcapacity * sizeof(SQDateType));
  9. if (tmp == NULL)
  10. {
  11. printf("realloc fail\n");
  12. exit(-1);
  13. }
  14. else
  15. {
  16. ps->a = tmp;
  17. ps->capacity = newcapacity;
  18. }
  19. }
  20. ps->a[ps->size] = x;
  21. ps->size++;
  22. }

 当然我们也把打印函数也给出来

  1. //打印数据
  2. void SeqListPrint(SL* ps)
  3. {
  4. int i = 0;
  5. for (i = 0; i < ps->size; i++)
  6. {
  7. printf("%d ", ps->a[i]);
  8. }
  9. printf("\n");
  10. }

4.顺序表的头插

我们实现了尾插,但是有时候也需要往头插入数据,这个该如何实现呢?

我们的想法是这样的,从后往前,一个数据一个数据往后挪动即可,玩玩不可从前往后挪,因为这样会出问题的

所以基本逻辑的实现如下所示

 而对于这段代码,其实面临着和尾插一样的问题,就是空间不够了呢?所以我们需要增容,既然头插也要增容,尾插也要增容,那我们不妨将增容封装成一个函数吧,仅仅这两个函数使用,如下图所示

 然后我们就可以先测试一下我们的代码

 测试结果如下

 我们将这段代码给出

  1. //扩容函数
  2. void SeqListCheckCapacity(SL* ps)
  3. {
  4. //判断是否满了,如果满了,就得扩容了
  5. if (ps->size == ps->capacity)
  6. {
  7. int newcapacity = ps->capacity == 0 ? 4 : ps->capacity * 2;
  8. SQDateType* tmp = (SQDateType*)realloc(ps->a, newcapacity * sizeof(SQDateType));
  9. if (tmp == NULL)
  10. {
  11. printf("realloc fail\n");
  12. exit(-1);
  13. }
  14. else
  15. {
  16. ps->a = tmp;
  17. ps->capacity = newcapacity;
  18. }
  19. }
  20. }
  21. //顺序表尾插
  22. void SeqListPushBack(SL* ps, SQDateType x)
  23. {
  24. SeqListCheckCapacity(ps);
  25. ps->a[ps->size] = x;
  26. ps->size++;
  27. }
  28. //顺序表的头插
  29. void SeqListPushFront(SL* ps, SQDateType x)
  30. {
  31. SeqListCheckCapacity(ps);
  32. int end = ps->size - 1;
  33. while (end >= 0)
  34. {
  35. ps->a[end + 1] = ps->a[end];
  36. end--;
  37. }
  38. ps->a[0] = x;
  39. ps->size++;
  40. }

 5.顺序表的尾删

尾部删除其实就比较简单了,只要size>0,他就可以进行删除,我们删除的思想是这样的,我们的数据都是依靠size进行管理的,所以我们只需要让size--就可以了,这样也就访问不到后面的数据了,当然我们判断size>0的时候可以使用一下暴力一点的方式。使用断言。

代码如下

  1. //顺序表的尾删
  2. void SeqListPopBack(SL* ps)
  3. {
  4. assert(ps->size > 0);
  5. ps->size--;
  6. }

测试数据如下

运行结果如下

 6.顺序表的头删

我们已经实现了顺序表的尾删,那么头删呢?其实头删跟头插是非常类似的,下图是我们的流程,从左往右走,让后面的数据覆盖前面的数据即可

 代码实现如下

  1. //顺序表的头删
  2. void SeqListPopFront(SL* ps)
  3. {
  4. assert(ps->size > 0);
  5. int start = 1;
  6. while (start < ps->size)
  7. {
  8. ps->a[start - 1] = ps->a[start];
  9. start++;
  10. }
  11. ps->size--;
  12. }

我们使用如下的测试用例

运行结果为

 7.顺序表任意位置的增加

 其实我们已经了解了顺序表的头插和尾插,那么就想能不能在任意位置都插入一个数据呢,或者任意位置的删除呢?我们应该也是可以实现的,所以我们现在来实现一下任意位置的插入和删除。我们先定义好这两个的函数声明

 我们先来实现任意位置的插入

任意位置的插入其实和头插是极其相似的,只不过结束点从0变成了pos

 代码实现如下

  1. //任意位置的插入
  2. void SeqListInsert(SL* ps, int pos, SQDateType x)
  3. {
  4. assert(pos < ps->size);
  5. SeqListCheckCapacity(ps);
  6. int end = ps->size - 1;
  7. while (pos <= end)
  8. {
  9. ps->a[end + 1] = ps->a[end];
  10. end--;
  11. }
  12. ps->a[pos] = x;
  13. ps->size++;
  14. }

这样的话,我们给一组测试用例

 运行结果为

8.顺序表任意位置的删除

我们接下来来实现一下任意位置的删除,其实这个跟头删也是极其相似的,只不过我们将结束条件变成了pos控制的而已

代码如下

  1. //任意位置的删除
  2. void SeqListEarse(SL* ps, int pos)
  3. {
  4. assert(pos < ps->size);
  5. int start = pos + 1;
  6. while (start < ps->size)
  7. {
  8. ps->a[start - 1] = ps->a[start];
  9. start++;
  10. }
  11. ps->size--;
  12. }

 我们的测试用例如下

 运行结果为

 9.顺序表的销毁

我们最后还需要加上一个销毁顺序表的函数,因为我们的空间都是malloc出来的,必须要还回去,否则会发生内存泄漏

  1. //顺序表的销毁
  2. void SeqListDestory(SL* ps)
  3. {
  4. free(ps->a);
  5. ps->a = NULL;
  6. ps->capacity = ps->size = 0;
  7. }

10.顺序表的查找

增删查改,我们现在就来实现查找

我们先声明好这个函数

然后我们来实现他,实现它也很简单,就是遍历一边他知道找到这个元素,找不到返回-1,找到返回它的下标

代码实现如下

  1. //顺序表的查找
  2. int SeqListFind(SL* ps, SQDateType x)
  3. {
  4. int i = 0;
  5. for (i = 0; i < ps->size; i++)
  6. {
  7. if (ps->a[i] == x)
  8. {
  9. return i;
  10. }
  11. }
  12. return -1;
  13. }

测试用例如下

 运行结果为

 11.顺序表的修改

 接下来就来实现顺序表的修改吧

这是顺序表修改的声明

 代码如下

  1. //顺序表的修改
  2. void SeqListModity(SL* ps, int pos, SQDateType x)
  3. {
  4. assert(pos < ps->size);
  5. ps->a[pos] = x;
  6. }

测试用例

运行结果为

 12.顺序表的菜单

现在,我们已经将一个顺序表的大致功能给解决了,我们接下来就来写一个菜单,将这些功能给整合起来。

菜单很好写,这里就直接给出代码了

  1. void meau()
  2. {
  3. printf("***************************************\n");
  4. printf("**** 请输入你想要执行的操作 ****\n");
  5. printf("**** 1.头插 ****\n");
  6. printf("**** 2.尾插 ****\n");
  7. printf("**** 3.头删 ****\n");
  8. printf("**** 4.尾删 ****\n");
  9. printf("**** 5.任意位置添加 ****\n");
  10. printf("**** 6.任意位置删除 ****\n");
  11. printf("**** 7.查找数据 ****\n");
  12. printf("**** 8.修改数据 ****\n");
  13. printf("**** 9.顺序表置零 ****\n");
  14. printf("**** 10.打印顺序表 ****\n");
  15. printf("**** 0.退出顺序表 ****\n");
  16. printf("***************************************\n");
  17. printf("请输入>:\n");
  18. }
  19. void test()
  20. {
  21. int x = 0;
  22. int pos = 0;
  23. SL s;
  24. SeqListInit(&s);
  25. int input = 0;
  26. do
  27. {
  28. meau();
  29. scanf("%d", &input);
  30. switch (input)
  31. {
  32. case 1:
  33. printf("请输入你头插入的数据:\n");
  34. scanf("%d", &x);
  35. SeqListPushFront(&s, x);
  36. break;
  37. case 2 :
  38. printf("请输入你尾插入的数据:\n");
  39. scanf("%d", &x);
  40. SeqListPushBack(&s, x);
  41. break;
  42. case 3:
  43. printf("执行头删\n");
  44. SeqListPopFront(&s);
  45. break;
  46. case 4:
  47. printf("执行尾删\n");
  48. SeqListPopBack(&s);
  49. break;
  50. case 5:
  51. printf("请输入你需要插入的数据:\n");
  52. scanf("%d", &x);
  53. printf("请输入你需要插入的位置(下标从零开始):\n");
  54. scanf("%d", &pos);
  55. SeqListInsert(&s, pos, x);
  56. break;
  57. case 6:
  58. printf("请输入你需要删除的数据下标(下标从零开始):\n");
  59. scanf("%d", &pos);
  60. SeqListErase(&s, pos);
  61. break;
  62. case 7:
  63. printf("请输入你需要查找的数据:\n");
  64. scanf("%d", &x);
  65. int ret = SeqListFind(&s, x);
  66. printf("该数据的下标是:%d\n", ret);
  67. printf("如果返回值是-1,说明没找到\n");
  68. break;
  69. case 8:
  70. printf("请输入需要修改的下标(下标从零开始):\n");
  71. scanf("%d", &pos);
  72. printf("请输入修改后的数据:\n");
  73. scanf("%d", &x);
  74. SeqListModity(&s, pos, x);
  75. break;
  76. case 9:
  77. SeqListInit(&s);
  78. printf("顺序表已经成功置零了\n");
  79. break;
  80. case 10:
  81. printf("顺序表目前的数据为:\n");
  82. SeqListPrint(&s);
  83. break;
  84. case 0:
  85. printf("即将退出程序,感谢您的使用\n");
  86. break;
  87. default:
  88. printf("输入数据有误,请重新输入!\n");
  89. }
  90. } while (input);
  91. }
  92. int main()
  93. {
  94. test();
  95. return 0;
  96. }

 三、顺序表完整代码

test.c文件

  1. #define _CRT_SECURE_NO_WARNINGS 1
  2. #include"SeqList.h"
  3. void meau()
  4. {
  5. printf("***************************************\n");
  6. printf("**** 请输入你想要执行的操作 ****\n");
  7. printf("**** 1.头插 ****\n");
  8. printf("**** 2.尾插 ****\n");
  9. printf("**** 3.头删 ****\n");
  10. printf("**** 4.尾删 ****\n");
  11. printf("**** 5.任意位置添加 ****\n");
  12. printf("**** 6.任意位置删除 ****\n");
  13. printf("**** 7.查找数据 ****\n");
  14. printf("**** 8.修改数据 ****\n");
  15. printf("**** 9.顺序表置零 ****\n");
  16. printf("**** 10.打印顺序表 ****\n");
  17. printf("**** 0.退出顺序表 ****\n");
  18. printf("***************************************\n");
  19. printf("请输入>:\n");
  20. }
  21. void test()
  22. {
  23. int x = 0;
  24. int pos = 0;
  25. SL s;
  26. SeqListInit(&s);
  27. int input = 0;
  28. do
  29. {
  30. meau();
  31. scanf("%d", &input);
  32. switch (input)
  33. {
  34. case 1:
  35. printf("请输入你头插入的数据:\n");
  36. scanf("%d", &x);
  37. SeqListPushFront(&s, x);
  38. break;
  39. case 2 :
  40. printf("请输入你尾插入的数据:\n");
  41. scanf("%d", &x);
  42. SeqListPushBack(&s, x);
  43. break;
  44. case 3:
  45. printf("执行头删\n");
  46. SeqListPopFront(&s);
  47. break;
  48. case 4:
  49. printf("执行尾删\n");
  50. SeqListPopBack(&s);
  51. break;
  52. case 5:
  53. printf("请输入你需要插入的数据:\n");
  54. scanf("%d", &x);
  55. printf("请输入你需要插入的位置(下标从零开始):\n");
  56. scanf("%d", &pos);
  57. SeqListInsert(&s, pos, x);
  58. break;
  59. case 6:
  60. printf("请输入你需要删除的数据下标(下标从零开始):\n");
  61. scanf("%d", &pos);
  62. SeqListErase(&s, pos);
  63. break;
  64. case 7:
  65. printf("请输入你需要查找的数据:\n");
  66. scanf("%d", &x);
  67. int ret = SeqListFind(&s, x);
  68. printf("该数据的下标是:%d\n", ret);
  69. printf("如果返回值是-1,说明没找到\n");
  70. break;
  71. case 8:
  72. printf("请输入需要修改的下标(下标从零开始):\n");
  73. scanf("%d", &pos);
  74. printf("请输入修改后的数据:\n");
  75. scanf("%d", &x);
  76. SeqListModity(&s, pos, x);
  77. break;
  78. case 9:
  79. SeqListInit(&s);
  80. printf("顺序表已经成功置零了\n");
  81. break;
  82. case 10:
  83. printf("顺序表目前的数据为:\n");
  84. SeqListPrint(&s);
  85. break;
  86. case 0:
  87. printf("即将退出程序,感谢您的使用\n");
  88. break;
  89. default:
  90. printf("输入数据有误,请重新输入!\n");
  91. }
  92. } while (input);
  93. }
  94. int main()
  95. {
  96. test();
  97. return 0;
  98. }

SeqList.h文件

  1. #pragma once
  2. #include<stdio.h>
  3. #include<string.h>
  4. #include<stdlib.h>
  5. #include<assert.h>
  6. //以下是动态的顺序表
  7. typedef int SQDateType;
  8. typedef struct SeqList
  9. {
  10. SQDateType* a; //指向动态开辟的数组
  11. int size; //当前的有效数据个数
  12. int capacity; //容量空间的大小
  13. }SL;
  14. //等价于typedef struct SeqList SL;
  15. //增删查改四大功能的函数接口声明
  16. //初始化
  17. void SeqListInit(SL* ps);
  18. //尾插
  19. void SeqListPushBack(SL* ps, SQDateType x);
  20. //头插
  21. void SeqListPushFront(SL* ps, SQDateType x);
  22. //尾删
  23. void SeqListPopBack(SL* ps);
  24. //头删
  25. void SeqListPopFront(SL* ps);
  26. //打印
  27. void SeqListPrint(SL* ps);
  28. //任意位置的插入
  29. void SeqListInsert(SL* ps, int pos, SQDateType x);
  30. //任意位置的删除
  31. void SeqListErase(SL* ps, int pos);
  32. //销毁顺序表
  33. void SeqListDestory(SL* ps);
  34. //顺序表的查找
  35. int SeqListFind(SL* ps, SQDateType x);
  36. //顺序表的修改
  37. void SeqListModity(SL* ps, int pos, SQDateType x);

SeqList.c文件

  1. #define _CRT_SECURE_NO_WARNINGS 1
  2. #include"SeqList.h"
  3. //以下是动态的顺序表
  4. //顺序表初始化
  5. void SeqListInit(SL* ps)
  6. {
  7. ps->a = NULL;
  8. ps->size = 0;
  9. ps->capacity = 0;
  10. }
  11. //打印数据
  12. void SeqListPrint(SL* ps)
  13. {
  14. int i = 0;
  15. for (i = 0; i < ps->size; i++)
  16. {
  17. printf("%d ", ps->a[i]);
  18. }
  19. printf("\n");
  20. }
  21. //顺序表的销毁
  22. void SeqListDestory(SL* ps)
  23. {
  24. free(ps->a);
  25. ps->a = NULL;
  26. ps->capacity = ps->size = 0;
  27. }
  28. //扩容函数
  29. void SeqListCheckCapacity(SL* ps)
  30. {
  31. //判断是否满了,如果满了,就得扩容了
  32. if (ps->size == ps->capacity)
  33. {
  34. int newcapacity = ps->capacity == 0 ? 4 : ps->capacity * 2;
  35. SQDateType* tmp = (SQDateType*)realloc(ps->a, newcapacity * sizeof(SQDateType));
  36. if (tmp == NULL)
  37. {
  38. printf("realloc fail\n");
  39. exit(-1);
  40. }
  41. else
  42. {
  43. ps->a = tmp;
  44. ps->capacity = newcapacity;
  45. }
  46. }
  47. }
  48. //顺序表尾插
  49. void SeqListPushBack(SL* ps, SQDateType x)
  50. {
  51. SeqListCheckCapacity(ps);
  52. ps->a[ps->size] = x;
  53. ps->size++;
  54. }
  55. //顺序表的头插
  56. void SeqListPushFront(SL* ps, SQDateType x)
  57. {
  58. SeqListCheckCapacity(ps);
  59. int end = ps->size - 1;
  60. while (end >= 0)
  61. {
  62. ps->a[end + 1] = ps->a[end];
  63. end--;
  64. }
  65. ps->a[0] = x;
  66. ps->size++;
  67. }
  68. //顺序表的尾删
  69. void SeqListPopBack(SL* ps)
  70. {
  71. assert(ps->size > 0);
  72. ps->size--;
  73. }
  74. //顺序表的头删
  75. void SeqListPopFront(SL* ps)
  76. {
  77. assert(ps->size > 0);
  78. int start = 1;
  79. while (start < ps->size)
  80. {
  81. ps->a[start - 1] = ps->a[start];
  82. start++;
  83. }
  84. ps->size--;
  85. }
  86. //任意位置的插入
  87. void SeqListInsert(SL* ps, int pos, SQDateType x)
  88. {
  89. assert(pos < ps->size);
  90. SeqListCheckCapacity(ps);
  91. int end = ps->size - 1;
  92. while (pos <= end)
  93. {
  94. ps->a[end + 1] = ps->a[end];
  95. end--;
  96. }
  97. ps->a[pos] = x;
  98. ps->size++;
  99. }
  100. //任意位置的删除
  101. void SeqListErase(SL* ps, int pos)
  102. {
  103. assert(pos < ps->size);
  104. int start = pos + 1;
  105. while (start < ps->size)
  106. {
  107. ps->a[start - 1] = ps->a[start];
  108. start++;
  109. }
  110. ps->size--;
  111. }
  112. //顺序表的查找
  113. int SeqListFind(SL* ps, SQDateType x)
  114. {
  115. int i = 0;
  116. for (i = 0; i < ps->size; i++)
  117. {
  118. if (ps->a[i] == x)
  119. {
  120. return i;
  121. }
  122. }
  123. return -1;
  124. }
  125. //顺序表的修改
  126. void SeqListModity(SL* ps, int pos, SQDateType x)
  127. {
  128. assert(pos < ps->size);
  129. ps->a[pos] = x;
  130. }

总结

好了,本小节就讲解了顺序表的实现,难度可能要比之前c语言要大很多,不过不用担心,只要认真学,一定是可以学会的。加油!,如果对你有帮助的话,那么不要忘记点赞加收藏哦!!!

想看更多精彩内容,那么就赶快来关注我吧!!!

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/Monodyee/article/detail/608843
推荐阅读
相关标签
  

闽ICP备14008679号