深圳幻海软件技术有限公司 欢迎您!

顺序表(更新版)——“数据结构与算法”

2023-05-18

各位CSDN的uu们你们好呀,今天小雅兰又来更新新专栏啦,其实之前我就已经写过了顺序表的内容,只是之前的内容不是最新版的顺序表,现在,我来更新一下最新版的顺序表,下面,就让我们进入更新版的顺序表的世界吧顺序表和小雅兰之前写的三子棋、扫雷、通讯录一样,分为三个文件:https://xiaoyalan.

各位CSDN的uu们你们好呀,今天小雅兰又来更新新专栏啦,其实之前我就已经写过了顺序表的内容,只是之前的内容不是最新版的顺序表,现在,我来更新一下最新版的顺序表,下面,就让我们进入更新版的顺序表的世界吧


顺序表和小雅兰之前写的三子棋、扫雷、通讯录一样,分为三个文件:

https://xiaoyalan.blog.csdn.net/article/details/128705747?spm=1001.2014.3001.5502

https://xiaoyalan.blog.csdn.net/article/details/128717749?spm=1001.2014.3001.5502

https://xiaoyalan.blog.csdn.net/article/details/128717749?spm=1001.2014.3001.5502

https://xiaoyalan.blog.csdn.net/article/details/129788167?spm=1001.2014.3001.5502

https://xiaoyalan.blog.csdn.net/article/details/129896970?spm=1001.2014.3001.5502

test.c——测试代码功能

SeqList.c——顺序表的实现

SeqList.h——顺序表的声明

 https://xiaoyalan.blog.csdn.net/article/details/129380414?spm=1001.2014.3001.5502

这是小雅兰之前写的顺序表的知识,有兴趣的可以去看看


我们写的是一个动态版的顺序表: 

  1. typedef struct SeqList
  2. {
  3. SLDataType* a;
  4. int size;//存储的有效数据的个数
  5. int capacity;//容量
  6. }SL;

把struct SeqList这个结构体重命名为SL

typedef int SLDataType;

 把int重命名为SLDataType

写成这样的形式是因为:如果以后想要修改类型,那就直接改int就可以了,如果不这样写, ​​​​​​要改很多个地方,就很麻烦

顺序表的初始化:

  1. //初始化
  2. void SLInit(SL* ps1)
  3. {
  4. ps1->a = malloc(sizeof(SLDataType) * 4);
  5. if (ps1 == NULL)
  6. {
  7. perror("malloc fail");
  8. return;
  9. }
  10. ps1->size = 0;
  11. ps1->capacity = 4;
  12. }

动态开辟出4个SLDataType类型的大小的空间

 顺序表的销毁:也就是把空间还给操作系统

  1. //销毁
  2. //把空间还给操作系统
  3. void SLDestroy(SL* ps1)
  4. {
  5. free(ps1->a);
  6. ps1->a = NULL;
  7. ps1->size = 0;
  8. ps1->capacity = 0;
  9. }

打印顺序表的内容:

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

尾插:

  1. ps1->a[ps1->size] = x;
  2. ps1->size++;

在这里,我们需要想一个问题:在尾插的过程中,如果空间不够了该怎么办呢???所以在这里,我们还需要一个检查容量的函数,如果容量不够就扩容

  1. //检查容量,容量不够就扩容
  2. void SLCheckCapacity(SL* ps1)
  3. {
  4. if (ps1->size == ps1->capacity)
  5. {
  6. SLDataType* tmp = (SLDataType*)realloc(ps1->a, sizeof(SLDataType) * ps1->capacity * 2);
  7. //扩上一个二倍大小的容量
  8. //这个数值可以自己设定,扩多了不好,扩少了也不好
  9. //所以扩上二倍是最合理的选择
  10. if (tmp == NULL)
  11. {
  12. perror("realloc fail");
  13. return;
  14. }
  15. ps1->a = tmp;
  16. ps1->capacity = ps1->capacity * 2;
  17. }
  18. }
  1. //尾插
  2. void SLPushBack(SL* ps1, SLDataType x)
  3. {
  4. SLCheckCapacity(ps1);
  5. ps1->a[ps1->size] = x;
  6. ps1->size++;
  7. }

下面,我们来测试一下尾插的功能,看是否成功

  1. int main()
  2. {
  3. SL s;
  4. SLInit(&s);
  5. SLPushBack(&s, 1);
  6. SLPushBack(&s, 2);
  7. SLPushBack(&s, 3);
  8. SLPushBack(&s, 4);
  9. SLPushBack(&s, 5);
  10. SLPushBack(&s, 6);
  11. SLPushBack(&s, 7);
  12. SLPushBack(&s, 8);
  13. SLPushBack(&s, 9);
  14. SLPushBack(&s, 10);
  15. SLPrint(&s);
  16. SLDestroy(&s);
  17. return 0;
  18. }

 结果发现,尾插的功能非常成功!!!

头插:

需要从后往前挪动数据!!!

 若是从前往后挪动数据,就会覆盖,这是绝对不行的

  1. //头插
  2. void SLPushFront(SL* ps1, SLDataType x)
  3. {
  4. SLCheckCapacity(ps1);
  5. //挪动数据
  6. int end = ps1->size - 1;
  7. while (end >= 0)
  8. {
  9. ps1->a[end + 1] = ps1->a[end];//把数据往后挪
  10. end--;
  11. }
  12. ps1->a[0] = x;
  13. ps1->size++;
  14. }

来测试一下头插的功能:

  1. //头插测试
  2. void TestSeqList2()
  3. {
  4. SL s;
  5. SLInit(&s);
  6. SLPushBack(&s, 1);
  7. SLPushBack(&s, 2);
  8. SLPushBack(&s, 3);
  9. SLPushBack(&s, 4);
  10. SLPushFront(&s, 5);
  11. SLPushFront(&s, 6);
  12. SLPushFront(&s, 7);
  13. SLPushFront(&s, 8);
  14. SLPushFront(&s, 9);
  15. SLPrint(&s);
  16. SLDestroy(&s);
  17. }

 

 尾删:

 直接把size--就可以了

  1. //尾删
  2. void SLPopBack(SL* ps1)
  3. {
  4. ps1->size--;
  5. }

 来测试一下尾删的功能:

  1. //尾删测试
  2. void TestSeqList3()
  3. {
  4. SL s;
  5. SLInit(&s);
  6. SLPushBack(&s, 1);
  7. SLPushBack(&s, 2);
  8. SLPushBack(&s, 3);
  9. SLPushBack(&s, 4);
  10. SLPushFront(&s, 5);
  11. SLPushFront(&s, 6);
  12. SLPushFront(&s, 7);
  13. SLPushFront(&s, 8);
  14. SLPushFront(&s, 9);
  15. SLPrint(&s);
  16. SLPopBack(&s);
  17. SLPopBack(&s);
  18. SLPopBack(&s);
  19. SLPrint(&s);
  20. SLDestroy(&s);
  21. }

但是这个尾删仍然有点问题,需要检查一下:

  1. //尾删
  2. void SLPopBack(SL* ps1)
  3. {
  4. //温柔的检查
  5. if (ps1->size == 0)
  6. {
  7. return;
  8. }
  9. ps1->size--;
  10. }

  1. //尾删
  2. void SLPopBack(SL* ps1)
  3. {
  4. //暴力的检查
  5. assert(ps1->size > 0);
  6. ps1->size--;
  7. }

 头删:

  1. //头删
  2. void SLPopFront(SL* ps1)
  3. {
  4. //暴力检查
  5. assert(ps1->size > 0);
  6. int start = 0;
  7. while (start < ps1->size - 1)
  8. {
  9. ps1->a[start] = ps1->a[start + 1];
  10. start++;
  11. }
  12. ps1->size--;
  13. }

来测试一下头删的功能:

  1. //头删测试
  2. void TestSeqList4()
  3. {
  4. SL s;
  5. SLInit(&s);
  6. SLPushBack(&s, 1);
  7. SLPushBack(&s, 2);
  8. SLPushBack(&s, 3);
  9. SLPushBack(&s, 4);
  10. SLPushFront(&s, 5);
  11. SLPushFront(&s, 6);
  12. SLPushFront(&s, 7);
  13. SLPushFront(&s, 8);
  14. SLPushFront(&s, 9);
  15. SLPrint(&s);
  16. SLPopBack(&s);
  17. SLPopBack(&s);
  18. SLPopBack(&s);
  19. SLPrint(&s);
  20. SLPopFront(&s);
  21. SLPopFront(&s);
  22. SLPopFront(&s);
  23. SLPrint(&s);
  24. SLDestroy(&s);
  25. }

 

在中间位置插入数据:

  1. //在中间位置(pos)插入数据
  2. void SLInsert(SL* ps1, int pos, SLDataType x)
  3. {
  4. SLCheckCapacity(ps1);
  5. int end = ps1->size - 1;
  6. while (end >= pos)
  7. {
  8. ps1->a[end + 1] = ps1->a[end];
  9. end--;
  10. }
  11. ps1->a[pos] = x;
  12. ps1->size++;
  13. }

写了这个函数的功能之后,我们就可以把之前写的头插和尾插修改一下:

  1. //尾插
  2. void SLPushBack(SL* ps1, SLDataType x)
  3. {
  4. SLInsert(ps1, ps1->size, x);
  5. }
  1. //头插
  2. void SLPushFront(SL* ps1, SLDataType x)
  3. {
  4. SLInsert(ps1, 0, x);
  5. }

但是,这个在中间插入数据的代码还是有点问题;

  1. //中间插数据测试
  2. void TestSeqList5()
  3. {
  4. SL s;
  5. SLInit(&s);
  6. SLPushBack(&s, 1);
  7. SLPushBack(&s, 2);
  8. SLPushBack(&s, 3);
  9. SLPushBack(&s, 4);
  10. SLPushFront(&s, 5);
  11. SLPushFront(&s, 6);
  12. SLPushFront(&s, 7);
  13. SLPushFront(&s, 8);
  14. SLPushFront(&s, 9);
  15. SLPrint(&s);
  16. SLPopBack(&s);
  17. SLPopBack(&s);
  18. SLPopBack(&s);
  19. SLPrint(&s);
  20. SLPopFront(&s);
  21. SLPopFront(&s);
  22. SLPopFront(&s);
  23. SLPrint(&s);
  24. SLInsert(&s, 2, 30);
  25. SLPrint(&s);
  26. SLInsert(&s, 20, 300);
  27. SLPrint(&s);
  28. SLDestroy(&s);
  29. }

从此运行结果可知:越界是不会报错的!!!但是它的的确确越界了!!!

所以把代码改进为:

  1. //在中间位置(pos)插入数据
  2. void SLInsert(SL* ps1, int pos, SLDataType x)
  3. {
  4. assert(pos >= 0 && pos <= ps1->size);
  5. SLCheckCapacity(ps1);
  6. int end = ps1->size - 1;
  7. while (end >= pos)
  8. {
  9. ps1->a[end + 1] = ps1->a[end];
  10. end--;
  11. }
  12. ps1->a[pos] = x;
  13. ps1->size++;
  14. }

在中间位置删除数据:

  1. //在中间位置(pos)删除数据
  2. void SLErase(SL* ps1, int pos)
  3. {
  4. assert(pos >= 0 && pos < ps1->size);
  5. assert(ps1->size > 0);//可有可无
  6. int start = pos + 1;
  7. while (start <= pos + 1)
  8. {
  9. ps1->a[start - 1] = ps1->a[start];
  10. start++;
  11. }
  12. ps1->size--;
  13. }

同样,有了这个功能之后,可以把头删和尾删修改一下:

  1. //头删
  2. void SLPopFront(SL* ps1)
  3. {
  4. SLErase(ps1, 0);
  5. }
  1. //尾删
  2. void SLPopBack(SL* ps1)
  3. {
  4. SLErase(ps1, ps1->size - 1);
  5. }

测试一下从中间删除数据的功能:

  1. //中间删数据测试
  2. void TestSeqList6()
  3. {
  4. SL s;
  5. SLInit(&s);
  6. SLPushBack(&s, 1);
  7. SLPushBack(&s, 2);
  8. SLPushBack(&s, 3);
  9. SLPushBack(&s, 4);
  10. SLPushFront(&s, 5);
  11. SLPushFront(&s, 6);
  12. SLPushFront(&s, 7);
  13. SLPushFront(&s, 8);
  14. SLPushFront(&s, 9);
  15. SLPrint(&s);
  16. SLPopBack(&s);
  17. SLPopBack(&s);
  18. SLPopBack(&s);
  19. SLPrint(&s);
  20. SLPopFront(&s);
  21. SLPopFront(&s);
  22. SLPopFront(&s);
  23. SLPrint(&s);
  24. SLInsert(&s, 2, 30);
  25. SLPrint(&s);
  26. SLErase(&s, 3);
  27. SLPrint(&s);
  28. SLDestroy(&s);
  29. }

 

 查找:

  1. //查找
  2. //找到了返回下标,找不到返回-1
  3. int SLFind(SL* ps1, SLDataType x)
  4. {
  5. int i = 0;
  6. for (i = 0; i < ps1->size; i++)
  7. {
  8. if (ps1->a[i] == x)
  9. {
  10. return i;
  11. }
  12. }
  13. return -1;
  14. }

修改:

  1. //修改
  2. void SLModify(SL* ps1, int pos, SLDataType x)
  3. {
  4. assert(pos >= 0 && pos < ps1->size);
  5. ps1->a[pos] = x;
  6. }

下面,浅浅附上一波源代码:

SeqList.c的内容

  1. #include"SeqList.h"
  2. //初始化
  3. void SLInit(SL* ps1)
  4. {
  5. assert(ps1);
  6. ps1->a = malloc(sizeof(SLDataType) * 4);
  7. if (ps1 == NULL)
  8. {
  9. perror("malloc fail");
  10. return;
  11. }
  12. ps1->size = 0;
  13. ps1->capacity = 4;
  14. }
  15. //销毁
  16. //把空间还给操作系统
  17. void SLDestroy(SL* ps1)
  18. {
  19. assert(ps1);
  20. free(ps1->a);
  21. ps1->a = NULL;
  22. ps1->size = 0;
  23. ps1->capacity = 0;
  24. }
  25. //打印
  26. void SLPrint(SL* ps1)
  27. {
  28. assert(ps1);
  29. int i = 0;
  30. for (i = 0; i < ps1->size; i++)
  31. {
  32. printf("%d ", ps1->a[i]);
  33. }
  34. printf("\n");
  35. }
  36. //检查容量,容量不够就扩容
  37. void SLCheckCapacity(SL* ps1)
  38. {
  39. assert(ps1);
  40. if (ps1->size == ps1->capacity)
  41. {
  42. SLDataType* tmp = (SLDataType*)realloc(ps1->a, sizeof(SLDataType) * ps1->capacity * 2);
  43. //扩上一个二倍大小的容量
  44. //这个数值可以自己设定,扩多了不好,扩少了也不好
  45. //所以扩上二倍是最合理的选择
  46. if (tmp == NULL)
  47. {
  48. perror("realloc fail");
  49. return;
  50. }
  51. ps1->a = tmp;
  52. ps1->capacity = ps1->capacity * 2;
  53. }
  54. }
  55. //在中间位置(pos)插入数据
  56. void SLInsert(SL* ps1, int pos, SLDataType x)
  57. {
  58. assert(ps1);
  59. assert(pos >= 0 && pos <= ps1->size);
  60. SLCheckCapacity(ps1);
  61. int end = ps1->size - 1;
  62. while (end >= pos)
  63. {
  64. ps1->a[end + 1] = ps1->a[end];
  65. end--;
  66. }
  67. ps1->a[pos] = x;
  68. ps1->size++;
  69. }
  70. //在中间位置(pos)删除数据
  71. void SLErase(SL* ps1, int pos)
  72. {
  73. assert(ps1);
  74. assert(pos >= 0 && pos < ps1->size);
  75. assert(ps1->size > 0);//可有可无
  76. int start = pos + 1;
  77. while (start <= pos + 1)
  78. {
  79. ps1->a[start - 1] = ps1->a[start];
  80. start++;
  81. }
  82. ps1->size--;
  83. }
  84. //尾插
  85. void SLPushBack(SL* ps1, SLDataType x)
  86. {
  87. assert(ps1);
  88. /*SLCheckCapacity(ps1);
  89. ps1->a[ps1->size] = x;
  90. ps1->size++;*/
  91. SLInsert(ps1, ps1->size, x);
  92. }
  93. //头插
  94. void SLPushFront(SL* ps1, SLDataType x)
  95. {
  96. assert(ps1);
  97. //SLCheckCapacity(ps1);
  98. 挪动数据
  99. //int end = ps1->size - 1;
  100. //while (end >= 0)
  101. //{
  102. //ps1->a[end + 1] = ps1->a[end];//把数据往后挪
  103. //end--;
  104. //}
  105. //ps1->a[0] = x;
  106. //ps1->size++;
  107. SLInsert(ps1, 0, x);
  108. }
  109. //尾删
  110. void SLPopBack(SL* ps1)
  111. {
  112. assert(ps1);
  113. 温柔的检查
  114. //if (ps1->size == 0)
  115. //{
  116. //return;
  117. //}
  118. //ps1->size--;
  119. //暴力的检查
  120. /*assert(ps1->size > 0);
  121. ps1->size--;*/
  122. SLErase(ps1, ps1->size - 1);
  123. }
  124. //头删
  125. void SLPopFront(SL* ps1)
  126. {
  127. assert(ps1);
  128. //暴力检查
  129. assert(ps1->size > 0);
  130. int start = 0;
  131. while (start < ps1->size - 1)
  132. {
  133. ps1->a[start] = ps1->a[start + 1];
  134. start++;
  135. }
  136. ps1->size--;
  137. //SLErase(ps1, 0);
  138. }
  139. //查找
  140. //找到了返回下标,找不到返回-1
  141. int SLFind(SL* ps1, SLDataType x)
  142. {
  143. assert(ps1);
  144. int i = 0;
  145. for (i = 0; i < ps1->size; i++)
  146. {
  147. if (ps1->a[i] == x)
  148. {
  149. return i;
  150. }
  151. }
  152. return -1;
  153. }
  154. //修改
  155. void SLModify(SL* ps1, int pos, SLDataType x)
  156. {
  157. assert(ps1);
  158. assert(pos >= 0 && pos < ps1->size);
  159. ps1->a[pos] = x;
  160. }

SeqList.h的内容

  1. #pragma once
  2. #include<stdio.h>
  3. #include<stdlib.h>
  4. #include<assert.h>
  5. //动态顺序表
  6. typedef int SLDataType;
  7. typedef struct SeqList
  8. {
  9. SLDataType* a;
  10. int size;//存储的有效数据的个数
  11. int capacity;//容量
  12. }SL;
  13. //初始化
  14. void SLInit(SL* ps1);
  15. //销毁
  16. //把空间还给操作系统
  17. void SLDestroy(SL* ps1);
  18. //打印
  19. void SLPrint(SL* ps1);
  20. //尾插
  21. void SLPushBack(SL* ps1,SLDataType x);
  22. //尾删
  23. void SLPopBack(SL* ps1);
  24. //头插
  25. void SLPushFront(SL* ps1, SLDataType x);
  26. //头删
  27. void SLPopFront(SL* ps1);
  28. //在中间位置(pos)插入数据
  29. void SLInsert(SL* ps1, int pos, SLDataType x);
  30. //在中间位置(pos)删除数据
  31. void SLErase(SL* ps1, int pos);
  32. //查找
  33. //找到了返回下标,找不到返回-1
  34. int SLFind(SL* ps1, SLDataType x);
  35. //修改
  36. void SLModify(SL* ps1, int pos, SLDataType x);

test.c的内容

  1. void menu()
  2. {
  3. printf("***********************************************************\n");
  4. printf("1、尾插数据 2、尾删数据\n");
  5. printf("\n");
  6. printf("3、头插数据 4、头删数据\n");
  7. printf("\n");
  8. printf("5、在任意位置插入数据(位置3插入20)\n");
  9. printf("\n");
  10. printf("6、在任意位置删除数据 \n");
  11. printf("\n");
  12. printf("7、查找某个数据的位置,并删除它 \n");
  13. printf("\n");
  14. printf("8、删除顺序表中有的 某个数据 \n");
  15. printf("\n");
  16. printf("9、打印数据 \n");
  17. printf("\n");
  18. printf("-1、退出 \n");
  19. printf("\n");
  20. printf("***********************************************************\n");
  21. }
  22. int main()
  23. {
  24. printf("************* 欢迎大家来到动态顺序表的测试 **************\n");
  25. int option = 0;
  26. SL s;
  27. SLInit(&s);
  28. do
  29. {
  30. menu();
  31. printf("请输入你的操作:>");
  32. scanf_s("%d", &option);
  33. int sum = 0;
  34. int x = 0;
  35. int y = 0;
  36. int z = 0;
  37. int pos = 0;
  38. int w = 0;
  39. switch (option)
  40. {
  41. case 1:
  42. printf("请依次输入你要尾插的数据:,以-1结束\n");
  43. scanf_s("%d", &sum);
  44. while (sum != -1)
  45. {
  46. SLPushBack(&s, sum); // 1.尾插
  47. scanf_s("%d", &sum);
  48. }
  49. break;
  50. case 2:
  51. SLPopBack(&s); // 2.尾删
  52. break;
  53. case 3:
  54. scanf_s("%d", &x);
  55. SLPushFront(&s, x); // 3.头插
  56. break;
  57. case 4:
  58. SLPopFront(&s); // 4.头删
  59. break;
  60. case 5:
  61. SLInsert(&s, 3, 20); // 5.在任意位置插入数据
  62. break;
  63. case 6:
  64. SLErase(&s, 3); // 6.在任意位置删除数据
  65. break;
  66. case 7:
  67. printf("请输入要删除序列的中的某个数字\n");
  68. scanf_s("%d", &z);
  69. y = SLFind(&s, z); // 7.查找某个数字的位置,并且删除它
  70. printf("%d的位置在%d处: \n", z, y);
  71. if (y != -1)
  72. {
  73. SLErase(&s, y);
  74. }
  75. break;
  76. case 8:
  77. printf("请输入要删除序列的中的数字\n"); //8.删除顺序表中 所有的 某个数据
  78. scanf_s("%d", &w);
  79. pos = SLFind(&s, w, 0);
  80. while (pos != -1)
  81. {
  82. SLErase(&s, pos);
  83. pos = SLFind(&s, w, pos);
  84. }
  85. break;
  86. case 9:
  87. SLPrint(&s);
  88. break;
  89. default:
  90. if (option == -1)
  91. {
  92. exit(0); // 退出程序
  93. }
  94. else
  95. {
  96. printf("输入错误,请重新输入\n");
  97. }
  98. break;
  99. }
  100. } while (option != -1); // 退出程序
  101. SLDestroy(&s);
  102. return 0;
  103. }

好啦,小雅兰今天的顺序表的更新版的内容就到这里啦,继续加油刷题和学习算法噢!!!

文章知识点与官方知识档案匹配,可进一步学习相关知识
算法技能树首页概览46513 人正在系统学习中