当前位置:   article > 正文

数据结构-顺序表详解专题

数据结构-顺序表详解专题

目录

顺序表

1.简单了解顺序表

2.顺序表的分类

2.1静态顺序表

2.2动态顺序表

2.3typedef命名作用

3.动态顺序表的实现

SeqList.h

SeqList.c

test.c


顺序表

1.简单了解顺序表

顺序表是线性表的一种,线性表是在逻辑上是线性结构,在物理逻辑上并不是一定连续的

顺序表的低层结构是数组,对数组的封装,实现了对数据的增删查改等功能。

2.顺序表的分类

顺序表可以分为静态顺序和动态顺序表

2.1静态顺序表

  1. #define MAX 100
  2. typedef int SLDataType;
  3. //静态顺序表
  4. typedef struct SeqList
  5. {
  6. SLDataType a[MAX];//这个是开辟100大小的空间,而不是已经使用有效的空间
  7. int size; //计算存放的有效数据
  8. }SL;

静态顺序表缺陷:空间给少了不够用会造成数据丢失,给多了造成空间浪费。

2.2动态顺序表

  1. //动态顺序表
  2. typedef struct SeqList
  3. {
  4. SLDataType * arr; //类似于数组指针,作为存储数据的低层结构
  5. int capacity;//容量,记录顺序表的空间大小,也就是要开辟的空间大小
  6. int size;//就是记录当前存放了多少有效数据。
  7. }SL;
  8. //两种相同的命名写法。
  9. //typedef sturuct SeqLits SL;

动态顺序表能够实现需要使用空间时候开辟,这样更方便数据的管理,所以推荐用动态顺序表。

2.3typedef命名作用

为什么要用typedef呢

因为当你写int的一堆代码,如果想要把int改成char类型的时候,如果没用到typedeff的话,就要一个一个的改,如果使用了typedef的话直接修改int 换成char就可以了。

3.动态顺序表的实现

分成了三个板块,分别为SeqList.h , SeqList.c ,test.c

SeqList.h

  1. //动态顺序表
  2. typedef struct SeqList
  3. {
  4. SLDataType * arr; //类似于数组指针,作为存储数据的低层结构
  5. int capacity;//容量,记录顺序表的空间大小,也就是要开辟的空间大小
  6. int size;//就是记录当前存放了多少有效数据。
  7. }SL;
  8. //两种相同的命名写法。
  9. //typedef sturuct SeqLits SL;
  10. void SLinit(SL *ps);
  11. void SLPrint(SL* ps); //打印
  12. void SLPushBack(SL * ps ,SLDataType x); //尾插
  13. void SLPushFront(SL* ps, SLDataType x); //头插
  14. void SLCheckcapacity(SL* ps); //扩容
  15. void SLPopBack(SL* ps); //尾删
  16. void SLPopFront(SL* ps); //头删
  17. void SLInsert(SL* ps, int pos, SLDataType x);//指定位置插入
  18. void SLErase(SL* ps, int pos);//指定位置删除
  19. void SLFind(SL* ps, SLDataType x);//查找
  20. void SLDestroy(SL* ps);//销毁
  21. void SLAlter(SL* ps, int pos, SLDataType x);//修改数据

SeqList.c

  1. #include "Sqlist.h"
  2. //初始化
  3. void SLinit(SL* ps)
  4. {
  5. ps->arr = NULL;
  6. ps->capacity = 0;
  7. ps->size = 0;
  8. }
  9. //打印
  10. void SLPrint(SL* ps)
  11. {
  12. for (int i = 0; i < ps->size; i++)
  13. {
  14. printf("%d ", ps->arr[i]);
  15. }
  16. printf("\n");
  17. }
  18. /扩容放在这里,因为等下头插也会用到,设置成公共的,减少代码
  19. void SLCheckcapacity(SL *ps)
  20. {
  21. //扩容
  22. //先判断是不是空间满了
  23. if (ps->size == ps->capacity)
  24. {
  25. //扩容先给arr申请开劈空间 SLDataType * arr;
  26. //realloc头文件 stdlib.h, void realloc (这是要在已有的空间情况下继续扩容,扩容的大小)
  27. //ps->arr = (SLDataType*)realloc(ps->arr,2* ps ->capacity );//扩容22* ps ->capacity
  28. //但是上面这个是不可取的,因为ps ->capacity刚刚被初始化现在为0
  29. //因此要事先判断当 ps ->capacity为0 时,要先赋值,如果不为0 那么开辟2倍的空间
  30. int newcapacity = ps->capacity == 0 ? 4 : 2 * ps->capacity; //三目运算符
  31. /*ps->arr = (SLDataType*)realloc(ps->arr, newcapacity);*/
  32. //这样写还是不够准确,这个时候newcapacity是比特大小,不是字节,
  33. //这个时候要* 一个sizeof(SLDataType),因为要类型的大小字节不同
  34. /*ps->arr = (SLDataType*)realloc(ps->arr, newcapacity * sizeof(SLDataType));*/
  35. //即使这样还是不行,因为你不知道是否申请成功,所以还要创建一个临时变量,然后进行判断realloc是否成功
  36. SLDataType* tmp = (SLDataType*)realloc(ps->arr, newcapacity * sizeof(SLDataType));
  37. //判断realloc是否申请空间成功
  38. if (tmp == NULL)//如果没空那么是没成功
  39. {
  40. perror("realloc fail!"); //这个为啥这么写还真不知道
  41. exit(1); //扩容失败直接中断程序
  42. }
  43. //到这步说明已经申请空间成功
  44. //free(ps->arr);//不需要这个,realloc他会自己销毁
  45. ps->arr = tmp;
  46. ps->capacity = newcapacity;
  47. }
  48. }
  49. //尾插
  50. //参数列表中有一个指向SL结构体的指针ps,
  51. //和一个用来存储数据的参数x。
  52. //函数内部先用assert函数判断st是否为空,
  53. //然后判断栈是否已经满了。如果栈满了,
  54. //就进行扩容操作,将原数组大小翻倍(如果原来大小是0则扩容为4),
  55. //然后利用realoc函数重新分配内存空间,并将原数组中的数据拷贝到新的空间中。,拷贝的时候要销毁空间
  56. //最后将数据x压入栈的顶部,并将栈顶指针top加一。
  57. void SLPushBack(SL* ps, SLDataType x) //用来存储数据的参数x,x是用来插入数据的内容
  58. {
  59. //assert 如果不成立那么会直接中断报错,并且会说明在哪里错误。
  60. //assert(ps);
  61. assert(ps != NULL);
  62. //温柔的判断解决,不会报错
  63. /*if (ps != NULL)
  64. {
  65. return;
  66. }*/
  67. //尾插分为情况
  68. //1.第一个是空间已经满了需要扩容
  69. //2.第二个是还有空间,直接在尾部,也就是ps -> size 位置插入即可。
  70. //空间不够
  71. SLCheckcapacity(ps);
  72. //空间没有满,直接进行尾插
  73. ps->arr[ps->size] = x; //为啥存放到arr里面,那capacity干嘛的
  74. //arr是结构体指针指向的是地址然后用来存放内容的,capacity只是用来存放目前空间大小的容量而已
  75. ps->size++;
  76. }
  77. //头插
  78. void SLPushFront(SL* ps, SLDataType x)
  79. {
  80. //头插也是两种情况,一种是满了要开空间,另一种是没满,要把旧数据往后移动,然后留首位置插入
  81. assert(ps != NULL);
  82. SLCheckcapacity(ps);
  83. //将旧数据往后移动,从后面开始移动
  84. for (int i = ps->size ; i > 0 ; i--) //让i指向size位置。
  85. {
  86. ps->arr[i] = ps->arr[i - 1]; //让i-1位置移动到i位置,就是往后移动一个位置。
  87. }
  88. ps->arr[0] = x; //首位置放新元素,头插
  89. ps->size++;
  90. }
  91. //尾删
  92. void SLPopBack(SL* ps)
  93. {
  94. //两种情况,第一种是全为空,无法删除,第二种是直接可以删尾部数据
  95. assert(ps != NULL);
  96. assert(ps->size != 0);//顺序表不能为空
  97. //进行第二种情况
  98. //ps->arr[ps->size - 1] = NULL;
  99. //size --,那么即使size位置里面有数据,也不会影响打印,插入,删除
  100. //因为默认size位置是不进行处理的。相当于看不见等于没有
  101. ps->size--;
  102. }
  103. void SLPopFront(SL* ps)
  104. {
  105. //两种情况,第一种是全为空,无法删除,第二种是删除头部,把数据往前移动
  106. assert(ps != NULL);
  107. assert(ps->size != 0);//顺序表不能为空
  108. for (int i = 0 ; i < ps ->size -1 ; i++) //因为size要往前移动一个,i最大只能说ps ->size-2
  109. {
  110. ps->arr[i] = ps->arr[i + 1];
  111. }
  112. ps->size--;
  113. }
  114. //在指定位置插入元素
  115. void SLInsert(SL* ps, int pos, SLDataType x)
  116. {
  117. assert(ps);
  118. //要限制pos的大小,不然会出错,pos要小于size,也要大于0
  119. assert(pos >= 0 && pos <= ps->size);
  120. //扩容
  121. SLCheckcapacity(ps);
  122. //首先要知道要插入的pos位置,然后把pos后面的数据往后移动,留pos位置插入
  123. for (int i = ps->size; i > pos; i--)
  124. {
  125. //最后一位size,所以从size开始
  126. ps->arr[i] = ps->arr[i - 1];//固定句式前面丢给后面
  127. }
  128. ps->arr[pos] = x;
  129. ps->size++;
  130. }
  131. //指定位置删除
  132. void SLErase(SL* ps, int pos)
  133. {
  134. assert(ps);
  135. assert(pos >= 0 && pos < ps->size );
  136. //让pos后面的数据往前移动
  137. for (int i = pos ; i < ps->size - 1 ; i++)
  138. {
  139. ps->arr[i] = ps->arr[i + 1];
  140. }
  141. ps->size--;
  142. }
  143. //查找
  144. void SLFind(SL* ps, SLDataType x)
  145. {
  146. assert(ps);//判断顺序表是否为空
  147. for (int i = 0; i < ps->size; i++)
  148. {
  149. if (ps->arr[i] == x)//判断是否有该元素
  150. {
  151. printf("查找成功,该元素下标为%d \n", i);
  152. return;
  153. }
  154. }
  155. //全部查找一遍。
  156. printf("查找失败。不存在该元素。 \n");
  157. }
  158. //销毁
  159. void SLDestroy(SL* ps)
  160. {
  161. //先判断是否为空表,然后释放arr的空间,接着就是让arr指向null
  162. assert(ps);
  163. //if (ps->arr != NULL)
  164. if (ps->arr)
  165. {
  166. free(ps->arr);
  167. }
  168. ps->arr = NULL;
  169. ps->capacity = ps->size = 0;
  170. }
  171. //修改
  172. void SLAlter(SL* ps, int pos, SLDataType x)
  173. {
  174. assert(ps);
  175. //先找到对应的数据,然后修改
  176. for (int i = 0; i < ps->size; i++)
  177. {
  178. if (ps->arr[i] == pos)
  179. {
  180. ps->arr[i] = x;
  181. }
  182. }
  183. }

test.c

  1. #include "Sqlist.h"
  2. void slinit()
  3. {
  4. SL sl;
  5. SLinit(&sl);//ctrl +d 快速复制
  6. //测试尾插
  7. SLPushBack(&sl, 1); //因为是int类型,一开始空间是四个
  8. SLPushBack(&sl, 2);
  9. SLPushBack(&sl, 3);
  10. SLPushBack(&sl, 4);
  11. /*SLPushBack(&sl, 1);
  12. SLPushBack(&sl, 1);*/
  13. SLPrint(&sl);
  14. //当传过去的是null空地址
  15. //SLPushBack(NULL, 4); //传空地址乱码,要用accert判断
  16. /*SLPushBack(&sl, 5);
  17. SLPrint(&sl);*/
  18. //测试头插
  19. SLPushFront(&sl, 5);
  20. SLPushFront(&sl, 6);
  21. SLPushFront(&sl, 7);
  22. SLPrint(&sl);
  23. //测试尾删
  24. /*SLPopBack(&sl);
  25. SLPopBack(&sl);
  26. SLPopBack(&sl);
  27. SLPrint(&sl);*/
  28. //测试头删
  29. SLPopFront(&sl);
  30. SLPopFront(&sl);
  31. SLPrint(&sl);
  32. //测试指定位置插入
  33. SLInsert(&sl, 0, 102);
  34. SLInsert(&sl, 3, 15);
  35. SLInsert(&sl, 4, 22);
  36. SLPrint(&sl);
  37. //测试指定位置删除
  38. SLErase(&sl, 0);
  39. SLErase(&sl, 2);
  40. SLPrint(&sl);
  41. //测试查找
  42. SLFind(&sl, 2);
  43. //测试修改
  44. SLAlter(&sl, 2, 3);
  45. SLPrint(&sl);
  46. //测试销毁
  47. SLDestroy(&sl);
  48. SLPrint(&sl);
  49. }
  50. int main()
  51. {
  52. slinit();
  53. return 0;
  54. }

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

闽ICP备14008679号