• 【数据结构】线性表之顺序表


    目录

    一.线性表

    1.顺序存储

    2.链式存储

    二.顺序表

    分类:

    静态顺序表 

    问题:

    动态顺序表

    问题:

    如何解决问题:

    三.代码实现

    初始化

    尾插入

    首插入

    方法1:

    方法2:

    头删

     尾删

     选择插入

    方法1:

     方法2:

     选择删除

    查找

     修改

    四.完整代码

    SeqList.h文件

    SeqList.c文件

    text.c文件


    一.线性表

    线性表:全名线性存储结构

    线性存储结构分为顺序存储结构和链式存储结构,前者称为顺序表,后者称为链表

    1.顺序存储

    顺序表就是把线性表中的所有元素按照某种逻辑顺序,依次存储到指定位置的一块连续的存储空间。

    2.链式存储

    用于存储逻辑关系为“一对一”的数据

    用一组任意的存储单元存储线性表的数据元素(这组存储单元可以是连续的,也可以是不连续的),包括数据与和指针域。数据域存储数据,指针域存储后继的信息。

    二.顺序表

    分类:

    1. 静态顺序表:使用定长数组存储
    2. 动态顺序表:使用动态开辟的数组存储

    静态顺序表 

    问题:

    给少了不够用 ,给多了用不完,不能灵活控制

    动态顺序表

    问题:

    1. 如果空间不够,增容。增容会付出一定性能消耗,其次可能存在一定的空间浪费
    2. 头部或者中部左右的插入和删除效率低

    如何解决问题:

    1.  空间上,按需给空间
    2. 不要求物理空间的连续(比如使用链表)

    • 这里我们使用动态顺序表

    三.代码实现

    初始化

    1. //初始化
    2. void SeqListInit(SL* psl)
    3. {
    4. assert(psl);//这里严格要加上断言,防止在代码行数过多时,传参错误,使我们知道错误发生在那
    5. psl->a = NULL;
    6. psl->capacity = 0;
    7. psl->sizel = 0;
    8. }

    尾插入

    1. //增容
    2. void SeqListCheckCapacity(SL* psl)
    3. {
    4. assert(psl);
    5. if (psl->capacity == psl->sizel)
    6. {
    7. int newcapacity = psl->capacity == 0 ? 4 : psl->capacity * 2;
    8. SQDataType* temp = (SQDataType*)realloc(psl->a, newcapacity * sizeof(SQDataType));
    9. //realloc将第一个参数的值依次存入所申请的空间
    10. assert(temp);
    11. psl->a = temp;
    12. psl->capacity = newcapacity;
    13. }
    14. }
    15. //尾插
    16. void SeqListPushBack(SL* psl, SQDataType x)
    17. {
    18. assert(psl);
    19. SeqListCheckCapacity(psl);//判断capacity是否足够,若不够进行增容
    20. psl->a[psl->sizel] = x;
    21. psl->sizel++;
    22. }

    首插入

    方法1:

    使用常规的for循环进行增容。

    1. void SeqListPushFront(SL* psl, SQDataType x)
    2. {
    3. assert(psl);
    4. SeqListCheckCapacity(psl);//增容
    5. for (int i = psl->sizel-1; i >= 0; i--)
    6. {
    7. psl->a[i + 1] = psl->a[i];
    8. }
    9. psl->a[0] = x;
    10. psl->sizel++;
    11. }

    方法2:

    使用memmove函数,以字节为单位,拷贝链表,使其每个元素的位置增加一个SQDataType的大小。

    1. //头插——方法2
    2. void SeqListPushFront(SL* psl, SQDataType x)
    3. {
    4. assert(psl);
    5. SeqListCheckCapacity(psl);//增容
    6. memmove(&(psl->a[1]), psl->a, psl->sizel * sizeof(SQDataType));
    7. psl->a[0] = x;
    8. psl->sizel++;
    9. }

    头删

    这里同样可以使用两种方法,这里我使用了最方便的memmove

    判断方法2可以准确的给出错误的位置,方便在代码行数过多时,找出错误

    判断方法1只是在发现出错后退出函数,不利于修改错误。

    大多情况我们使用方法2.

    1. //头删
    2. void SeqListPopFront(SL* psl)
    3. {
    4. assert(psl);
    5. //判断方法1:温柔检查
    6. //if (psl->size == 0)
    7. //{
    8. // printf("顺序表以为空,无法删除!\n");
    9. // return;
    10. //}
    11. //判断方法2:暴力检查
    12. assert(psl->sizel > 0);//判断顺序表中是否有数据
    13. memmove(psl->a, &(psl->a[1]), (psl->sizel - 1) * sizeof(SQDataType));
    14. //psl->a[psl->sizel - 1] = 0;
    15. //这行代码有点多余,下次尾插的值为0时将毫无意义,而顺序表是通过size1访问的,改变size1即可
    16. psl->sizel--;
    17. }

     尾删

    1. //尾删
    2. void SeqListPopBack(SL* psl)
    3. {
    4. assert(psl);
    5. //判断方法1:温柔检查
    6. //if (psl->size == 0)
    7. //{
    8. // printf("顺序表以为空,无法删除!\n");
    9. // return;
    10. //}
    11. //判断方法2:暴力检查
    12. assert(psl->sizel > 0);//判断顺序表中是否有数据
    13. psl->a[psl->sizel - 1] = NULL;
    14. psl->sizel--;
    15. }

     选择插入

    方法1:

    使用memmove函数调整表中元素位置后插入

    1. //选择插入
    2. void SeqListInsert(SL* psl, int index, SQDataType x)
    3. {
    4. assert(psl);
    5. assert(pos <= psl->sizel);
    6. SeqListCheckCapacity(psl);//增容
    7. memmove(&(psl->a[index + 1]), &(psl->a[index]), (psl->sizel - index) * sizeof(SQDataType));
    8. psl->a[index] = x;
    9. psl->sizel++;
    10. }

     方法2:

    使用循环依次移动元素最终插入

    1. //选择插入
    2. void SeqListInsert(SL* psl, int index, SQDataType x)
    3. {
    4. assert(psl);
    5. assert(index <= psl->sizel);//判断index范围是否合法
    6. SeqListCheckCapacity(psl);//增容
    7. int cou = psl->sizel;
    8. while (cou > index)
    9. {
    10. psl->a[cou] = psl->a[cou - 1];
    11. cou--;
    12. }
    13. psl->a[index] = x;
    14. psl->sizel++;
    15. }

     选择删除

    使用memmove函数覆盖所要删除的位置

    1. //选择删除
    2. void SeqListErase(SL* psl, int index)
    3. {
    4. assert(psl);
    5. assert(index < psl->sizel);
    6. memmove(&(psl->a[index]), &(psl->a[index + 1]), (psl->sizel - index - 1) * sizeof(SQDataType));
    7. psl->a[psl->sizel - 1] = NULL;
    8. psl->sizel--;
    9. }

    查找

    在顺序表中查找x,若找到返回下标,找不到则说明顺序表中没有改值

    1. //查找
    2. void SeqListFind(SL* psl, SQDataType x)
    3. {
    4. assert(psl);
    5. int num = 0;
    6. while (num < psl->sizel)
    7. {
    8. if (psl->a[num] == x)
    9. {
    10. printf("%d\n", num);
    11. return;
    12. }
    13. num++;
    14. }
    15. printf("表中没有%d\b", x);
    16. return;
    17. }

     修改

    给出要修改元素的下标和替换的值,进行替换操作。

    1. //修改
    2. void SeqListModity(SL* psl, int pos, SQDataType x)
    3. {
    4. assert(psl);
    5. assert(pos < psl->sizel && pos > 0);//判断给出的下标是否在范围内
    6. psl->a[pos] = x;
    7. }

    四.完整代码

    SeqList.h文件

    在头文件定义,存放函数、头文件和结构体的声明

    1. #pragma once
    2. #include
    3. #include
    4. #include
    5. #include
    6. #define N 10;
    7. typedef int SQDataType;
    8. typedef struct SeqList
    9. {
    10. SQDataType* a;
    11. int sizel; //有效数据个数
    12. int capacity; //容量
    13. }SL;
    14. //初始化
    15. void SeqListInit(SL* psl);
    16. //尾插入
    17. void SeqListPushBack(SL* psl, SQDataType x);
    18. //头插入
    19. void SeqListPushFront(SL* psl, SQDataType x);
    20. //头删
    21. void SeqListPopFront(SL* psl);
    22. //尾删
    23. void SeqListPopBack(SL* psl);
    24. //选择插入
    25. void SeqListInsert(SL* psl, int index, SQDataType x);
    26. //选择删除
    27. void SeqListErase(SL* psl, int index);
    28. //查找
    29. void SeqListFind(SL* psl, SQDataType x);
    30. //修改
    31. void SeqListModity(SL* psl, int pos, SQDataType x);
    32. //打印
    33. void SeqListPrint(SL* psl);
    34. //销毁空间
    35. void SeqListDestroy(SL* psl);

    SeqList.c文件

    函数的实现放在此文件

    1. #define _CRT_SECURE_NO_WARNINGS 1
    2. #include "SeqList.h"
    3. //初始化
    4. void SeqListInit(SL* psl)
    5. {
    6. psl->a = NULL;
    7. psl->capacity = 0;
    8. psl->sizel = 0;
    9. }
    10. //增容
    11. void SeqListCheckCapacity(SL* psl)
    12. {
    13. if (psl->capacity == psl->sizel)
    14. {
    15. int newcapacity = psl->capacity == 0 ? 4 : psl->capacity * 2;
    16. SQDataType* temp = (SQDataType*)realloc(psl->a, newcapacity * sizeof(SQDataType));
    17. assert(temp);
    18. psl->a = temp;
    19. psl->capacity = newcapacity;
    20. }
    21. }
    22. //尾插
    23. void SeqListPushBack(SL* psl, SQDataType x)
    24. {
    25. SeqListCheckCapacity(psl);//判断capacity是否足够,若不够进行增容
    26. psl->a[psl->sizel] = x;
    27. psl->sizel++;
    28. }
    29. //头插——方法1
    30. //void SeqListPushFront(SL* psl, SQDataType x)
    31. //{
    32. // SeqListCheckCapacity(psl);//增容
    33. // for (int i = psl->sizel-1; i >= 0; i--)
    34. // {
    35. // psl->a[i + 1] = psl->a[i];
    36. // }
    37. // psl->a[0] = x;
    38. // psl->sizel++;
    39. //}
    40. //头插——方法2
    41. void SeqListPushFront(SL* psl, SQDataType x)
    42. {
    43. SeqListCheckCapacity(psl);//增容
    44. memmove(&(psl->a[1]), psl->a, psl->sizel * sizeof(SQDataType));
    45. psl->a[0] = x;
    46. psl->sizel++;
    47. }
    48. //头删
    49. void SeqListPopFront(SL* psl)
    50. {
    51. assert(psl->sizel > 0);//判断顺序表中是否有数据
    52. memmove(psl->a, &(psl->a[1]), (psl->sizel - 1) * sizeof(SQDataType));
    53. psl->a[psl->sizel - 1] = 0;
    54. psl->sizel--;
    55. }
    56. //尾删
    57. void SeqListPopBack(SL* psl)
    58. {
    59. assert(psl->sizel > 0);//判断顺序表中是否有数据
    60. psl->a[psl->sizel - 1] = NULL;
    61. psl->sizel--;
    62. }
    63. //选择插入
    64. //void SeqListInsert(SL* psl, int index, SQDataType x)
    65. //{
    66. // assert(index <= psl->sizel);
    67. // SeqListCheckCapacity(psl);//增容
    68. // memmove(&(psl->a[index + 1]), &(psl->a[index]), (psl->sizel - index) * sizeof(SQDataType));
    69. // psl->a[index] = x;
    70. // psl->sizel++;
    71. //}
    72. //选择插入
    73. void SeqListInsert(SL* psl, int index, SQDataType x)
    74. {
    75. assert(index <= psl->sizel);
    76. SeqListCheckCapacity(psl);//增容
    77. int cou = psl->sizel;
    78. while (cou > index)
    79. {
    80. psl->a[cou] = psl->a[cou - 1];
    81. cou--;
    82. }
    83. psl->a[index] = x;
    84. psl->sizel++;
    85. }
    86. //选择删除
    87. void SeqListErase(SL* psl, int index)
    88. {
    89. assert(index < psl->sizel);
    90. memmove(&(psl->a[index]), &(psl->a[index + 1]), (psl->sizel - index - 1) * sizeof(SQDataType));
    91. psl->a[psl->sizel - 1] = NULL;
    92. psl->sizel--;
    93. }
    94. //查找
    95. void SeqListFind(SL* psl, SQDataType x)
    96. {
    97. int num = 0;
    98. while (num < psl->sizel)
    99. {
    100. if (psl->a[num] == x)
    101. {
    102. printf("%d\n", num);
    103. return;
    104. }
    105. num++;
    106. }
    107. printf("表中没有%d\b", x);
    108. return;
    109. }
    110. //修改
    111. void SeqListModity(SL* psl, int pos, SQDataType x)
    112. {
    113. assert(pos < psl->sizel);
    114. psl->a[pos] = x;
    115. }
    116. //打印链表
    117. void SeqListPrint(SL* psl)
    118. {
    119. for (int i = 0; i < psl->sizel; i++)
    120. {
    121. printf("%d ", psl->a[i]);
    122. }
    123. printf("\n");
    124. }
    125. //销毁空间
    126. void SeqListDestroy(SL* psl)
    127. {
    128. free(psl->a);
    129. psl->a = NULL;
    130. psl->capacity = 0;
    131. psl->sizel = 0;
    132. }

    text.c文件

    存放主函数,其它函数在此文件夹调用

    1. #define _CRT_SECURE_NO_WARNINGS 1
    2. #include
    3. #include "SeqList.h"
    4. //菜单
    5. void menu()
    6. {
    7. printf("**********************\n");
    8. printf("1.尾插数据,2.头插数据\n");
    9. printf("3.尾删数据,4.头删数据\n");
    10. printf("5.选择插入,6.选择删除\n");
    11. printf("7.查找元素,8.修改链表\n");
    12. printf("9.打印数据,-1,退出\n");
    13. printf("**********************\n");
    14. printf("请输入你的选择:");
    15. }
    16. int main()
    17. {
    18. SL slist;
    19. int choose = 0;
    20. SeqListInit(&slist);//初始化
    21. while (choose != -1)
    22. {
    23. int a = 0, b = 0;
    24. menu();
    25. scanf(" %d", &choose);
    26. switch (choose)
    27. {
    28. case 1://尾插
    29. printf("请输入你要插入的数据,以-1结束\n");
    30. while (a != -1)
    31. {
    32. scanf("%d", &a);
    33. if(a!=-1)
    34. SeqListPushBack(&slist, a);
    35. }
    36. break;
    37. case 2://头插
    38. printf("请输入你要插入的数据,以-1结束\n");
    39. while (a != -1)
    40. {
    41. scanf("%d", &a);
    42. if (a != -1)
    43. SeqListPushFront(&slist, a);
    44. }
    45. break;
    46. case 3://尾删
    47. SeqListPopBack(&slist);
    48. printf("尾删,删除成功!\n");
    49. break;
    50. case 4://头删
    51. SeqListPopFront(&slist);
    52. printf("头删,删除成功!\n");
    53. break;
    54. case 5://选择插入
    55. printf("请输入需要插入的下标和元素:");
    56. scanf("%d%d", &a, &b);
    57. SeqListInsert(&slist, a, b);
    58. break;
    59. case 6://选择删除
    60. printf("请输入需要删除的元素的下标:");
    61. scanf("%d", &a);
    62. SeqListErase(&slist, a);
    63. break;
    64. case 7://查找元素
    65. printf("请输入需要查找的元素的下标:");
    66. scanf("%d", &a);
    67. SeqListFind(&slist, a);
    68. break;
    69. case 8://修改链表
    70. printf("请输入需要修改的下标和元素:");
    71. scanf("%d%d", &a, &b);
    72. SeqListModity(&slist, a, b);
    73. break;
    74. case 9://打印
    75. SeqListPrint(&slist);
    76. break;
    77. case -1://退出
    78. SeqListDestroy(&slist);//销毁空间
    79. break;
    80. default:
    81. printf("输入错误,请重新输入!\n");
    82. break;
    83. }
    84. system("pause");
    85. system("cls");
    86. }
    87. return 0;
    88. }

    上述分模块写的代码为修改后的,添加了一些细节性的东西,下方完整代码为修改前的,懒得改了,可以正常使用。

  • 相关阅读:
    什么是EventEmitter?它在Node.js中有什么作用?
    机器学习中的特征选择:方法和 Python 示例
    使用Docker安装部署ElasticSearch和ElasticSearch-Head
    【LLM】提示工程技术提炼精华分享
    Windows内的Ubuntu虚拟机安装docker
    SVM算法原理解读
    shell脚本处理日志转化为JsonArray
    【深度学习】图像修复的一些模型
    新手使用vue引入cesium
    交通流的微观模型(Matlab代码实现)
  • 原文地址:https://blog.csdn.net/m0_52094687/article/details/126881530