当前位置:   article > 正文

C语言实现顺序表_顺序表c语言实现

顺序表c语言实现

前言

数据结构常见的结构有线性结构、树型结构、图形结构。

而线性结构又分为线性表、栈、数组、队列,本文讲的是顺序表,是线性表的一种。

 一、项目

1.1 SeqList.h(头文件)

  1. #pragma once
  2. #include<stdio.h>
  3. #include<assert.h>
  4. #include<stdlib.h>
  5. #define Max_Capacity 10
  6. typedef int SLDateType;
  7. //顺序表
  8. typedef struct SeqList
  9. {
  10. //顺序表地址q
  11. SLDateType* a;
  12. //顺序表的有效长度
  13. int size;
  14. //顺序表大小
  15. int capacity;
  16. }SeqList;
  17. //初始化顺序表
  18. void SeqListInit(SeqList* ps);
  19. //销毁顺序表
  20. void SeqListDestroy(SeqList* ps);
  21. //打印顺序表
  22. void SeqListPrint(SeqList* ps);
  23. //头插
  24. void SeqListPushFront(SeqList* ps, SLDateType x);
  25. //尾插
  26. void SeqListPushBack(SeqList* ps, SLDateType x);
  27. //头删
  28. void SeqListPopFront(SeqList* ps);
  29. //尾删
  30. void SeqListPopBack(SeqList* ps);
  31. //中间插
  32. void SeqListInsert(SeqList* ps, int pos, int x);
  33. //中间删
  34. void SeqListErase(SeqList* ps, int pos);
  35. //检查顺序表是否满了
  36. SLDateType SeqListFull(SeqList* ps);
  37. //顺序表扩容
  38. void SeqListAdd(SeqList* ps);
  39. //顺序表中查数
  40. void SeqListSearch(SeqList* ps, SLDateType x);
  41. //顺序表中改数
  42. void SeqListChange(SeqList* ps, SLDateType x,SLDateType y);

1.2 SeqList.c

  1. #include"SeqList.h"
  2. //初始化顺序表
  3. void SeqListInit(SeqList* ps)
  4. {
  5. ps->a = NULL;
  6. ps->size = 0;
  7. ps->capacity = 0;
  8. }
  9. //打印顺序表
  10. void SeqListPrint(SeqList* ps)
  11. {
  12. assert(ps);
  13. if (ps->size == 0)
  14. {
  15. printf("顺序表无有效数据\n");
  16. return;
  17. }
  18. for (SLDateType i = 0; i < ps->size; i++)
  19. {
  20. printf("%d ", *(ps->a + i));
  21. }
  22. printf("\n");
  23. }
  24. //销毁顺序表
  25. void SeqListDestroy(SeqList* ps)
  26. {
  27. assert(ps);
  28. free(ps->a);
  29. ps->a = NULL;
  30. ps->size = 0;
  31. ps->capacity = 0;
  32. }
  33. //判断顺序表是否满了
  34. SLDateType SeqListFull(SeqList* ps)
  35. {
  36. assert(ps);
  37. if (ps->size == ps->capacity)
  38. {
  39. return 1;
  40. }
  41. return 0;
  42. }
  43. //扩容
  44. void SeqListAdd(SeqList* ps)
  45. {
  46. assert(ps);
  47. ps->a = (SLDateType*)realloc(ps->a,ps->capacity*2*sizeof(SLDateType));
  48. if (ps->a == NULL)
  49. {
  50. perror("realloc error");
  51. exit(-1);
  52. }
  53. ps->capacity *= 2;
  54. }
  55. //头插
  56. void SeqListPushFront(SeqList* ps, SLDateType x)
  57. {
  58. assert(ps);
  59. if (ps->size < 0)
  60. {
  61. ps->size = 0;
  62. }
  63. if (SeqListFull(ps))
  64. {
  65. SeqListAdd(ps);
  66. }
  67. for(SLDateType i = ps->size-1; i >=0; i--)
  68. {
  69. ps->a[i + 1] = ps->a[i];
  70. }
  71. ps->a[0] = x;
  72. ps->size++;
  73. }
  74. //尾插
  75. void SeqListPushBack(SeqList* ps, SLDateType x)
  76. {
  77. assert(ps);
  78. if (ps->size < 0)
  79. {
  80. ps->size = 0;
  81. }
  82. if (SeqListFull(ps))
  83. {
  84. SeqListAdd(ps);
  85. }
  86. ps->a[ps->size] = x;
  87. ps->size++;
  88. }
  89. //头删
  90. void SeqListPopFront(SeqList* ps)
  91. {
  92. assert(ps);
  93. if (ps->size <=0)
  94. {
  95. ps->size = 0;
  96. return;
  97. }
  98. for (SLDateType i = 1; i < ps->size; i++)
  99. {
  100. ps->a[i - 1] = ps->a[i];
  101. }
  102. ps->size--;
  103. }
  104. //尾删
  105. void SeqListPopBack(SeqList* ps)
  106. {
  107. assert(ps);
  108. if (ps->size <= 0)
  109. {
  110. ps->size = 0;
  111. return;
  112. }
  113. ps->size--;
  114. }
  115. //中间插
  116. void SeqListInsert(SeqList* ps,int pos,int x)
  117. {
  118. assert(ps);
  119. if (ps->size <0)
  120. {
  121. ps->size = 0;
  122. }
  123. if (SeqListFull(ps))
  124. {
  125. SeqListAdd(ps);
  126. }
  127. if (pos - 1 < ps->size)
  128. {
  129. for(SLDateType i = ps->size - 1; i >= pos - 1; i--)
  130. ps->a[i + 1] = ps->a[i];
  131. ps->a[pos - 1] = x;
  132. ps->size++;
  133. }
  134. else
  135. printf("插入无效\n");
  136. }
  137. //中间删
  138. void SeqListErase(SeqList* ps, int pos)
  139. {
  140. assert(ps);
  141. if (ps->size <= 0)
  142. {
  143. ps->size = 0;
  144. return;
  145. }
  146. if (pos - 1 < ps->size)
  147. {
  148. for (SLDateType i = pos; i < ps->size; i++)
  149. ps->a[i - 1] = ps->a[i];
  150. ps->size--;
  151. }
  152. else
  153. printf("删除无效\n");
  154. }
  155. //
  156. void SeqListSearch(SeqList* ps, int pos)
  157. {
  158. assert(ps);
  159. if (ps->size <= 0)
  160. {
  161. ps->size = 0;
  162. }
  163. if (pos - 1 < ps->size)
  164. {
  165. printf("%d\n",ps->a[pos - 1]);
  166. return;
  167. }
  168. printf("查找无效\n");
  169. }
  170. //
  171. void SeqListChange(SeqList* ps, int pos, int x)
  172. {
  173. assert(ps);
  174. if (ps->size <= 0)
  175. {
  176. ps->size = 0;
  177. return;
  178. }
  179. if (pos - 1 < ps->size)
  180. {
  181. ps->a[pos - 1] = x;
  182. }
  183. else
  184. printf("修改无效\n");
  185. }

1.3 test.c

  1. #define _CRT_SECURE_NO_WARNINGS 1
  2. #include"SeqList.h"
  3. SLDateType main()
  4. {
  5. //创造顺序表
  6. SeqList sl;
  7. //初始化
  8. SeqListInit(&sl);
  9. sl.capacity = Max_Capacity;
  10. sl.a = (SLDateType*)realloc(sl.a,sl.capacity * sizeof(SLDateType));
  11. if (sl.a == NULL)
  12. {
  13. perror("realloc error");
  14. exit(-1);
  15. }
  16. //尾插012345
  17. for (SLDateType i = 0; i < 5; i++)
  18. SeqListPushBack(&sl, i);
  19. //打印顺序表
  20. SeqListPrint(&sl);
  21. //头插012345
  22. for (SLDateType i = 0; i < 5; i++)
  23. SeqListPushFront(&sl, i);
  24. //再次打印
  25. SeqListPrint(&sl);
  26. //尾删3个数
  27. for (SLDateType i = 0; i < 3; i++)
  28. SeqListPopBack(&sl);
  29. SeqListPrint(&sl);
  30. //头删2个数
  31. for(SLDateType i=0;i<2;i++)
  32. SeqListPopFront(&sl);
  33. SeqListPrint(&sl);
  34. //中间第三个数插入2
  35. SeqListInsert(&sl, 3, 2);
  36. SeqListPrint(&sl);
  37. //中间第三个数删除
  38. SeqListErase(&sl, 3);
  39. SeqListPrint(&sl);
  40. //查找第3个数
  41. SeqListSearch(&sl, 3);
  42. //修改第3个数为100
  43. SeqListChange(&sl, 3, 100);
  44. SeqListPrint(&sl);
  45. //销毁顺序表
  46. SeqListDestroy(&sl);
  47. return 0;
  48. }

二、顺序表的实现

2.1 顺序表

  1. typedef int SLDateType;
  2. //顺序表
  3. typedef struct SeqList
  4. {
  5. //顺序表地址q
  6. SLDateType* a;
  7. //顺序表的有效长度
  8. int size;
  9. //顺序表大小
  10. int capacity;
  11. }SeqList;

创建一个顺序表结构体,成员包含顺序表地址、长度、大小,用于创建顺序表变量。

2.2 初始化顺序表

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

 将顺序表变量的地址传参,通过指针接收对顺序表的顺序表数组初始化为空,长度为0,大小为0。

2.3 打印顺序表

  1. //打印顺序表
  2. void SeqListPrint(SeqList* ps)
  3. {
  4. assert(ps);
  5. if (ps->size == 0)
  6. {
  7. printf("顺序表无有效数据\n");
  8. return;
  9. }
  10. for (SLDateType i = 0; i < ps->size; i++)
  11. {
  12. printf("%d ", *(ps->a + i));
  13. }
  14. printf("\n");
  15. }

同样传地址,要先断言指针是否为空,不然会出异常。

然后判断顺序表大小是否为0,为0则代表顺序表中没有有效元素,打印提示,并返回函数,如果大于0,则有元素,从下标0开始,打印size个顺序表元素,并用空格相隔。

2.4 销毁顺序表

  1. //销毁顺序表
  2. void SeqListDestroy(SeqList* ps)
  3. {
  4. assert(ps);
  5. free(ps->a);
  6. ps->a = NULL;
  7. ps->size = 0;
  8. ps->capacity = 0;
  9. }

当我们结束程序时,因为我们是通过动态分配空间给顺序表,所以结束时我们要手动销毁,先断言,防止free空指针,成功释放空间后,将ps->a手动置空,避免产生野指针,并将大小、空间赋0。

三、对顺序表进行操作

3.1 在顺序表的头部插入数据

  1. //头插
  2. void SeqListPushFront(SeqList* ps, SLDateType x)
  3. {
  4. assert(ps);
  5. if (ps->size < 0)
  6. {
  7. ps->size = 0;
  8. }
  9. if (SeqListFull(ps))
  10. {
  11. SeqListAdd(ps);
  12. }
  13. for(SLDateType i = ps->size-1; i >=0; i--)
  14. {
  15. ps->a[i + 1] = ps->a[i];
  16. }
  17. ps->a[0] = x;
  18. ps->size++;
  19. }

在头部插入数据,要先判断容量是否已满,如果已满,需要扩容,还有空间,那么就从下标为ps->size-1开始,到0上的值都要将前一个元素给覆盖,而将要插入的数据覆盖给下标为0的空间,长度加1。

3.2 在顺序表末尾插入数据

  1. //尾插
  2. void SeqListPushBack(SeqList* ps, SLDateType x)
  3. {
  4. assert(ps);
  5. if (ps->size < 0)
  6. {
  7. ps->size = 0;
  8. }
  9. if (SeqListFull(ps))
  10. {
  11. SeqListAdd(ps);
  12. }
  13. ps->a[ps->size] = x;
  14. ps->size++;
  15. }

都是插入数据,所以前面的操作和头插一致,但是尾插要比头插看起来方便,因为只要在顺序表后一个空间内插入要插入的数据,不需要移动数据,并将长度+1。

3.3 删除在顺序表头部的数

  1. //头删
  2. void SeqListPopFront(SeqList* ps)
  3. {
  4. assert(ps);
  5. if (ps->size <=0)
  6. {
  7. ps->size = 0;
  8. return;
  9. }
  10. for (SLDateType i = 1; i < ps->size; i++)
  11. {
  12. ps->a[i - 1] = ps->a[i];
  13. }
  14. ps->size--;
  15. }

判断部分不需要判断容量是否够,且长度不能为负数。

和头插相反,我们要从下标为1,到ps->size-1,将前一个数覆盖,长度减1。

3.4 删除在顺序表末尾的数

  1. //尾删
  2. void SeqListPopBack(SeqList* ps)
  3. {
  4. assert(ps);
  5. if (ps->size <= 0)
  6. {
  7. ps->size = 0;
  8. return;
  9. }
  10. ps->size--;
  11. }

判断部分一致,尾删只需将长度减一即可。

3.5 在顺序表中间位置插入数据

  1. //中间插
  2. void SeqListInsert(SeqList* ps,int pos,int x)
  3. {
  4.     assert(ps);
  5.     if (ps->size <0)
  6.     {
  7.         ps->size = 0;
  8.     }
  9.     if (SeqListFull(ps))
  10.     {
  11.         SeqListAdd(ps);
  12.     }
  13.     if (pos - 1 < ps->size)
  14.     {
  15.         for(SLDateType i = ps->size - 1; i >= pos - 1; i--)
  16.             ps->a[i + 1] = ps->a[i];
  17.         ps->a[pos - 1] = x;
  18.         ps->size++;
  19.     }
  20.     else
  21.         printf("插入无效\n");
  22. }

中间插比较麻烦,不仅要断言,判断ps->size是否合理,容量是否够,还要判断所给插入数据下标位置是否在0到ps->size之间的合法区域,所以以上同时合法时, 才能实现插入数据,和头插相似,它们都是先从尾部数据开始,先向右整体覆盖过去,但是头插是到0停止,而中间插是到所给下标停止,并将该下标的数插入为想插入的数据,长度加1。

3.6 在顺序表中间位置删除数据

  1. //中间删
  2. void SeqListErase(SeqList* ps, int pos)
  3. {
  4. assert(ps);
  5. if (ps->size <= 0)
  6. {
  7. ps->size = 0;
  8. return;
  9. }
  10. if (pos - 1 < ps->size)
  11. {
  12. for (SLDateType i = pos; i < ps->size; i++)
  13. ps->a[i - 1] = ps->a[i];
  14. ps->size--;
  15. }
  16. else
  17. printf("删除无效\n");
  18. }

和头删相似,将指定下标左边的元素往左移动一个空间,长度减1。

3.7 在顺序表中查找指定下标的值

  1. //
  2. void SeqListSearch(SeqList* ps, int pos)
  3. {
  4. assert(ps);
  5. if (ps->size <= 0)
  6. {
  7. ps->size = 0;
  8. }
  9. if (pos - 1 < ps->size)
  10. {
  11. printf("%d\n",ps->a[pos - 1]);
  12. return;
  13. }
  14. printf("查找无效\n");
  15. }

返回指定下标下的值,比较容易实现。

3.8 将顺序表指定下标的值修改

  1. //
  2. void SeqListChange(SeqList* ps, int pos, int x)
  3. {
  4. assert(ps);
  5. if (ps->size <= 0)
  6. {
  7. ps->size = 0;
  8. return;
  9. }
  10. if (pos - 1 < ps->size)
  11. {
  12. ps->a[pos - 1] = x;
  13. }
  14. else
  15. printf("修改无效\n");
  16. }

找到指定下标的位置,直接赋给修改的值即可,也很容易实现。

3.9 顺序表的扩容

  1. /判断顺序表是否满了
  2. SLDateType SeqListFull(SeqList* ps)
  3. {
  4. assert(ps);
  5. if (ps->size == ps->capacity)
  6. {
  7. return 1;
  8. }
  9. return 0;
  10. }
  11. //扩容
  12. void SeqListAdd(SeqList* ps)
  13. {
  14. assert(ps);
  15. ps->a = (SLDateType*)realloc(ps->a,ps->capacity*2*sizeof(SLDateType));
  16. if (ps->a == NULL)
  17. {
  18. perror("realloc error");
  19. exit(-1);
  20. }
  21. ps->capacity *= 2;
  22. }

如果ps->size等于容量,代表容量已满,则将容量扩大为原来的两倍,但是可能会出现内存泄漏的情况,严谨一点应该在realloc完后将地址赋给一个新指针,由新指针判断不为空,再赋给顺序表指针,如果扩容失败,程序将会终止。

四、实现程序

  1. #define _CRT_SECURE_NO_WARNINGS 1
  2. #include"SeqList.h"
  3. SLDateType main()
  4. {
  5. //创造顺序表
  6. SeqList sl;
  7. //初始化
  8. SeqListInit(&sl);
  9. sl.capacity = Max_Capacity;
  10. sl.a = (SLDateType*)realloc(sl.a,sl.capacity * sizeof(SLDateType));
  11. if (sl.a == NULL)
  12. {
  13. perror("realloc error");
  14. exit(-1);
  15. }
  16. //尾插01234
  17. for (SLDateType i = 0; i < 5; i++)
  18. SeqListPushBack(&sl, i);
  19. //打印顺序表
  20. SeqListPrint(&sl);
  21. //头插01234
  22. for (SLDateType i = 0; i < 5; i++)
  23. SeqListPushFront(&sl, i);
  24. //再次打印
  25. SeqListPrint(&sl);
  26. //尾删3个数
  27. for (SLDateType i = 0; i < 3; i++)
  28. SeqListPopBack(&sl);
  29. SeqListPrint(&sl);
  30. //头删2个数
  31. for(SLDateType i=0;i<2;i++)
  32. SeqListPopFront(&sl);
  33. SeqListPrint(&sl);
  34. //中间第三个数插入2
  35. SeqListInsert(&sl, 3, 2);
  36. SeqListPrint(&sl);
  37. //中间第三个数删除
  38. SeqListErase(&sl, 3);
  39. SeqListPrint(&sl);
  40. //查找第3个数
  41. SeqListSearch(&sl, 3);
  42. //修改第3个数为100
  43. SeqListChange(&sl, 3, 100);
  44. SeqListPrint(&sl);
  45. //销毁顺序表
  46. SeqListDestroy(&sl);
  47. return 0;
  48. }

用SeqList.c的函数实现我们对顺序表sl的一系列操作,结束时销毁顺序表。

打印结果如下

本文内容由网友自发贡献,转载请注明出处:【wpsshop博客】
推荐阅读
相关标签
  

闽ICP备14008679号