当前位置:   article > 正文

C语言【数据结构】顺序表(动态开辟)实现_c语言 列表结构体 开辟空间

c语言 列表结构体 开辟空间

目录

1.创建结构体

2.初始化

3.尾插(需判断是否要扩容)

4.尾删

5.头插

6.头删

7.插入

8.删除

9.查找

10.修改

11.销毁

12.打印

一.SeqList.h

二.SeqList.c

三.Test.c

四.用Insert和Erase代替尾插尾删头插头删


顺序表OJ题练习:C语言【数据结构】顺序表【OJ题(C++)练习】_糖果雨滴a的博客-CSDN博客

前言:这是数据结构的开始,顺序表。现在已经开始学数据结构了,学数据结构最重要的3点是

①善于画图,多画图思考

②一定要细心

③勤加练习

好了,现在开始顺序表的学习了:

1.创建结构体

首先呢,要想创建一个顺序表,首先我们可以创建3个文件分别为SeqList.h, SeqList.c, Test.c

接下来我们就首先要创建一个结构体:

  1. typedef int SLDataType
  2. typedef struct SeqList
  3. {
  4. SLDataType* a;//指向动态开辟的数组
  5. int size;//存储数据个数
  6. int capacity;//存储空间大小
  7. }SeqList;

而在创建结构体的时候,我们会发现如果我们定义动态开辟的空间为int类型,那么我们只能存放int类型的数据,而想要修改,就必须把之后的int都修改一遍,很麻烦。因此我们可以用typedef用SLDataType作为数据类型。

2.初始化

创建顺序表首先要初始化。这里为什么用SeqList* psl,在3里详细说明。

  1. void SeqListInit(SeqList* psl)
  2. {
  3. assert(psl);
  4. psl->a = NULL;
  5. psl->size = 0;
  6. psl->capacity = 0;
  7. }

3.尾插(需判断是否要扩容)

我们想要创建一个顺序表,那么就应该有增删查改。我们先来完成尾插。首先在Test.c创建一个main函数,然后可以用多个TestSeqList去测试写的对错。

然后呢,我们创建一个TestSeqList1,然后在里面定义结构体类型变量,SeqList s。接下来就创建尾插函数,并传参。然后再创建一个函数来打印顺序表,验证对错。

当我们实参为s的时候,我们会发现无论插入什么数,顺序表都为空,这是因为实参为s,而传过去的形参是临时创建的,出函数即销毁。因此我们应该传地址,即&s,这样实参和形参的地址一样,改形参的时候,实参也会被改,因此就可以输入数据了。

实现尾插很简单,只要通过当前size的值就可以,同时每插入一个,size++。但是我们应该注意扩容的问题,如果数据过多,需要扩容,而该扩容应该多次使用,因此我们可以创建SeqListCheckCapacity函数来判断是否需要扩容。

  1. void SeqListCheckCapacity(SeqList* psl)
  2. {
  3. assert(psl);
  4. if (psl->size == psl->capacity)
  5. {
  6. size_t newCapacity = psl->capacity == 0 ? 4 : psl->capacity * 2;
  7. SLDataType* tmp = realloc(psl->a, sizeof(SLDataType) * newCapacity);
  8. if (tmp == NULL)
  9. {
  10. printf("realloc fail\n");
  11. exit(-1);
  12. }
  13. else
  14. {
  15. psl->a = tmp;
  16. psl->capacity = newCapacity;
  17. }
  18. }
  19. }
  1. void SeqListsPushBack(SeqList* psl, SLDataType x)
  2. {
  3. assert(psl);
  4. SeqListCheckCapacity(psl);
  5. psl->a[psl->size] = x;
  6. ++psl->size;
  7. }

assert(psl)是为了防止传过来空指针导致出错,而我们不知道在哪出错,有了assert传空指针时会告诉我们在哪出错,因此我们都应该加上assert断言。

4.尾删

尾删也很简单。每次让size--就行。要注意size > 0,否则会导致后面的插入出错。

  1. void SeqListPopBack(SeqList* psl)
  2. {
  3. assert(psl);
  4. if (psl->size > 0)
  5. {
  6. --psl->size;
  7. }
  8. }

5.头插

头插和头删相对于尾插和尾删要复杂一些,并且尾插和尾删的时间复杂度为O(1),而头插和头删的时间复杂度为O(N)。

我们想要头插一个数,可以先把原来其中的数向后依次挪动,然后再插入该数。

  1. void SeqListPushFront(SeqList* psl, SLDataType x)
  2. {
  3. assert(psl);
  4. SeqListCheckCapacity(psl);
  5. int end = psl->size - 1;
  6. while (end >= 0)
  7. {
  8. psl->a[end + 1] = psl->a[end];
  9. --end;
  10. }
  11. psl->a[0] = x;
  12. ++psl->size;
  13. }

6.头删

头删正好与头插相反,头删应该把数依次向前挪动,覆盖第一个数据。

  1. void SeqListPopFront(SeqList* psl)
  2. {
  3. assert(psl);
  4. int begin = 1;
  5. if(psl->size > 0)
  6. {
  7. while (begin < psl->size)
  8. {
  9. psl->a[begin - 1] = psl->a[begin];
  10. ++begin;
  11. }
  12. --psl->size;
  13. }
  14. }

7.插入

插入与头插类似,但是因为pos的存在,我们需要判断pos的值是否越界。

同时因为size_t的原因,我们要注意,不要让end变成负数,否则因为size的原因,会导致负数变成一个非常大的正数,导致出错。

  1. void SeqListInsert(SeqList* psl, size_t pos, SLDataType x)
  2. {
  3. assert(psl);
  4. if (pos > psl->size)
  5. {
  6. printf("pos 越界: %d\n", pos);
  7. return;
  8. }
  9. SeqListCheckCapacity(psl);
  10. size_t end = psl->size;
  11. while (end > pos)
  12. {
  13. psl->a[end] = psl->a[end - 1];
  14. end--;
  15. }
  16. psl->a[pos] = x;
  17. ++psl->size;
  18. }

8.删除

删除与头删类似。

  1. void SeqListErase(SeqList* psl, size_t pos)
  2. {
  3. assert(psl);
  4. assert(pos < psl->size);
  5. size_t begin = pos + 1;
  6. while (begin < psl->size)
  7. {
  8. psl->a[begin - 1] = psl->a[begin];
  9. ++begin;
  10. }
  11. --psl->size;
  12. }

9.查找

这个很简单。

  1. int SeqListFind(SeqList* psl, SLDataType x)
  2. {
  3. assert(psl);
  4. for (int i = 0; i < psl->size; ++i)
  5. {
  6. if (psl->a[i] == x)
  7. {
  8. return i;
  9. }
  10. }
  11. return -1;
  12. }

10.修改

也很简单。也要注意pos的值。

  1. void SeqListModify(SeqList* psl, size_t pos, SLDataType x)
  2. {
  3. assert(psl);
  4. assert(pos < psl->size);
  5. psl->a[pos] = x;
  6. }

11.销毁

销毁顺序表,变为初始状态

  1. void SeqListDestory(SeqList* psl)
  2. {
  3. assert(psl);
  4. free(psl->a);
  5. psl->a = NULL;
  6. psl->size = 0;
  7. psl->capacity = 0;
  8. }

12.打印

遍历打印即可

  1. void SeqListPrint(SeqList* psl)
  2. {
  3. assert(psl);
  4. for (int i = 0; i < psl->size; ++i)
  5. {
  6. printf("%d ", psl->a[i]);
  7. }
  8. printf("\n");
  9. }

一.SeqList.h

  1. #pragma once
  2. #include <stdio.h>
  3. #include <stdlib.h>
  4. #include <assert.h>
  5. typedef int SLDataType;
  6. typedef struct SeqList
  7. {
  8. SLDataType* a;
  9. int size;
  10. int capacity;
  11. }SeqList;
  12. void SeqListInit(SeqList* psl);
  13. void SeqListDestory(SeqList* psl);
  14. void SeqListPrint(SeqList* psl);
  15. void SeqListCheckCapacity(SeqList* psl);
  16. void SeqListsPushBack(SeqList* psl, SLDataType x);
  17. void SeqListPopBack(SeqList* psl);
  18. void SeqListPushFront(SeqList* psl, SLDataType x);
  19. void SeqListPopFront(SeqList* psl);
  20. void SeqListInsert(SeqList* psl, size_t pos, SLDataType x);
  21. void SeqListErase(SeqList* psl, size_t x);
  22. int SeqListFind(SeqList* psl, SLDataType x);
  23. void SeqListModify(SeqList* psl, size_t pos, SLDataType x);

二.SeqList.c

  1. #include "SeqList.h"
  2. void SeqListInit(SeqList* psl)
  3. {
  4. assert(psl);
  5. psl->a = NULL;
  6. psl->size = 0;
  7. psl->capacity = 0;
  8. }
  9. void SeqListDestory(SeqList* psl)
  10. {
  11. assert(psl);
  12. free(psl->a);
  13. psl->a = NULL;
  14. psl->size = 0;
  15. psl->capacity = 0;
  16. }
  17. void SeqListPrint(SeqList* psl)
  18. {
  19. assert(psl);
  20. for (int i = 0; i < psl->size; ++i)
  21. {
  22. printf("%d ", psl->a[i]);
  23. }
  24. printf("\n");
  25. }
  26. void SeqListCheckCapacity(SeqList* psl)
  27. {
  28. assert(psl);
  29. if (psl->size == psl->capacity)
  30. {
  31. size_t newCapacity = psl->capacity == 0 ? 4 : psl->capacity * 2;
  32. SLDataType* tmp = realloc(psl->a, sizeof(SLDataType) * newCapacity);
  33. if (tmp == NULL)
  34. {
  35. printf("realloc fail\n");
  36. exit(-1);
  37. }
  38. else
  39. {
  40. psl->a = tmp;
  41. psl->capacity = newCapacity;
  42. }
  43. }
  44. }
  45. void SeqListsPushBack(SeqList* psl, SLDataType x)
  46. {
  47. assert(psl);
  48. SeqListCheckCapacity(psl);
  49. psl->a[psl->size] = x;
  50. ++psl->size;
  51. }
  52. void SeqListPopBack(SeqList* psl)
  53. {
  54. assert(psl);
  55. if (psl->size > 0)
  56. {
  57. --psl->size;
  58. }
  59. }
  60. void SeqListPushFront(SeqList* psl, SLDataType x)
  61. {
  62. assert(psl);
  63. SeqListCheckCapacity(psl);
  64. int end = psl->size - 1;
  65. while (end >= 0)
  66. {
  67. psl->a[end + 1] = psl->a[end];
  68. --end;
  69. }
  70. psl->a[0] = x;
  71. ++psl->size;
  72. }
  73. void SeqListPopFront(SeqList* psl)
  74. {
  75. assert(psl);
  76. int begin = 1;
  77. if(psl->size > 0)
  78. {
  79. while (begin < psl->size)
  80. {
  81. psl->a[begin - 1] = psl->a[begin];
  82. ++begin;
  83. }
  84. --psl->size;
  85. }
  86. }
  87. void SeqListInsert(SeqList* psl, size_t pos, SLDataType x)
  88. {
  89. assert(psl);
  90. if (pos > psl->size)
  91. {
  92. printf("pos 越界: %d\n", pos);
  93. return;
  94. }
  95. SeqListCheckCapacity(psl);
  96. size_t end = psl->size;
  97. while (end > pos)
  98. {
  99. psl->a[end] = psl->a[end - 1];
  100. end--;
  101. }
  102. psl->a[pos] = x;
  103. ++psl->size;
  104. }
  105. void SeqListErase(SeqList* psl, size_t pos)
  106. {
  107. assert(psl);
  108. assert(pos < psl->size);
  109. size_t begin = pos + 1;
  110. while (begin < psl->size)
  111. {
  112. psl->a[begin - 1] = psl->a[begin];
  113. ++begin;
  114. }
  115. --psl->size;
  116. }
  117. int SeqListFind(SeqList* psl, SLDataType x)
  118. {
  119. assert(psl);
  120. for (int i = 0; i < psl->size; ++i)
  121. {
  122. if (psl->a[i] == x)
  123. {
  124. return i;
  125. }
  126. }
  127. return -1;
  128. }
  129. void SeqListModify(SeqList* psl, size_t pos, SLDataType x)
  130. {
  131. assert(psl);
  132. assert(pos < psl->size);
  133. psl->a[pos] = x;
  134. }

三.Test.c

  1. #include "SeqList.h"
  2. TestSeqList1()
  3. {
  4. SeqList s;
  5. SeqListInit(&s);
  6. SeqListsPushBack(&s, 1);
  7. SeqListsPushBack(&s, 2);
  8. SeqListsPushBack(&s, 3);
  9. SeqListsPushBack(&s, 4);
  10. SeqListsPushBack(&s, 5);
  11. SeqListsPushBack(&s, 0);
  12. SeqListPrint(&s);
  13. SeqListPopBack(&s);
  14. SeqListPopBack(&s);
  15. SeqListPopBack(&s);
  16. SeqListPopBack(&s);
  17. SeqListPopBack(&s);
  18. SeqListPopBack(&s);
  19. SeqListPopBack(&s);
  20. SeqListPrint(&s);
  21. SeqListsPushBack(&s, 10);
  22. SeqListsPushBack(&s, 20);
  23. SeqListPrint(&s);
  24. SeqListDestory(&s);
  25. }
  26. TestSeqList2()
  27. {
  28. SeqList s;
  29. SeqListInit(&s);
  30. SeqListsPushBack(&s, 1);
  31. SeqListsPushBack(&s, 2);
  32. SeqListsPushBack(&s, 3);
  33. SeqListsPushBack(&s, 4);
  34. SeqListPrint(&s);
  35. SeqListPushFront(&s, 0);
  36. SeqListPushFront(&s, -1);
  37. SeqListPrint(&s);
  38. SeqListPopFront(&s);
  39. SeqListPopFront(&s);
  40. SeqListPopFront(&s);
  41. SeqListPopFront(&s);
  42. SeqListPopFront(&s);
  43. SeqListPopFront(&s);
  44. SeqListPopFront(&s);
  45. SeqListPopFront(&s);
  46. SeqListPushFront(&s, 10);
  47. SeqListPushFront(&s, 20);
  48. SeqListPrint(&s);
  49. }
  50. TestSeqList3()
  51. {
  52. SeqList s;
  53. SeqListInit(&s);
  54. SeqListsPushBack(&s, 1);
  55. SeqListsPushBack(&s, 2);
  56. SeqListsPushBack(&s, 3);
  57. SeqListsPushBack(&s, 4);
  58. SeqListPrint(&s);
  59. SeqListInsert(&s, 4, 10);
  60. SeqListInsert(&s, 2, 20);
  61. SeqListInsert(&s, 0, 30);
  62. SeqListPrint(&s);
  63. SeqListErase(&s, 6);
  64. SeqListErase(&s, 0);
  65. SeqListErase(&s, 2);
  66. SeqListPrint(&s);
  67. }
  68. TestSeqList4()
  69. {
  70. SeqList s;
  71. SeqListInit(&s);
  72. SeqListsPushBack(&s, 1);
  73. SeqListsPushBack(&s, 2);
  74. SeqListsPushBack(&s, 3);
  75. SeqListsPushBack(&s, 4);
  76. SeqListPrint(&s);
  77. int ret = SeqListFind(&s, 4);
  78. printf("%d", ret);
  79. }
  80. int main()
  81. {
  82. TestSeqList1();
  83. TestSeqList2();
  84. TestSeqList3();
  85. TestSeqList4();
  86. return 0;
  87. }

测试结果:

四.用Insert和Erase代替尾插尾删头插头删

最后,因为学了插入和删除,我们可以用它们代替尾插尾删头插头删。如下:

  1. void SeqListsPushBack(SeqList* psl, SLDataType x)
  2. {
  3. assert(psl);
  4. SeqListInsert(psl, psl->size, x);
  5. }
  1. void SeqListPopBack(SeqList* psl)
  2. {
  3. assert(psl);
  4. SeqListErase(psl, psl->size - 1);
  5. }
  1. void SeqListPushFront(SeqList* psl, SLDataType x)
  2. {
  3. assert(psl);
  4. SeqListInsert(psl, 0, x);
  5. }
  1. void SeqListPopFront(SeqList* psl)
  2. {
  3. assert(psl);
  4. SeqListErase(psl, 0);
  5. }

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

闽ICP备14008679号