• 顺序表漫谈


    目录

    ​编辑

    1.线性表

    2.顺序表

    2.1概念及结构

    2.2接口实现

    1.顺序表的动态存储

    2.顺序表初始化

    3.顺序表销毁

    4.顺序表增容

    5.顺序表头插

    6.顺序表尾插

    7.顺序表头删

    8.顺序表尾删

    9.顺序表打印

    10.顺序表在任意下标位置插入数据

    11.顺序表删除任意下标位置的值

    12.顺序表查找

    2.3菜单

    3.源码


    1.线性表

    • 线性表(linear list)是n个具有相同特性的数据元素的有限序列。
    • 线性表是一种在实际中广泛使用的数据结构,常见的线性表有:顺序表、链表、栈、队列、字符串...
    • 线性表在逻辑上是线性结构,也就说是连续的一条直线。但是在物理结构上并不一定是连续的,线性表在物理上存储时,通常以数组和链式结构的形式存储。


     

    2.顺序表

    2.1概念及结构

    顺序表是一种线性表的实现方式,它通过一段物理地址连续的存储单元依次存储数据元素,数据元素之间的逻辑关系通过元素在内存中的相对位置来表示,一般情况下采用数组存储。在数组上完成数据的增删查改。

    顺序表简单来说就是一个数组,它和数组的唯一区别就是里边的数据只能从头开始连续存储

    🌵顺序表一般可以分为:

    1.静态顺序表:使用定长数组存储元素

    2.动态顺序表:使用动态开辟的数组存储元素

    2.2接口实现

    静态顺序表只适用于确定知道需要存储数据的场景。静态顺序表的定长数组导致N定大了,空间开多了浪费,开少了不够用。所以现实中基本都是使用动态顺序表,根据需要动态的分配空间大小,所以下面我们实现动态顺序表。

    1.顺序表的动态存储

    要实现动态的顺序表,我们首先得有一个指向数组的指针,因为内存是malloc或者realloc出来的。还得有一个size,知道到底存了多少个数据,以及得有一个capacity,用来记录空间容量。

    1. typedef int SLDataType;
    2. typedef struct SeqList
    3. {
    4. assert(psl);
    5. SLDataType* arr; //指向动态开辟的数组
    6. int size; //有效数据个数,看作下标时,它指向最后一个数据的下一个位置
    7. int capacity; //空间容量
    8. }SeqList;

    2.顺序表初始化

    因为形参是实参的一份临时拷贝,改变形参的值不会影响实参,所以传值的时候要传地址,形参用指针接收。

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

    3.顺序表销毁

    1. //顺序表销毁
    2. void SeqListDestory(SeqList* psl)
    3. {
    4. assert(psl);
    5. if (psl->arr != NULL)
    6. {
    7. free(psl->arr);
    8. psl->arr = NULL;
    9. psl->size = 0;
    10. psl->capacity = 0;
    11. }
    12. }

    4.顺序表增容

    即检查空间,如果满了,就进行增容。因为头插和尾插都需要增容,所以我们把它成一个公共的函数,方便管理。 关于动态内存开辟有不清楚的铁子们可以看这篇博客:动态内存管理详解

    1. //增容
    2. void SeqListCheckCapacity(SeqList* psl)
    3. {
    4. assert(psl);
    5. if (psl->size == psl->capacity)
    6. {
    7. int newCapacity = psl->capacity == 0 ? 4 : psl->capacity * 2;
    8. //防止扩容失败将原来的空间给覆盖掉,所以用一个临时变量来接收
    9. SLDataType* tmp = (SLDataType*)realloc(psl->arr, sizeof(SLDataType) * newCapacity);
    10. if (tmp == NULL)
    11. {
    12. perror("realloc");
    13. return;
    14. }
    15. psl->arr = tmp;
    16. psl->capacity = newCapacity;
    17. }
    18. }

    5.顺序表头插

    要想在头部插入数据,必须将所有的数据先向后挪动一个位置,然后将要插入的数据放在第一个位置。我们可以先定义一个变量end,让它等于最后一个数据,然后利用while循环将所有的数据向后挪动一个位置,再将数据插入头部,然后让数据个数size+1。

    1. //头插
    2. void SeqListPushFront(SeqList* psl, SLDataType x)
    3. {
    4. assert(psl);
    5. SeqListCheckCapacity(psl);
    6. //挪动数据
    7. int end = psl->size - 1;
    8. while (end >= 0)
    9. {
    10. psl->arr[end + 1] = psl->arr[end];
    11. end--;
    12. }
    13. psl->arr[0] = x;
    14. psl->size++;
    15. }

    6.顺序表尾插

    尾插相对来说比较简单,如果空间不够,增容之后直接将要插入的数据放在尾部即可,然后将数据个数size+1。

    1. //尾插
    2. void SeqListPushBack(SeqList* psl, SLDataType x)
    3. {
    4. assert(psl);
    5. //增容
    6. SeqListCheckCapacity(psl);
    7. psl->arr[psl->size] = x;
    8. psl->size++;
    9. }

    7.顺序表头删

    头删时我们采用的方法还是挪动数据,但是要从前面开始挪动,因为如果从后往前挪的话会将前面的数据给覆盖掉。先定义一个变量begin,让它等于1,然后利用while循环将所有的数据向前挪动一个位置(让后一个数据将前一个数据覆盖掉),直到begin小于size就跳出循环,然后让数据个数size-1。

    1. //头删
    2. void SeqListPopFront(SeqList* psl)
    3. {
    4. assert(psl);
    5. //暴力检查
    6. assert(psl->size);
    7. int begin = 1;
    8. while (begin < psl->size)
    9. {
    10. psl->arr[begin - 1] = psl->arr[begin];
    11. begin++;
    12. }
    13. psl->size--;
    14. }

    8.顺序表尾删

    尾删时我们只需让有效数据 size-- 就行,但是必须进行检查看顺序表是否为空,因为如果为空,后面我们在头插时就会出现问题。

    1. //尾删
    2. void SeqListPopBack(SeqList* psl)
    3. {
    4. assert(psl);
    5. //若顺序表为空,则进行检查
    6. //温柔的检查
    7. /*if (psl->size == 0)
    8. {
    9. return;
    10. }*/
    11. //暴力检查
    12. assert(psl->size > 0);
    13. psl->size--;
    14. }

    9.顺序表打印

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

    10.顺序表在任意下标位置插入数据

    首先要保证指针不为空以及pos位置的合法性。然后定义变量end,让它指向最后一个数据的位置,通过while循环将 pos到end 位置的值向后挪动一个位置,将要插入的数据放入pos位置,再将size+1。

    1. //顺序表在任意下标位置插入数据
    2. void SeqListInsert(SeqList* psl, int pos, SLDataType x)
    3. {
    4. assert(psl);
    5. assert(pos >= 0 && pos <= psl->size);
    6. int end = psl->size - 1;
    7. while (end >= pos)
    8. {
    9. psl->arr[end + 1] = psl->arr[end];
    10. end--;
    11. }
    12. psl->arr[pos] = x;
    13. psl->size++;
    14. }

    11.顺序表删除任意下标位置的值

    1. //顺序表删除任意下标位置的值
    2. void SeqListErase(SeqList* psl, int pos)
    3. {
    4. assert(psl);
    5. assert(pos >= 0 && pos < psl->size);
    6. //挪动数据
    7. int begin = pos + 1;
    8. while (begin < psl->size)
    9. {
    10. psl->arr[begin - 1] = psl->arr[begin];
    11. begin++;
    12. }
    13. psl->size--;
    14. }

    12.顺序表查找

    在顺序表中查找数据,如果找到了,就返回下标;如果没有找到,则返回-1。

    1. //顺序表查找
    2. int SeqListFind(SeqList* psl, SLDataType x)
    3. {
    4. assert(psl);
    5. for (int i = 0; i < psl->size; i++)
    6. {
    7. if (psl->arr[i] == x)
    8. {
    9. return i;
    10. break;
    11. }
    12. }
    13. return -1;
    14. }

    2.3菜单

    1. void menu()
    2. {
    3. printf("*************************************\n");
    4. printf("*** 1.头插数据 2.尾插数据 ***\n");
    5. printf("*** 3.头删数据 4.尾删数据 ***\n");
    6. printf("*** 5.查找数据 6.打印顺序表 ***\n");
    7. printf("*** 7.在任意下标位置插入数据 ***\n");
    8. printf("*** 8.删除任意下标位置的数据 ***\n");
    9. printf("*** 0.退出系统 ***\n");
    10. printf("*************************************\n");
    11. }
    12. void Test()
    13. {
    14. SeqList sl;
    15. SeqListInit(&sl);//初始化
    16. int x = 0, pos = 0;
    17. int input = 0;
    18. do
    19. {
    20. printf("欢迎来到顺序表系统!\n");
    21. menu();
    22. printf("请输入你的选择:>");
    23. scanf("%d", &input);
    24. switch (input)
    25. {
    26. case 1:
    27. printf("请输入你要头插的数据:\n");
    28. scanf("%d", &x);
    29. SeqListPushFront(&sl, x);
    30. printf("头插成功!\n");
    31. break;
    32. case 2:
    33. printf("请输入你要尾插的数据:\n");
    34. scanf("%d", &x);
    35. SeqListPushBack(&sl, x);
    36. printf("尾插成功!\n");
    37. break;
    38. case 3:
    39. SeqListPopFront(&sl);
    40. printf("头删成功!\n");
    41. break;
    42. case 4:
    43. SeqListPopBack(&sl);
    44. printf("尾删成功!\n");
    45. break;
    46. case 5:
    47. printf("请输入你要查找的数据(查找成功则返回下标, 负责返回-1):\n");
    48. scanf("%d", &x);
    49. int pos = SeqListFind(&sl, x);
    50. printf("%d\n", pos);
    51. break;
    52. case 6:
    53. printf("顺序表目前的数据为:\n");
    54. SeqListPrint(&sl);
    55. break;
    56. case 7:
    57. printf("请输入你要插入的数据:");
    58. scanf("%d", &x);
    59. printf("请输入你要插入数据的下标(下标从0开始):");
    60. scanf("%d", &pos);
    61. SeqListInsert(&sl, pos, x);
    62. printf("插入数据成功!\n");
    63. break;
    64. case 8:
    65. printf("请输入你要删除数据的下标:");
    66. scanf("%d", &pos);
    67. SeqListErase(&sl, pos);
    68. printf("删除成功!\n");
    69. break;
    70. case 0:
    71. printf("退出系统!\n");
    72. break;
    73. default:
    74. printf("选择错误,请重新选择!\n");
    75. break;
    76. }
    77. } while (input);
    78. SeqListDestory(&sl);//销毁
    79. }

    3.源码

    🌻test.c

    1. #include "SeqList.h"
    2. void menu()
    3. {
    4. printf("*************************************\n");
    5. printf("*** 1.头插数据 2.尾插数据 ***\n");
    6. printf("*** 3.头删数据 4.尾删数据 ***\n");
    7. printf("*** 5.查找数据 6.打印顺序表 ***\n");
    8. printf("*** 7.在任意下标位置插入数据 ***\n");
    9. printf("*** 8.删除任意下标位置的数据 ***\n");
    10. printf("*** 0.退出系统 ***\n");
    11. printf("*************************************\n");
    12. }
    13. void Test()
    14. {
    15. SeqList sl;
    16. SeqListInit(&sl);
    17. int x = 0, pos = 0;
    18. int input = 0;
    19. do
    20. {
    21. printf("欢迎来到顺序表系统!\n");
    22. menu();
    23. printf("请输入你的选择:>");
    24. scanf("%d", &input);
    25. switch (input)
    26. {
    27. case 1:
    28. printf("请输入你要头插的数据:\n");
    29. scanf("%d", &x);
    30. SeqListPushFront(&sl, x);
    31. printf("头插成功!\n");
    32. break;
    33. case 2:
    34. printf("请输入你要尾插的数据:\n");
    35. scanf("%d", &x);
    36. SeqListPushBack(&sl, x);
    37. printf("尾插成功!\n");
    38. break;
    39. case 3:
    40. SeqListPopFront(&sl);
    41. printf("头删成功!\n");
    42. break;
    43. case 4:
    44. SeqListPopBack(&sl);
    45. printf("尾删成功!\n");
    46. break;
    47. case 5:
    48. printf("请输入你要查找的数据(查找成功则返回下标, 负责返回-1):\n");
    49. scanf("%d", &x);
    50. int pos = SeqListFind(&sl, x);
    51. printf("%d\n", pos);
    52. break;
    53. case 6:
    54. printf("顺序表目前的数据为:\n");
    55. SeqListPrint(&sl);
    56. break;
    57. case 7:
    58. printf("请输入你要插入的数据:");
    59. scanf("%d", &x);
    60. printf("请输入你要插入数据的下标(下标从0开始):");
    61. scanf("%d", &pos);
    62. SeqListInsert(&sl, pos, x);
    63. printf("插入数据成功!\n");
    64. break;
    65. case 8:
    66. printf("请输入你要删除数据的下标:");
    67. scanf("%d", &pos);
    68. SeqListErase(&sl, pos);
    69. printf("删除成功!\n");
    70. break;
    71. case 0:
    72. printf("退出系统!\n");
    73. break;
    74. default:
    75. printf("选择错误,请重新选择!\n");
    76. break;
    77. }
    78. } while (input);
    79. SeqListDestory(&sl);
    80. }
    81. int main()
    82. {
    83. Test();
    84. return 0;
    85. }

    🌻SeqList.h

    1. #pragma once
    2. #include
    3. #include
    4. #include
    5. typedef int SLDataType;
    6. typedef struct SeqList
    7. {
    8. SLDataType* arr;//指向动态开辟的数组
    9. int size; //有效数据
    10. int capacity; //空间容量
    11. }SeqList;
    12. //顺序表初始化
    13. void SeqListInit(SeqList* psl);
    14. //顺序表销毁
    15. void SeqListDestory(SeqList* psl);
    16. //顺序表打印
    17. void SeqListPrint(SeqList* psl);
    18. //增容
    19. void SeqListCheckCapacity(SeqList* psl);
    20. //头插
    21. void SeqListPushFront(SeqList* psl, SLDataType x);
    22. //尾插
    23. void SeqListPushBack(SeqList* psl, SLDataType x);
    24. //头删
    25. void SeqListPopFront(SeqList* psl);
    26. //尾删
    27. void SeqListPopBack(SeqList* psl);
    28. //顺序表在任意位置插入数据
    29. void SeqListInsert(SeqList* psl, int pos, SLDataType x);
    30. //顺序表删除任意位置的值
    31. void SeqListErase(SeqList* psl, int pos);
    32. //顺序表查找
    33. int SeqListFind(SeqList* psl, SLDataType x);

    🌻SeqList.c

    1. #include "SeqList.h"
    2. //顺序表初始化
    3. void SeqListInit(SeqList* psl)
    4. {
    5. assert(psl);
    6. psl->arr = NULL;
    7. psl->size = 0;
    8. psl->capacity = 0;
    9. }
    10. //顺序表销毁
    11. void SeqListDestory(SeqList* psl)
    12. {
    13. assert(psl);
    14. if (psl->arr != NULL)
    15. {
    16. free(psl->arr);
    17. psl->arr = NULL;
    18. psl->size = 0;
    19. psl->capacity = 0;
    20. }
    21. }
    22. //顺序表打印
    23. void SeqListPrint(SeqList* psl)
    24. {
    25. assert(psl);
    26. for (int i = 0; i < psl->size; i++)
    27. {
    28. printf("%d ", psl->arr[i]);
    29. }
    30. printf("\n");
    31. }
    32. //增容
    33. void SeqListCheckCapacity(SeqList* psl)
    34. {
    35. assert(psl);
    36. if (psl->size == psl->capacity)
    37. {
    38. int newCapacity = psl->capacity == 0 ? 4 : psl->capacity * 2;
    39. //防止扩容失败将原来的空间给覆盖掉,所以用一个临时变量来接收
    40. SLDataType* tmp = (SLDataType*)realloc(psl->arr, sizeof(SLDataType) * newCapacity);
    41. if (tmp == NULL)
    42. {
    43. perror("realloc");
    44. return;
    45. }
    46. psl->arr = tmp;
    47. psl->capacity = newCapacity;
    48. }
    49. }
    50. //头插
    51. void SeqListPushFront(SeqList* psl, SLDataType x)
    52. {
    53. assert(psl);
    54. SeqListCheckCapacity(psl);
    55. //挪动数据
    56. int end = psl->size - 1;
    57. while (end >= 0)
    58. {
    59. psl->arr[end + 1] = psl->arr[end];
    60. end--;
    61. }
    62. psl->arr[0] = x;
    63. psl->size++;
    64. }
    65. //尾插
    66. void SeqListPushBack(SeqList* psl, SLDataType x)
    67. {
    68. assert(psl);
    69. //增容
    70. SeqListCheckCapacity(psl);
    71. psl->arr[psl->size] = x;
    72. psl->size++;
    73. }
    74. //头删
    75. void SeqListPopFront(SeqList* psl)
    76. {
    77. assert(psl);
    78. //暴力检查
    79. assert(psl->size);
    80. int begin = 1;
    81. while (begin < psl->size)
    82. {
    83. psl->arr[begin - 1] = psl->arr[begin];
    84. begin++;
    85. }
    86. psl->size--;
    87. }
    88. //尾删
    89. void SeqListPopBack(SeqList* psl)
    90. {
    91. assert(psl);
    92. //若顺序表为空,则进行检查
    93. //温柔的检查
    94. /*if (psl->size == 0)
    95. {
    96. return;
    97. }*/
    98. //暴力检查
    99. assert(psl->size);
    100. psl->size--;
    101. }
    102. //顺序表在任意下标位置插入数据
    103. void SeqListInsert(SeqList* psl, int pos, SLDataType x)
    104. {
    105. assert(psl);
    106. assert(pos >= 0 && pos <= psl->size);
    107. int end = psl->size - 1;
    108. while (end >= pos)
    109. {
    110. psl->arr[end + 1] = psl->arr[end];
    111. end--;
    112. }
    113. psl->arr[pos] = x;
    114. psl->size++;
    115. }
    116. //顺序表删除任意下标位置的值
    117. void SeqListErase(SeqList* psl, int pos)
    118. {
    119. assert(psl);
    120. assert(pos >= 0 && pos < psl->size);
    121. int begin = pos + 1;
    122. while (begin < psl->size)
    123. {
    124. psl->arr[begin - 1] = psl->arr[begin];
    125. begin++;
    126. }
    127. psl->size--;
    128. }
    129. //顺序表查找
    130. int SeqListFind(SeqList* psl, SLDataType x)
    131. {
    132. assert(psl);
    133. for (int i = 0; i < psl->size; i++)
    134. {
    135. if (psl->arr[i] == x)
    136. {
    137. return i;
    138. break;
    139. }
    140. }
    141. return -1;
    142. }
  • 相关阅读:
    乌克兰的 IT 外包,为什么如此“发达”?
    探索Django路由规则(路由匹配、路由命名空间、HTML中的跳转与Django集成、路由传参以及后端重定向)
    简述CompletableFuture异步任务编排
    HNU-CSer的推免经历记录
    1、风行内容仓的增效之路 - 前言
    Unity之ShaderGraph如何实现积雪效果
    深度学习在胰腺医学影像中的应用综述
    思维+启发式合并
    element ui 里面只能输入input 数字 +限制长度
    Alibaba Nacos注册中心源码剖析
  • 原文地址:https://blog.csdn.net/weixin_65931202/article/details/136177367