当前位置:   article > 正文

【C语言】顺序表(原理+实现)_顺序表长度的原理是什么

顺序表长度的原理是什么

一.原理

1.线性表、顺序表

线性表(Linear list)是n个具有相同特性的数据元素的有限序列。线性表在逻辑上是线性结构,就如同一条连续的直线,但是在物理结构上不一定是连续的。

顺序表(Sequence list)是线性表的一种,但顺序表不仅在逻辑上是线性的,它在物理上同样是线性的。顺序表的底层结构是数组,数组本身就是同一类型数据的集合,顺序表在对数组的封装上实现了常用的增删改查等接口。

2.静态顺序表

静态顺序表的实现如下,在一个自定义结构体SL中定义一个定长数组和已用长度size,在对顺序表进行增删时size(也就是当前数组元素个数进行加减),但之所以叫作静态顺序表,就是因为在开始数组的大小就被给定了(就是MAX),数据最多只能存储到MAX个,因此MAX的大小设置成了问题,空间给少了不够用,给多了造成空间浪费,因此就有了动态顺序表。

3.动态顺序表

动态顺序表在静态的基础上,将定长数组改为一个指针,这样对于就能使用realloc函数合理地进行扩容,并且容量(capacity)也能随时变化,做到了动态地变化。

二.实现

1.初始化、销毁

在进行实现之前需要注意一点:结构体传参的时候,要传结构体的地址。(这点在我之前结构体的文章介绍过)不仅是由于压栈,在如下顺序表初始化的函数中,需要给结构体成员赋值,只有指针能做到,传值的话只能改变形式参数,无法达到效果。

无论是初始化还是销毁,只要传参传的地址,先使用assert对其进行断言保障安全性,初始化指针赋NULL,元素个数size和容量都为0即可。销毁时需要释放动态开辟的空间,并且将指针赋NULL。

  1. //初始化
  2. void SLInit(SL* ps)
  3. {
  4. assert(ps);
  5. ps->arr = NULL;
  6. ps->size = ps->capacity = 0;
  7. }
  8. //销毁
  9. void SLDestroy(SL* ps)
  10. {
  11. assert(ps);
  12. assert(ps->arr);
  13. free(ps->arr);
  14. ps->arr = NULL;
  15. ps->size = ps->capacity = 0;
  16. }

2.打印

打印需要分不同的类型,在之前的结构体定义前对类型统一命名为SLdatatype,方便修改和阅览。如果对SLdatatype重命名的是int,那么此时的打印方式就以int的形式进行。

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

3.头插、尾插

在正式进行插入前,首先要进行容量判定,如果容量不够怎么能成功插入呢?如果不够就进行扩容,在扩容时选择一个标准,一般是成倍数的进行扩容(2倍,3倍),这样能较好的节约空间并且也能足够使用。在此作者选择2倍扩容,不过在最开始(即ps->capacity = 0)时先扩容四个元素大小,检查容量是否足够就是检查capacity是否等于size。

  1. //容量检查、扩容
  2. void SLcheckcapacity(SL* ps)
  3. {
  4. assert(ps);
  5. if (ps->capacity == ps->size)
  6. {
  7. int newspace = ps->capacity == 0 ? 4 : 2 * ps->capacity;
  8. SLdatatpye* tmp = (SLdatatpye*)realloc(ps->arr, newspace * sizeof(SLdatatpye));
  9. if (tmp == NULL)
  10. {
  11. perror("realloc");
  12. exit(1);
  13. }
  14. ps->arr = tmp;
  15. ps->capacity = newspace;
  16. }
  17. }

 头插,需要把每个元素往后移动一位,使用for循环实现,随后在第一位插入输入的值,最后不要忘了size++,只要是插入建议先写size++防止忘记。尾插则更为简单,只需要在size出赋值就行。不过需要知道,size是代表元素个数,而元素个数要是表示下标,那就是最后一个元素的后一位。

  1. //头插
  2. void SLPushfront(SL* ps, SLdatatpye value)
  3. {
  4. assert(ps);
  5. SLcheckcapacity(ps);
  6. for (int i = ps->size; i > 0; i--)
  7. {
  8. ps->arr[i] = ps->arr[i - 1];//arr[1] = arr[0]
  9. }
  10. ps->arr[0] = value;
  11. ps->size++;
  12. }
  13. //尾插
  14. void SLPushback(SL* ps, SLdatatpye value)
  15. {
  16. assert(ps);
  17. SLcheckcapacity(ps);
  18. ps->arr[ps->size++] = value;
  19. }

4.头删、尾删

与头插尾插同理,头删需要将第一位后的数字都往前移动一位,随后就是size--(删掉了一个元素)。而尾删只需要size--就行,不会影响其他函数,能达到删除的功能。

  1. //头删
  2. void SLDeletefront(SL* ps)
  3. {
  4. assert(ps);
  5. assert(ps->size);
  6. for (int i = 0; i < ps->size - 1; i++)
  7. {
  8. ps->arr[i] = ps->arr[i + 1];//size - 2 = size - 1
  9. }
  10. ps->size--;
  11. }
  12. //尾删
  13. void SLDeleteback(SL* ps)
  14. {
  15. assert(ps);
  16. assert(ps->size);
  17. ps->size--;
  18. }

5.指定位置插入、删除

将头插尾插进行广泛化,但核心原理是相同的,只不过起点可以指定而已,此处对于指定位置需要进行判断,必须大于等于0和小于(等于)size。

  1. //指定位置插入
  2. void SLInsert(SL* ps, int pos, SLdatatpye value)
  3. {
  4. assert(ps);
  5. assert(pos >= 0 && pos <= ps->size);
  6. SLcheckcapacity(ps);
  7. for (int i = ps->size; i > pos; i--)
  8. {
  9. ps->arr[i] = ps->arr[i - 1];//pos+1 = pos
  10. }
  11. ps->arr[pos] = value;
  12. ps->size++;
  13. }
  14. //指定位置删除
  15. void SLDelete(SL* ps, int pos)
  16. {
  17. assert(ps);
  18. assert(pos >= 0 && pos < ps->size);
  19. for (int i = pos; i < ps->size - 1; i++)
  20. {
  21. ps->arr[i] = ps->arr[i + 1];//size -2 = size - 1
  22. }
  23. ps->size--;
  24. }

6.查找

对动态数组进行遍历,查看是否有与输入值相等的值,若有则返回下标。

  1. //查找
  2. int SLFind(SL* ps, SLdatatpye value)
  3. {
  4. assert(ps);
  5. for (int i = 0; i < ps->size; i++)
  6. {
  7. if (ps->arr[i] == value)
  8. return i;
  9. }
  10. return -1;
  11. }

三.完整代码

头文件:SeqList.h

  1. #pragma once
  2. #include<stdio.h>
  3. #include<stdlib.h>
  4. #include<assert.h>
  5. typedef int SLdatatpye;
  6. typedef struct Seqlist
  7. {
  8. SLdatatpye* arr;
  9. int size;
  10. int capacity;
  11. }SL;
  12. //初始化
  13. void SLInit(SL*);
  14. //销毁
  15. void SLDestroy(SL* ps);
  16. //打印
  17. void SLPrint_int(SL* ps);
  18. //检查容量、扩容
  19. void SLcheckcapacity(SL* ps);
  20. //头插
  21. void SLPushfront(SL* ps, SLdatatpye value);
  22. //尾插
  23. void SLPushback(SL* ps, SLdatatpye value);
  24. //头删
  25. void SLDeletefront(SL* ps);
  26. //尾删
  27. void SLDeleteback(SL* ps);
  28. //指定位置插入
  29. void SLInsert(SL* ps, int pos, SLdatatpye value);
  30. //指定位置删除
  31. void SLDelete(SL* ps, int pos);
  32. //查找
  33. int SLFind(SL* ps, SLdatatpye value);

源文件:SeqList.c

  1. #include"SeqList.h"
  2. void SLInit(SL* ps)
  3. {
  4. assert(ps);
  5. ps->arr = NULL;
  6. ps->size = ps->capacity = 0;
  7. }
  8. void SLDestroy(SL* ps)
  9. {
  10. assert(ps);
  11. assert(ps->arr);
  12. free(ps->arr);
  13. ps->arr = NULL;
  14. ps->size = ps->capacity = 0;
  15. }
  16. void SLPrint_int(SL* ps)
  17. {
  18. assert(ps);
  19. for (int i = 0; i < ps->size; i++)
  20. {
  21. printf("%d ", ps->arr[i]);
  22. }
  23. printf("\n");
  24. }
  25. void SLcheckcapacity(SL* ps)
  26. {
  27. assert(ps);
  28. if (ps->capacity == ps->size)
  29. {
  30. int newspace = ps->capacity == 0 ? 4 : 2 * ps->capacity;
  31. SLdatatpye* tmp = (SLdatatpye*)realloc(ps->arr, newspace * sizeof(SLdatatpye));
  32. if (tmp == NULL)
  33. {
  34. perror("realloc");
  35. exit(1);
  36. }
  37. ps->arr = tmp;
  38. ps->capacity = newspace;
  39. }
  40. }
  41. void SLPushfront(SL* ps, SLdatatpye value)
  42. {
  43. assert(ps);
  44. SLcheckcapacity(ps);
  45. for (int i = ps->size; i > 0; i--)
  46. {
  47. ps->arr[i] = ps->arr[i - 1];//arr[1] = arr[0]
  48. }
  49. ps->arr[0] = value;
  50. ps->size++;
  51. }
  52. void SLPushback(SL* ps, SLdatatpye value)
  53. {
  54. assert(ps);
  55. SLcheckcapacity(ps);
  56. ps->arr[ps->size++] = value;
  57. }
  58. void SLDeletefront(SL* ps)
  59. {
  60. assert(ps);
  61. assert(ps->size);
  62. for (int i = 0; i < ps->size - 1; i++)
  63. {
  64. ps->arr[i] = ps->arr[i + 1];//size - 2 = size - 1
  65. }
  66. ps->size--;
  67. }
  68. void SLDeleteback(SL* ps)
  69. {
  70. assert(ps);
  71. assert(ps->size);
  72. ps->size--;
  73. }
  74. void SLInsert(SL* ps, int pos, SLdatatpye value)
  75. {
  76. assert(ps);
  77. assert(pos >= 0 && pos <= ps->size);
  78. SLcheckcapacity(ps);
  79. for (int i = ps->size; i > pos; i--)
  80. {
  81. ps->arr[i] = ps->arr[i - 1];//pos+1 = pos
  82. }
  83. ps->arr[pos] = value;
  84. ps->size++;
  85. }
  86. void SLDelete(SL* ps, int pos)
  87. {
  88. assert(ps);
  89. assert(pos >= 0 && pos < ps->size);
  90. for (int i = pos; i < ps->size - 1; i++)
  91. {
  92. ps->arr[i] = ps->arr[i + 1];//size -2 = size - 1
  93. }
  94. ps->size--;
  95. }
  96. int SLFind(SL* ps, SLdatatpye value)
  97. {
  98. assert(ps);
  99. for (int i = 0; i < ps->size; i++)
  100. {
  101. if (ps->arr[i] == value)
  102. return i;
  103. }
  104. return -1;
  105. }

源文件:test.c 

  1. #include"Seqlist.h"
  2. void testSL01(SL* ps)
  3. {
  4. SLInit(ps);
  5. SLPushback(ps, 1);
  6. SLPushback(ps, 2);
  7. SLPushback(ps, 3);
  8. SLPushback(ps, 4);
  9. SLPrint_int(ps);
  10. SLInsert(ps, 2, 3);
  11. SLInsert(ps, 0, 0);
  12. SLPrint_int(ps);
  13. SLDelete(ps, 3);
  14. SLDelete(ps, 0);
  15. SLPrint_int(ps);
  16. int ret = SLFind(ps, 2);
  17. if (ret != -1)
  18. {
  19. printf("找到了,下标为:%d\n", ret);
  20. }
  21. else
  22. {
  23. printf("找不到\n");
  24. }
  25. SLDestroy(ps);
  26. }
  27. int main()
  28. {
  29. SL s;
  30. testSL01(&s);
  31. }

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

闽ICP备14008679号