• 动态顺序表的代码实现


    一、头文件

    Seqlist.h这个头文件中包含了顺序表的定义和对顺序表进行操作的所有函数,所有的函数只传递结构体指针以加快程序运行速度。

    1. #pragma once
    2. #include
    3. #include
    4. #include
    5. #define TYPE int//定义常量字符串类型进行替换,可以在顺序表内存储所有类型的变量
    6. struct SeqList
    7. {
    8. TYPE* SL;//维护动态开辟的内存的指针
    9. int volume;//当前的容量
    10. int size;//当前存储的有效数据的个数
    11. };
    12. typedef struct SeqList SList;//简化类型名
    13. //初始化
    14. void InitSeqlist(SList* p);
    15. //扩容
    16. void enlarge(SList* p);
    17. //打印
    18. void print(SList* p);
    19. //销毁
    20. void destory(SList* p);
    21. //对顺序表实现增删查改的函数
    22. //增加元素
    23. void Seqlist_front_push(SList* p, TYPE a);//前增
    24. void Seqlist_back_push(SList* p, TYPE a); //后增
    25. //减少元素
    26. void Seqlist_front_pop(SList* p); //前减
    27. void Seqlist_back_pop(SList* p);//后减
    28. //查找对应下标的元素,没有找到就返回-1
    29. int Seqlist_search_element(SList* p,TYPE a);
    30. //修改对应下标的元素
    31. void Seqlist_modify_element(SList* p, size_t pos, TYPE b);
    32. // 顺序表在pos位置插入a
    33. void SLInsert(SList* p, size_t pos, TYPE a);
    34. // 顺序表删除pos位置的值
    35. void SLErase(SList* p, size_t pos);

    二、函数

    这些函数储存在一个function.c 文件中

    1.初始化

    void InitSeqlist(SList* p);

    首先断言有没有创建相应的结构体,我们要逐步接受使用断言判断的写法,有利于C++的学习。然后整型值归零,指针置空

    1. void InitSeqlist(SList* p)
    2. {
    3. assert(p);
    4. p->size = 0;
    5. p->volume = 0;
    6. p->SL = NULL;
    7. }

    2.扩容

    void enlarge(SList* p);

    这个函数用于配合增加元素时在适当时扩大容量,在代码中就是当前的容量与当前存储的有效数据的个数相同时扩容

    1. void enlarge(SList* p)
    2. {
    3. if (p->size == p->volume)//容量与数据量相同扩容,每次扩容当前二倍大小的空间
    4. {
    5. assert(p);
    6. int newvolume = (p->volume == 0 ? 4 : 2 * p->volume);
    7. //定义一个变量保存新容量的大小,容量为0扩容4个,不为0扩容二倍
    8. TYPE* p1 = (TYPE*)realloc(p->SL, newvolume*sizeof(TYPE));
    9. //容量为0时,malloc与realloc效果相同
    10. if (p1 == NULL)
    11. {
    12. perror("realloc");
    13. return;
    14. }
    15. p->SL = p1;
    16. p->volume = newvolume;
    17. }
    18. }

    3.打印所有元素

    void print(SList* p);

    与数组的打印相同

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

    4.销毁

    void destory(SList* p);

    释放指针管理的内容,但是此时指针依旧指向那个空间的头地址,指针需要置空以避免野指针。最后整型值归零

    1. void destory(SList* p)
    2. {
    3. assert(p);
    4. free(p->SL);
    5. p->size = 0;
    6. p->volume = 0;
    7. p->SL = NULL;
    8. }

    5.增加元素

    (1)前增

    void Seqlist_front_push(SList* p, TYPE a);

    在头部增加,此时头部有内容,就需要从后向前的顺序一个一个向后挪一位,然后有效数据个数加一

    1 2 3 4 5(原数据)

    1 2 3 4 5 5(5后挪一位)

    1 2 3 4 4 5(4后挪一位)

    ……

    1 1 2 3 4 5(1后挪一位)

    a 1 2 3 4 5(头插入数据)

    顺序表的头插的时间复杂度为O(N),这是顺序表的缺点:头插复杂

    1. void Seqlist_front_push(SList* p, TYPE a)
    2. {
    3. assert(p);
    4. enlarge(p);//函数负责在适当时负责扩容
    5. int i = p->size;
    6. while (i >= 0)
    7. {
    8. p->SL[i] = p->SL[i - 1];//顺序表的头插需要将所有数据从后向前后挪一位
    9. i--;
    10. }
    11. *(p->SL) = a;//插入数据
    12. p->size++;//自增
    13. }

    (2)后增

    void Seqlist_back_push(SList* p, TYPE a);

    后增就比较简单,直接在下标为size的所在的位置添加数据

    1. void Seqlist_back_push(SList* p, TYPE a)
    2. {
    3. assert(p);
    4. enlarge(p);//函数负责在适当时负责扩容
    5. *((p->SL) + (p->size)) = a;//此时size正好是应插入位置的下标
    6. p->size++;//size 自增
    7. }

    6.减少元素

    (1)前减

    void Seqlist_front_pop(SList* p);

    在头部减少,此时尾部有内容,把后面的当作前面的,就需要从第二个开始按照从前向后的顺序一个一个向前挪一位,然后有效数据个数减一

    1 2 3 4 5(原数据)

    2 2 3 4 5(2前挪一位)

    2 3 3 4 4 5(3前挪一位)

    ……

    2 3 4 5 5(5前挪一位)

    此时有效数据个数减一后,后面的5不在指针管理的范围内,注意我们减少数据时不需要缩容

    1. void Seqlist_front_pop(SList* p)
    2. {
    3. assert(p);
    4. int i = 0;
    5. for (i = 0; i < p->size - 1; i++)
    6. {
    7. p->SL[i] = p->SL[i + 1];//把每一个数据从前向后挪一位
    8. }
    9. p->size--;
    10. }

    顺序表的头删的时间复杂度也为O(N),这也是顺序表的缺点:头删复杂

    (2)后减

    void Seqlist_back_pop(SList* p);

    尾删直接有效数据个数减一,后面的数据就不在指针管理的内存内了

    1. void Seqlist_back_pop(SList* p)
    2. {
    3. assert(p);
    4. p->size--;//只需要减少有效数据的个数,自减即可
    5. }

    7.查找对应下标的元素,没有找到就返回-1

    int Seqlist_search_element(SList* p,TYPE a);

    我们默认元素中没有-1,遍历数组寻找即可

    1. int Seqlist_search_element(SList* p, TYPE a)
    2. {
    3. assert(p);
    4. int i = 0;
    5. for (i = 0; i < p->size; i++)
    6. {
    7. if (p->SL[i] == a)
    8. {
    9. return i;//找到了返回下标
    10. }
    11. }
    12. return -1;//找不到返回-1
    13. }

    8.修改对应下标的元素

    void Seqlist_modify_element(SList* p, size_t pos, TYPE b);

    这个函数就直接通过下标找到数据并修改。如果想要实现查找并修改,那么就在查找的基础上找到后修改对应的值就可以了。

    1. void Seqlist_modify_element(SList* p, size_t pos, TYPE b)
    2. {
    3. p->SL[pos] = b;//改变某个下标对应的数据
    4. }

    9.顺序表在pos位置插入a

    void SLInsert(SList* p, size_t pos, TYPE a);

    包括pos从后向前后挪一位再赋值

    1. void Seqlist_insert_element(SList* p, int pos, TYPE a)
    2. {
    3. assert(p);
    4. assert(pos < (p->size));
    5. enlarge(p);
    6. int i = pos;
    7. for (i = pos; i < p->size; i++)
    8. {
    9. p->SL[i + 1] = p->SL[i];
    10. }
    11. p->SL[pos] = a;
    12. p->size++;
    13. }

    10.顺序表删除pos位置的值

    void SLErase(SList* p, size_t pos);

    从前向后覆盖pos后的数据

    1. void Seqlist_delete_element(SList* p, int pos)
    2. {
    3. int i = 0;
    4. for (i = pos; i < p->size - 1;i++)
    5. {
    6. p->SL[i] = p->SL[i + 1];//从前向后覆盖pos后的数据
    7. }
    8. p->size--;//自减
    9. }

    三、调试

    通过test.c来进行操作

    1. void test1(SList* p)
    2. {
    3. Seqlist_front_push(p, 2);
    4. Seqlist_front_push(p, 1);
    5. Seqlist_back_push(p, 3);
    6. Seqlist_back_push(p, 4);
    7. print(p);
    8. Seqlist_back_pop(p);
    9. Seqlist_front_pop(p);
    10. print(p);
    11. }
    12. void test2(SList* p)
    13. {
    14. Seqlist_back_push(p, 1);
    15. Seqlist_back_push(p, 2);
    16. Seqlist_back_push(p, 3);
    17. Seqlist_back_push(p, 4);
    18. Seqlist_back_push(p, 5);
    19. Seqlist_back_push(p, 6);
    20. print(p);
    21. Seqlist_modify_element(p, Seqlist_search_element(p, 4), 10);
    22. print(p);
    23. Seqlist_insert_element(p, 5, 15);
    24. print(p);
    25. Seqlist_delete_element(p, 2);
    26. print(p);
    27. }
    28. int main()
    29. {
    30. SList s;
    31. SList* p = &s;
    32. InitSeqlist(p);
    33. //test1(p);
    34. test2(p);
    35. destory(p);
    36. return 0;
    37. }

  • 相关阅读:
    亲爱的朋友
    AcWing 827. 双链表
    为什么要使用 kafka,为什么要使用消息队列?
    Elasticsearch(三)聚合基本使用
    红帽权限设置及提权知识点结合
    Python安装selenium时报错:ERROR: No matching distribution found for selenium 附解决方法
    flutter系列之:Navigator的高级用法
    Docker打包python镜像(Windows)
    SpringAMQP对RabbitMQ消息的确认
    Ansys Maxwell三相变压器制作方法教程
  • 原文地址:https://blog.csdn.net/qq_65285898/article/details/126465227