• 【数据结构初阶】顺序表SeqList


    描述

    顺序表我们可以把它想象成在一个表格里面填数据,并对数据做调整;

    那我们的第一个问题是:怎么样在创建出足够的空间呢?

    我们可以去堆上申请,用一个指针指向一块空间,如果申请的空间不够,我们可以再realloc申请出来。

    我们的第二个问题是:怎么样标记我们用了多少空间呢?

    这时我们就需要一个变量来记录我们当前的用到第几个“格子”(即用了多少空间),我们这里用size来表示:

    我们的第三个问题是:怎么样知道我们有空间呢?

    这时我们就需要一个变量来记录我们“格子”总数(即拥有多少空间),我们这里用capacity来表示:

    所以(在.h文件中)我们线性表的结构体描述为:

    1. typedef int SLDataType;
    2. typedef struct SeList
    3. {
    4. SLDataType* a;
    5. int size;
    6. int capacity;
    7. }SL;

    组织

    1. 初始化
    2. 释放
    3. 尾插
    4. 尾删
    5. 头插
    6. 头删
    7. 指定位置删除
    8. 指定位置插入
    9. 查找指定元素

    1.初始化

    把我们描述出来的顺序表结构体里的变量初始化

    在.h文件中:

    因为要对创建出来的结构体里的内容进行修改,所以函数要进行传址调用

    在.c文件中:

    我们用malloc来开辟空间,同时注意检查malloc;

    因为我们刚刚开辟空间,并没有往顺序表里增删查改 所以此时size为0;

    而我们的capacity就是在malloc开辟的空间大小。

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

    2.释放

    将描述出来的顺序表结构体里的变量逐个进行释放;

    在.h 文件中:

    在.c文件中:

    首先是指针a,需要使用free函数将其释放,还需要注意的是free后,需要将a置空,避免出现野指针

    因为size和capacity是临时变量储存在栈上,函数调用结束后会自动释放,我们这里把它改为0就可以了。

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

    3.尾插

    向顺序表的尾部插入数据;

    在.h 文件中:

    在.c文件中:

    尾插数据时,首先,需要判断capacity(空间)是否足够,如果不够需要扩容,这里我们写个扩容函数:

    扩容我们用realloc函数,最后要返回ps至尾插函数判断是否为空;

    接着,才能将数据尾插;

    最后别忘了调整size的位置;

    1. SL* SLExpand(SL* ps)
    2. {
    3. assert(ps->a);
    4. if (ps->size == ps->capacity)
    5. {
    6. SLDataType* tmp = (SLDataType*)realloc(ps->a, sizeof(SLDataType)* ps->capacity*2);
    7. if (tmp == NULL)
    8. {
    9. perror("realloc fail");
    10. return NULL;
    11. }
    12. ps->capacity *=2;
    13. ps->a = tmp;
    14. }
    15. return ps;
    16. }
    17. void SLPushBack(SL* ps,SLDataType x)
    18. {
    19. assert(ps->a);
    20. //扩容
    21. if (ps->size == ps->capacity)
    22. {
    23. SL* ret = SLExpand(ps);
    24. if (ret == NULL)
    25. {
    26. return;
    27. }
    28. }
    29. ps->a[ps->size] = x;
    30. ps->size++;
    31. }

    4.尾删

    将顺序表的尾部删除;

    在.h 文件中:

    在.c 文件中:

    因为顺序表是从开始连续存储size个数据,不能单独释放那一块区域,所以我们直接将size--就可以了,如果往后插入的话,就直接把数据覆盖;

    assert()如果当capacity为空的时候还尾删时会报错,并且终止程序;

    1. void SLPopBack(SL* ps)
    2. {
    3. assert(ps->a);
    4. ps->size--;
    5. }

    5.头插

    向顺序表的头部插入数据;

    在.h 文件中:

    在.c 文件中:

    首先,我们得先判断空间是否足够,如果不够就扩容;

    第二步:把数据往后移一位,数据从最后一位开始向后移动;

    第三步:进行数据头插,别忘了把size的大小改改;

    1. void SLPushFront(SL* ps, SLDataType x)
    2. {
    3. assert(ps->a);
    4. //扩容
    5. if (ps->size == ps->capacity)
    6. {
    7. SL* ret = SLExpand(ps);
    8. if (ret == NULL)
    9. {
    10. return;
    11. }
    12. }
    13. //移动数据
    14. for (int i = ps->size; i >0 ; i--)
    15. {
    16. ps->a[i] = ps->a[i - 1];
    17. }
    18. //头插
    19. ps->a[0] = x;
    20. ps->size++;
    21. }

    6.头删

    将顺序表的头部数据删除;

    在.h 文件中:

    在.c 文件中:

    我们只需要将从第二位数据开始往前移动,把前一位的数据覆盖就可以达到头删的效果;

    1. void SLPopFront(SL* ps)
    2. {
    3. assert(ps->a);
    4. assert(ps->size > 0);
    5. for (int i = 0; i < ps->size; i++)
    6. {
    7. ps->a[i] = ps->a[i + 1];
    8. }
    9. ps->size--;
    10. }

    7.指定位置删除

    将顺序表的指定位置数据删除;

    在.h 文件中:

    在.c 文件中:

    首先,要先用assert检查一下空间和pos的值是否合理;

    如果删除的数据是最后一个就直接尾删;

    如果如果删除的数据不是最后一个就需要移动数据覆盖,类似于头删;

    1. void SLErase(SL* ps, int pos)
    2. {
    3. assert(ps->a);
    4. assert(pos >= 0&&possize);
    5. //如果pos是最后一个数据,尾删
    6. if (pos == ps->size - 1)
    7. {
    8. SLPopBack(ps);
    9. }
    10. else
    11. {
    12. for (int i = pos; i < ps->size; i++)
    13. {
    14. ps->a[i] = ps->a[i + 1];
    15. }
    16. ps->size--;
    17. }
    18. }

    8.指定位置插入

    将顺序表的指定位置数据插入;

    在.h 文件中:

    在.c 文件中:

    首先,要先用assert检查一下空间和pos的值是否合理;

    如果插入的数据是最后一个就直接尾插;

    如果如果插入的数据不是最后一个就需要移动数据,再插入数据,类似于头插;

    1. void SLInsert(SL* ps, int pos, SLDataType x)
    2. {
    3. assert(ps->a);
    4. assert(pos >= 0 && pos <= ps->size);
    5. //判断容量
    6. if (ps->size == ps->capacity)
    7. {
    8. SL* ret = SLExpand(ps);
    9. if (ret == NULL)
    10. {
    11. return;
    12. }
    13. }
    14. //尾插
    15. if (pos == ps->size - 1)
    16. {
    17. SLPushBack(ps,x);
    18. }
    19. else
    20. {
    21. for (int i = ps->size; i > pos; i--)
    22. {
    23. ps->a[i] = ps->a[i - 1];
    24. }
    25. ps->size++;
    26. ps->a[pos] = x;
    27. }
    28. }

    9.查找指定元素

    在顺序表中查找指定数据,并输出其下表,和在该表中的个数;

    在.h 文件中:

    在.c 文件中:

    for循环遍历一下顺序表,如果遍历过程中找到了直接打印其下标,并用一个变量记录它出现的此数。

    出循环后打印其和在该表中出现的个数。

    1. void SLFindPoint(SL* ps, SLDataType x)
    2. {
    3. assert(ps->a);
    4. int cnt = 0;
    5. for (int i = 0; i < ps->size; i++)
    6. {
    7. if (ps->a[i] == x)
    8. {
    9. cnt++;
    10. printf("找到了第%d个,下标为:%d\n",cnt, i);
    11. }
    12. }
    13. if (cnt == 0)
    14. {
    15. printf("抱歉,无该数据\n");
    16. }
    17. else
    18. {
    19. printf("共找到%d个数据\n", cnt);
    20. }
    21. }

    整个程序

    .h文件:

    1. #define _CRT_SECURE_NO_WARNINGS 1
    2. #include
    3. #include
    4. #include
    5. #include
    6. typedef int SLDataType;
    7. #define INIT_CAPACITY 4
    8. typedef struct SeList
    9. {
    10. SLDataType* a;
    11. int size;
    12. int capacity;
    13. }SL;
    14. void SLPrint(SL* ps);
    15. void SLInit(SL* ps);
    16. void SLDestroy(SL* ps);
    17. void SLPushBack(SL* ps,SLDataType x);
    18. void SLPopBack(SL* ps);
    19. void SLPushFront(SL* ps, SLDataType x);
    20. void SLPopFront(SL* ps);
    21. void SLErase(SL* ps,int pos);
    22. void SLInsert(SL* ps, int pos, SLDataType x);
    23. void SLFindPoint(SL* ps, SLDataType x);

    .c文件:

    1. #define _CRT_SECURE_NO_WARNINGS 1
    2. #include"Seqlist.h"
    3. void SLPrint(SL* ps)
    4. {
    5. assert(ps->a);
    6. for (int i = 0; i < ps->size; i++)
    7. {
    8. printf("%d ", ps->a[i]);
    9. }
    10. printf("\n");
    11. }
    12. void SLInit(SL* ps)
    13. {
    14. assert(ps->a);
    15. ps->a = (SLDataType*)malloc(sizeof(SLDataType) * INIT_CAPACITY);
    16. if (ps->a == NULL)
    17. {
    18. perror("malloc fail");
    19. return;
    20. }
    21. ps->size = 0;
    22. ps->capacity = INIT_CAPACITY;
    23. }
    24. void SLDestroy(SL* ps)
    25. {
    26. assert(ps->a);
    27. free(ps->a);
    28. ps->a = NULL;
    29. ps->capacity = 0;
    30. ps->size = 0;
    31. }
    32. SL* SLExpand(SL* ps)
    33. {
    34. assert(ps->a);
    35. if (ps->size == ps->capacity)
    36. {
    37. SLDataType* tmp = (SLDataType*)realloc(ps->a, sizeof(SLDataType)* ps->capacity*2);
    38. if (tmp == NULL)
    39. {
    40. perror("realloc fail");
    41. return NULL;
    42. }
    43. ps->capacity *=2;
    44. ps->a = tmp;
    45. }
    46. return ps;
    47. }
    48. void SLPushBack(SL* ps,SLDataType x)
    49. {
    50. assert(ps->a);
    51. //扩容
    52. if (ps->size == ps->capacity)
    53. {
    54. SL* ret = SLExpand(ps);
    55. if (ret == NULL)
    56. {
    57. return;
    58. }
    59. }
    60. ps->a[ps->size] = x;
    61. ps->size++;
    62. }
    63. void SLPopBack(SL* ps)
    64. {
    65. assert(ps->a);
    66. ps->size--;
    67. }
    68. void SLPushFront(SL* ps, SLDataType x)
    69. {
    70. assert(ps->a);
    71. //扩容
    72. if (ps->size == ps->capacity)
    73. {
    74. SL* ret = SLExpand(ps);
    75. if (ret == NULL)
    76. {
    77. return;
    78. }
    79. }
    80. //移动数据
    81. for (int i = ps->size; i >0 ; i--)
    82. {
    83. ps->a[i] = ps->a[i - 1];
    84. }
    85. //头插
    86. ps->a[0] = x;
    87. ps->size++;
    88. }
    89. void SLPopFront(SL* ps)
    90. {
    91. assert(ps->a);
    92. assert(ps->size > 0);
    93. for (int i = 0; i < ps->size; i++)
    94. {
    95. ps->a[i] = ps->a[i + 1];
    96. }
    97. ps->size--;
    98. }
    99. void SLErase(SL* ps, int pos)
    100. {
    101. assert(ps->a);
    102. assert(pos >= 0&&possize);
    103. //如果pos是最后一个数据,尾删
    104. if (pos == ps->size - 1)
    105. {
    106. SLPopBack(ps);
    107. }
    108. else
    109. {
    110. for (int i = pos; i < ps->size; i++)
    111. {
    112. ps->a[i] = ps->a[i + 1];
    113. }
    114. ps->size--;
    115. }
    116. }
    117. void SLInsert(SL* ps, int pos, SLDataType x)
    118. {
    119. assert(ps->a);
    120. assert(pos >= 0 && pos <= ps->size);
    121. //判断容量
    122. if (ps->size == ps->capacity)
    123. {
    124. SL* ret = SLExpand(ps);
    125. if (ret == NULL)
    126. {
    127. return;
    128. }
    129. }
    130. //尾插
    131. if (pos == ps->size - 1)
    132. {
    133. SLPushBack(ps,x);
    134. }
    135. else
    136. {
    137. for (int i = ps->size; i > pos; i--)
    138. {
    139. ps->a[i] = ps->a[i - 1];
    140. }
    141. ps->size++;
    142. ps->a[pos] = x;
    143. }
    144. }
    145. void SLFindPoint(SL* ps, SLDataType x)
    146. {
    147. assert(ps->a);
    148. int cnt = 0;
    149. for (int i = 0; i < ps->size; i++)
    150. {
    151. if (ps->a[i] == x)
    152. {
    153. cnt++;
    154. printf("找到了第%d个,下标为:%d\n",cnt, i);
    155. }
    156. }
    157. if (cnt == 0)
    158. {
    159. printf("抱歉,无该数据\n");
    160. }
    161. else
    162. {
    163. printf("共找到%d个数据\n", cnt);
    164. }
    165. }

  • 相关阅读:
    ACM笔记
    PostgreSQL的学习心得和知识总结(一百三十九)|深入理解PostgreSQL数据库GUC参数 allow_alter_system 的使用和原理
    抖音小店需要办理营业执照吗?怎么办理?这个流程你一定要收好!
    java基础之内部类[31]
    操作系统——网络通信——多路复用——select 、poll 、epoll的函数的相关使用
    生命在于学习——Stable Diffution(Mac端)
    [Linux] 基于阻塞队列的生产者消费者模型
    全国职业技能大赛云计算--高职组赛题卷④(容器云)
    网安周报|Chaes恶意软件的新Python变种针对银行和物流行业
    水厂除砷项目,砷出水未检出
  • 原文地址:https://blog.csdn.net/lsj1345714539566/article/details/134347485