当前位置:   article > 正文

顺序表(数据结构)

顺序表

目录

前情提示

概念

内容

1.顺序表的定义

2.顺序表的初始化

3.顺序表的销毁

4.检查空间

5.顺序表的尾插

6.顺序表的打印

7.顺序表的尾删

8.顺序表的头插

9.顺序表的头删

10.顺序表的指定位置插入

 11.顺序表指定位置值的删除

12.顺序表的查找

13.顺序表修改pos位置的值

总代码(想直接看结果的可以看这里)

在 SeqList.h 下

在 SeqList.c 下

在 Test.c 下


前情提示

SeqList.h  用于  引用的头文件、顺序表的定义、接口的函数声明。

SeqList.c  用于  接口函数的定义。

Test.c       用于   顺序表功能的测试。


概念

线性表是最基本、最简单、也是最常用的一种数据结构。一个线性表是n个具有相同特性的数据元素的有限序列。常见的线性表:顺序表、链表、栈、队列、字符串...

线性表在逻辑上是线性结构,也就说是连续的一条直线。但是在物理结构上并不一定是连续的, 线性表在物理上存储时,通常以 数组链式结构的形式存储。
顺序表是用一段物理地址连续的存储单元依次存储数据元素的线性结构,一般情况下采用数组存储。在数组上完成数据的增删查改。
          

 顺序表分为:静态顺序表动态顺序表

1. 静态顺序表:使用定长数组存储元素。( 空间开多了浪费,开少了不够用 )

2. 动态顺序表:使用动态开辟的数组存储。(按需申请)

静态顺序表只适用于确定知道需要存多少数据的场景。不适用于现实生活中的实际情况,所以接下来我们只讲解动态顺序表。


内容

1.顺序表的定义

在 SeqList.h 下

  1. #pragma once//使同一个文件不会被包含(include)多次,不必担心宏名冲突。
  2. //先将可能使用到的头文件写上
  3. #include<stdio.h>
  4. #include<stdlib.h>
  5. #include<assert.h>
  6. typedef int SLDataType;//顺序表的类型名称,给变量定义一个易于记忆且意义明确的新名字,
  7. //并且便于以后存储其它类型时方便改动.
  8. //(比如我晚点想存double类型的数据,我就直接将 int 改为 double )
  9. typedef struct SeqList
  10. {
  11. SLDataType* a;//指向动态开辟的数组。
  12. size_t size;//有效数据个数
  13. size_t capacity;//空间容量
  14. }SL;
  15. //struct 关键字和 SeqList 一起构成了这个结构类型。
  16. //typedef 为这个结构起了一个别名,叫 SL,即:typedef struct SeqList SL 。
  17. //现在就可以像 int 和 double 那样直接使用 SL 定义变量。

2.顺序表的初始化

在 SeqList.h 下

  1. #define INIT_CAPACITY 4//初始化的容量
  2. //顺序表初始化
  3. //我们传地址而不是传值,因为形参是实参的拷贝,形参的改变不影响实参。
  4. void SLInit(SL* ps);

在 SeqList.c 下

  1. #include"SeqList.h"//别忘了
  2. void SLInit(SL* ps)
  3. {
  4. assert(ps);//断言
  5. //用malloc申请了一块空间
  6. ps->a = (SLDataType*)malloc(sizeof(SLDataType)*INIT_CAPACITY);
  7. //表示:malloc申请开辟 sizeof(int)乘以4 即16个字节大小的空间后,强制类型转换成(int*)
  8. if (ps->a == NULL)//如果开辟失败
  9. {
  10. perror("malloc fail");//输出错误信息
  11. return;
  12. }
  13. ps->size = 0;
  14. ps->capacity = INIT_CAPACITY;//初始化的时候先开辟一点空间
  15. }

提醒:

对malloc函数和sizeof操作符熟悉的可以跳过这一部分。

malloc函数内参数要求是size_t类型的,返回类型是void*。

如果分配成功则返回指向被分配内存的指针,否则返回空指针NULL。

在使用malloc开辟空间时,使用完成一定要释放空间(free),如果不释放会造内存泄漏。

malloc的头文件,在ANSI标准建议使用stdlib.h头文件,但许多C编译要求用malloc.h。

 在 Test.c 下

  1. #include"SeqList.h"//别忘了
  2. //用于接口函数功能的测试
  3. void TestSeqList1()
  4. {
  5. SL s;
  6. SLInit(&s);
  7. }
  8. int main()
  9. {
  10. TestSeqList1();//调用测试函数
  11. return 0;
  12. }

3.顺序表的销毁

在 SeqList.h 下

  1. // 顺序表销毁
  2. void SLDestroy(SL* ps);

在 SeqList.c 下

  1. // 顺序表销毁
  2. void SLDestroy(SL* ps)
  3. {
  4. assert(ps);//断言,最好加上,防止有些人直接将指针初始化为 NULL,而不用SLInit()函数
  5. free(ps->a);//释放a
  6. ps->a = NULL;//归还空间
  7. ps->capacity = ps->size = 0;//有效数据个数和空间容量都赋值为0
  8. //将0赋给size,再将size赋给capacity
  9. }

在 Test.c 下

  1. //用于接口函数功能的测试
  2. void TestSeqList1()
  3. {
  4. SL s;
  5. SLInit(&s);
  6. SLDestroy(&s);
  7. }

4.检查空间

在 SeqList.h 下

  1. //检查空间,如果满了,进行增容
  2. void SLCheckCapacity(SL* ps);

在 SeqList.c 下

扩容一般一次增容 2 倍,你也可以扩3倍、4倍。

  1. //检查空间
  2. void SLCheckCapacity(SL* ps)
  3. {
  4. assert(ps);//断言
  5. //判断是否扩容,若是,则扩
  6. if (ps->size == ps->capacity)//若最后一个数据的下一个位置的下标等于空间容量,则需扩容
  7. {
  8. //realloc的注意事项可看下文。
  9. //很多人容易把下面这一行代码写成
  10. //SLDataType*tmp=(SLDataType*)realloc(ps->a,ps->capacity*2);->这只扩到8个字节
  11. SLDataType*temp=(SLDataType*)realloc(ps->a,sizeof(SLDataType)*ps->capacity*2);
  12. //扩的空间是原来的两倍->扩到32个字节
  13. //realloc(a地址,izeof(int)*4*2)后强制类型转化,
  14. //从void*转化成int*类型,赋值给int*类型的temp
  15. if (temp == NULL)//如果申请失败
  16. {
  17. perror("realloc fail");//报错
  18. return;
  19. }
  20. ps->a = temp;//a接收realloc返回的指针,realloc不一定原地扩容,可能原地、异地
  21. //如果美甲上面那行代码程序没有报错,只是巧合,刚好原地扩容了。
  22. ps->capacity *= 2;//如果扩容成功,size不变,capacity是原来2倍
  23. }
  24. }

提醒:

对realloc函数熟悉的可以跳过这一部分。

realloc函数返回的是void*类型的指针,指向在堆区重新开辟的内存块的起始地址,ptr是先前开辟的内存块的指针,size_t size指的是New size in bytes,新的字节数,注意不是增加的字节数,而是新开辟的那块内存空间的字节数。如果申请失败,将返回NULL,此时,原来的指针仍然有效。如果调用成功,不管当前内存段后面的空闲空间是否满足要求,都会释放掉原来的指针,重新返回一个指针。

5.顺序表的尾插

在 SeqList.h 下

  1. // 顺序表尾插——在顺序表的最后插入一个数据
  2. void SLPushBack(SL* ps, SLDataType x);//x为插入的数据

在 SeqList.c 下

有图可知:sz是数据个数,同时也是最后一个数据的下一个位置的下标

  1. //顺序表的尾插
  2. void SLPushBack(SL* ps, SLDataType x)
  3. {
  4. assert(ps);//断言
  5. SLCheckCapacity(ps);//扩容
  6. if (temp == NULL)//如果申请失败
  7. {
  8. perror("realloc fail");//报错
  9. return;
  10. }
  11. //sz是数据个数,同时也是最后一个数据的下一个位置的下标
  12. ps->a[ps->size++] = x;
  13. //意思是:ps->a[ps->size] = x;
  14. // ps->size++;
  15. }

在 Test.c 下

  1. //用于接口函数功能的测试
  2. void TestSeqList1()
  3. {
  4. SL s;
  5. SLInit(&s);
  6. SLPushBack(&s, 1);
  7. SLPushBack(&s, 2);
  8. SLPushBack(&s, 3);
  9. SLPushBack(&s, 4);
  10. SLPushBack(&s, 5);
  11. SLPushBack(&s, 6);
  12. SLDestroy(&s);
  13. }

6.顺序表的打印

在 SeqList.h 下

  1. //顺序表打印
  2. void SLPrint(SL* ps);

在 SeqList.c 下

  1. // 顺序表打印
  2. void SLPrint(SL* ps)
  3. {
  4. assert(ps);//断言
  5. for (size_t i = 0; i < ps->size; ++i)
  6. {
  7. printf("%d ", ps->a[i]);
  8. }
  9. printf("\n");
  10. }

在 Test.c 下

  1. //用于接口函数功能的测试
  2. void TestSeqList1()
  3. {
  4. SL s;
  5. SLInit(&s);
  6. SLPushBack(&s, 1);
  7. SLPushBack(&s, 2);
  8. SLPushBack(&s, 3);
  9. SLPushBack(&s, 4);
  10. SLPushBack(&s, 5);
  11. SLPushBack(&s, 6);
  12. SLPrint(&s);
  13. SLDestroy(&s);
  14. }

7.顺序表的尾删

在 SeqList.h 下

  1. // 顺序表尾删——在顺序表的最后删除一个数据
  2. void SLPopBack(SL* ps);

在 SeqList.c 下

  1. // 顺序表尾删
  2. void SLPopBack(SL* ps)
  3. {
  4. assert(ps);//断言
  5. //size为 0之后就不能再删除了!
  6. if (ps->size == 0)
  7. {
  8. return;
  9. }
  10. //或者
  11. //assert(ps->size>0);
  12. //加不加 ps->a[ps->size - 1] = 0;都无所谓
  13. ps->size--;
  14. }

在 Test.c 下

  1. //用于接口函数功能的测试
  2. void TestSeqList1()
  3. {
  4. SL s;
  5. SLInit(&s);
  6. SLPushBack(&s, 1);
  7. SLPushBack(&s, 2);
  8. SLPushBack(&s, 3);
  9. SLPushBack(&s, 4);
  10. SLPushBack(&s, 5);
  11. SLPushBack(&s, 6);
  12. SLPrint(&s);
  13. SLPopBack(&s);
  14. SLPopBack(&s);
  15. SLPrint(&s);
  16. SLDestroy(&s);
  17. }

提醒:

若size为0之后还继续减,则size会取max(int)值。

 

注意:

很多人到这里有一个疑问,就是顺序表可以扩容,那我尾删后可以缩容(释放部分)吗?

不能,因为操作系统的内存管理不支持,操作系统支持内存整块的申请,整块的释放。

8.顺序表的头插

思路:挪动数据(在SeqList.c中体现)

............ 

 

在 SeqList.h 下

  1. // 顺序表头插——在顺序表的开头插入一个数据
  2. void SLPushFront(SL* ps, SLDataType x);//x为插入的数据

在 SeqList.c 下

  1. // 顺序表头插
  2. void SLPushFront(SL* ps, SLDataType x)
  3. {
  4. assert(ps);//断言
  5. SLCheckCapacity(ps);//扩容
  6. int end = (int)ps->size - 1;//思路理解看上图
  7. while (end >= 0)
  8. {
  9. ps->a[end + 1] = ps->a[end];
  10. --end;
  11. }
  12. ps->a[0] = x;
  13. ps->size++;
  14. }

在 Test.c 下

  1. //用于接口函数功能的测试
  2. void TestSeqList2()
  3. {
  4. SL s;
  5. SLInit(&s);
  6. SLPushFront(&s, 1);
  7. SLPushFront(&s, 2);
  8. SLPushFront(&s, 3);
  9. SLPushFront(&s, 4);
  10. SLPushFront(&s, 5);
  11. SLPrint(&s);
  12. }
  13. int main()
  14. {
  15. //TestSeqList1();
  16. TestSeqList2();
  17. return 0;
  18. }

9.顺序表的头删

思路:挪动数据(在SeqList.c中体现)

 

 .........

在 SeqList.h 下

  1. // 顺序表头删——在顺序表的开头删除一个数据
  2. void SLPopFront(SL* ps);

在 SeqList.c 下

  1. // 顺序表头删
  2. void SLPopFront(SL* ps)
  3. {
  4. assert(ps);//断言
  5. assert(ps->size > 0);//防止size为 0的时候,跳过循环,继续减减。
  6. int begin = 1;//思路理解看上图
  7. while (begin < (int)ps->size)
  8. {
  9. ps->a[begin - 1] = ps->a[begin];
  10. ++begin;
  11. }
  12. ps->size--;
  13. }

在 Test.c 下

  1. void TestSeqList2()
  2. {
  3. SL s;
  4. SLInit(&s);
  5. SLPushFront(&s, 1);
  6. SLPushFront(&s, 2);
  7. SLPushFront(&s, 3);
  8. SLPushFront(&s, 4);
  9. SLPushFront(&s, 5);
  10. SLPrint(&s);
  11. SLPopFront(&s);
  12. SLPrint(&s);
  13. SLPopFront(&s);
  14. SLPrint(&s);
  15. SLPopFront(&s);
  16. SLPrint(&s);
  17. }

注意:头插/头删N个数据时间复杂度为0(N^2)

           尾插/尾删N个数据时间复杂度为0(N)

10.顺序表的指定位置插入

思路:挪动数据(在SeqList.c中体现)

 

 

 

 

在 SeqList.h 下

  1. // 顺序表在pos位置插入x
  2. void SLInsert(SL* ps, size_t pos, SLDataType x);

 在 SeqList.c 下

  1. // 顺序表在pos位置插入x
  2. void SLInsert(SL* ps, size_t pos, SLDataType x)
  3. {
  4. assert(ps);//断言
  5. assert(pos >= 0 && pos <= ps->size);//保证pos在0与size之间
  6. //取等时相当于头插/尾插
  7. SLCheckCapacity(ps);//扩容
  8. int end = ps->size - 1;
  9. while (end >= (int)pos)//这里特别注意强制类型转换
  10. //不改动其它,只将int end改成 size_t end会走死循环
  11. {
  12. ps->a[end + 1] = ps->a[end];
  13. --end;
  14. }
  15. //或者下面这种写法
  16. //size_t end = ps->size;
  17. //while (end >pos)
  18. //{
  19. // ps->a[end] = ps->a[end-1];
  20. // --end;
  21. //}
  22. ps->a[pos] = x;
  23. ps->size++;
  24. }

学会在指定位置插入值的函数后,发现头插和尾插也能用这个函数。即:

  1. void SLPushFront(SL* ps, SLDataType x)
  2. {
  3. SLInsert(ps,0,x);
  4. }
  1. void SLPushBack(SL* ps, SLDataType x)
  2. {
  3. SLInsert(ps,ps->size,x);
  4. }

在 Test.c 下

  1. //用于接口函数功能的测试
  2. void TestSeqList3()
  3. {
  4. SL s;
  5. SLInit(&s);
  6. SLPushFront(&s, 0);
  7. SLPushFront(&s, 2);
  8. SLInsert(&s,0,5);
  9. SLPrint(&s);
  10. }
  11. int main()
  12. {
  13. //TestSeqList1();
  14. //TestSeqList2();
  15. TestSeqList3();
  16. return 0;
  17. }

 11.顺序表指定位置值的删除

思路:挪动数据(在SeqList.c中体现)

 

 

在 SeqList.h 下

  1. // 顺序表删除pos位置的值
  2. void SLErase(SL* ps, size_t pos);

 在 SeqList.c 下

  1. // 顺序表删除pos位置的值
  2. void SLErase(SL* ps, size_t pos)
  3. {
  4. assert(ps);
  5. assert(pos >= 0 && pos < ps->size);
  6. //注意:pos不能等于size,这里和指定位置插入不一样,
  7. //并且间接防止了size为0的时候,跳过循环,继续减减。
  8. int begin = pos + 1;
  9. while (begin <(int)ps->size)
  10. {
  11. ps->a[begin - 1] = ps->a[begin];
  12. ++begin;
  13. }
  14. ps->size--;
  15. }

在 Test.c 下

  1. void TestSeqList4()
  2. {
  3. SL s;
  4. SLInit(&s);
  5. SLPushFront(&s, 1);
  6. SLPushFront(&s, 2);
  7. SLPushFront(&s, 3);
  8. SLPushFront(&s, 4);
  9. SLPushFront(&s, 5);
  10. SLPushFront(&s, 6);
  11. SLPushFront(&s, 7);
  12. SLPushFront(&s, 8);
  13. SLPushFront(&s, 9);
  14. SLPrint(&s);
  15. SLInsert(&s, 4, 666);
  16. SLPrint(&s);
  17. SLInsert(&s, 0, 666);
  18. SLPrint(&s);
  19. SLErase(&s, 4);
  20. SLPrint(&s);
  21. SLErase(&s, 4);
  22. SLPrint(&s);
  23. }
  24. int main()
  25. {
  26. //TestSeqList1();
  27. //TestSeqList2();
  28. //TestSeqList3();
  29. TestSeqList4();
  30. return 0;
  31. }

 学会删除指定位置的值的函数后,发现头删和尾删也能用这个函数。即:

  1. void SLPopFront(SL* ps)
  2. {
  3. SLErase(ps,0);
  4. }
  1. void SLPopBack(SL* ps)
  2. {
  3. SLErase(ps,ps->size-1);
  4. }

12.顺序表的查找

在 SeqList.h 下

  1. // 顺序表查找
  2. int SLFind(SL* ps, SLDataType x);//x为查找的数据

 在 SeqList.c 下

  1. // 顺序表查找
  2. int SLFind(SL* ps, SLDataType x)
  3. {
  4. assert(ps);
  5. for (int i = 0; i < (int)ps->size; ++i)
  6. {
  7. if (ps->a[i] == x)//如果找到了
  8. {
  9. return i;//则返回要找的值的下标
  10. }
  11. }
  12. return -1;//否则返回-1
  13. }

在 Test.c 下

  1. void TestSeqList5()
  2. {
  3. SL s;
  4. SLInit(&s);
  5. int result = 0;
  6. SLPushFront(&s, 1);
  7. SLPushFront(&s, 2);
  8. SLPushFront(&s, 3);
  9. SLPushFront(&s, 4);
  10. SLPushFront(&s, 5);
  11. SLPrint(&s);
  12. result=SLFind(&s, 3);
  13. printf("%d\n", result);
  14. }
  15. int main()
  16. {
  17. //TestSeqList1();
  18. //TestSeqList2();
  19. //TestSeqList3();
  20. //TestSeqList4();
  21. TestSeqList5();
  22. return 0;
  23. }

13.顺序表修改pos位置的值

在 SeqList.h 下

  1. //顺序表修改pos位置的值
  2. void SLModify(SL* ps, size_t pos, SLDataType x);//x为修改后的值

 在 SeqList.c 下

  1. //顺序表修改pos位置的值
  2. void SLModify(SL* ps, size_t pos, SLDataType x)
  3. {
  4. assert(ps);
  5. assert(pos >= 0 && pos < ps->size);//既防止了size等于0,又规范了pos的位置
  6. ps->a[pos] = x;
  7. }

在 Test.c 下

  1. void TestSeqList6()
  2. {
  3. SL s;
  4. SLInit(&s);
  5. SLPushFront(&s, 1);
  6. SLPushFront(&s, 2);
  7. SLPushFront(&s, 3);
  8. SLPushFront(&s, 4);
  9. SLPushFront(&s, 5);
  10. SLPrint(&s);
  11. SLModify(&s, 2, 1);
  12. SLPrint(&s);
  13. }
  14. int main()
  15. {
  16. //TestSeqList1();
  17. //TestSeqList2();
  18. //TestSeqList3();
  19. //TestSeqList4();
  20. //TestSeqList5();
  21. TestSeqList6();
  22. return 0;
  23. }

总代码(想直接看结果的可以看这里)

在 SeqList.h 下

  1. #pragma once//使同一个文件不会被包含(include)多次,不必担心宏名冲突。
  2. //使用到的头文件
  3. #include<stdio.h>
  4. #include<stdlib.h>
  5. #include<assert.h>
  6. typedef int SLDataType;//顺序表的类型名称,给变量定义一个易于记忆且意义明确的新名字,
  7. //并且便于以后存储其它类型时方便改动。
  8. //(比如我晚点想存double类型的数据,我就直接将int改为double)
  9. #define INIT_CAPACITY 4//初始化的容量
  10. typedef struct SeqList
  11. {
  12. SLDataType* a;//指向动态开辟的数组
  13. size_t size;//有效数据个数
  14. size_t capacity;//空间容量
  15. }SL;
  16. //struct 关键字和 SeqList 一起构成了这个结构类型。
  17. //typedef 为这个结构起了一个别名,叫 SL,即:typedef struct SeqList SL 。
  18. //现在就可以像 int 和 double 那样直接使用 SL 定义变量。
  19. //基本增删查改接口
  20. //顺序表初始化
  21. //我们传地址而不是传值,因为形参是实参的拷贝,形参的改变不影响实参。
  22. void SLInit(SL* ps);
  23. // 顺序表销毁
  24. void SLDestroy(SL* ps);
  25. //顺序表打印
  26. void SLPrint(SL* ps);
  27. // 顺序表尾插——在顺序表的最后插入一个数据
  28. void SLPushBack(SL* ps, SLDataType x);//x为插入的数据
  29. // 顺序表尾删——在顺序表的最后删除一个数据
  30. void SLPopBack(SL* ps);
  31. // 顺序表头插——在顺序表的开头插入一个数据
  32. void SLPushFront(SL* ps, SLDataType x);//x为插入的数据
  33. // 顺序表头删——在顺序表的开头删除一个数据
  34. void SLPopFront(SL* ps);
  35. //检查空间,如果满了,进行增容
  36. void SLCheckCapacity(SL* ps);
  37. // 顺序表在pos位置插入x
  38. void SLInsert(SL* ps, size_t pos, SLDataType x);//x为插入的数据
  39. // 顺序表删除pos位置的值
  40. void SLErase(SL* ps, size_t pos);
  41. // 顺序表查找
  42. int SLFind(SL* ps, SLDataType x);//x为查找的数据
  43. //顺序表修改pos位置的值
  44. void SLModify(SL* ps, size_t pos, SLDataType x);//x为修改后的值

在 SeqList.c 下

  1. #include"SeqList.h"//别忘了
  2. //顺序表初始化
  3. void SLInit(SL* ps)
  4. {
  5. assert(ps);//断言
  6. //用malloc申请了一块空间
  7. ps->a = (SLDataType*)malloc(sizeof(SLDataType)*INIT_CAPACITY);
  8. //表示:malloc申请开辟 sizeof(int)乘以4
  9. //即16个字节大小的空间后,强制类型转换成(int*)
  10. if (ps->a == NULL)//如果开辟失败
  11. {
  12. perror("malloc fail");//输出错误信息
  13. return;
  14. }
  15. ps->size = 0;
  16. ps->capacity = INIT_CAPACITY;//初始化的时候先开辟一点空间
  17. }
  18. // 顺序表销毁
  19. void SLDestroy(SL* ps)
  20. {
  21. assert(ps);//断言,最好加上,防止有些人直接将指针初始化为NULL,而不用SLInit()函数
  22. free(ps->a);//释放a
  23. ps->a = NULL;//归还空间
  24. ps->capacity = ps->size = 0;//有效数据个数和空间容量都赋值为0
  25. }
  26. //检查空间
  27. void SLCheckCapacity(SL* ps)
  28. {
  29. assert(ps);
  30. //判断是否扩容,若是,则扩
  31. if (ps->size == ps->capacity)//若最后一个数据的下一个位置的下标等于空间容量,则需扩容
  32. {
  33. //realloc的注意事项可看下文。
  34. //很多人容易把下面这一行代码写成
  35. //SLDataType*tmp=(SLDataType*)realloc(ps->a,ps->capacity*2);->这只扩到8个字节
  36. SLDataType*temp=(SLDataType*)realloc(ps->a,sizeof(SLDataType)*ps->capacity*2);
  37. //扩的空间是原来的两倍->扩到32个字节
  38. //realloc(a地址sizeof(int)*4*2)后,
  39. //强制类型转化从void*转化成int*类型赋值给int*类型的temp
  40. if (temp == NULL)//如果申请失败
  41. {
  42. perror("realloc fail");//报错
  43. return;
  44. }
  45. ps->a = temp;//a接收realloc返回的指针,realloc不一定原地扩容,可能原地、异地
  46. 如果美甲上面那行代码程序没有报错,只是巧合,刚好原地扩容了。
  47. ps->capacity *= 2;//如果扩容成功,size不变,capacity是原来2倍
  48. }
  49. }
  50. //顺序表的尾插
  51. void SLPushBack(SL* ps, SLDataType x)
  52. {
  53. assert(ps);//断言
  54. SLCheckCapacity(ps);//扩容
  55. //sz是数据个数,同时也是最后一个数据的下一个位置的下标
  56. ps->a[ps->size++] = x;
  57. //意思是:ps->a[ps->size] = x;
  58. // ps->size++;
  59. }
  60. // 顺序表打印
  61. void SLPrint(SL* ps)
  62. {
  63. assert(ps);//断言
  64. for (size_t i = 0; i < ps->size; ++i)
  65. {
  66. printf("%d ", ps->a[i]);
  67. }
  68. printf("\n");
  69. }
  70. // 顺序表尾删
  71. void SLPopBack(SL* ps)
  72. {
  73. assert(ps);
  74. //size为0之后就不能再删除了!
  75. if (ps->size == 0)
  76. {
  77. return;
  78. }
  79. //或者
  80. //assert(ps->size>0);
  81. //加不加ps->a[ps->size - 1] = 0;都无所谓
  82. ps->size--;
  83. }
  84. // 顺序表头插
  85. void SLPushFront(SL* ps, SLDataType x)
  86. {
  87. assert(ps);//断言
  88. SLCheckCapacity(ps);//扩容
  89. int end = ps->size - 1;
  90. while (end >= 0)
  91. {
  92. ps->a[end + 1] = ps->a[end];
  93. --end;
  94. }
  95. ps->a[0] = x;
  96. ps->size++;
  97. }
  98. // 顺序表头删
  99. void SLPopFront(SL* ps)
  100. {
  101. assert(ps);//断言
  102. assert(ps->size > 0);//防止size为0的时候,跳过循环,继续减减。
  103. int begin = 1;
  104. while (begin < (int)ps->size)
  105. {
  106. ps->a[begin - 1] = ps->a[begin];
  107. ++begin;
  108. }
  109. ps->size--;
  110. }
  111. // 顺序表在pos位置插入x
  112. void SLInsert(SL* ps, size_t pos, SLDataType x)
  113. {
  114. assert(ps);//断言
  115. assert(pos >= 0 && pos <= ps->size);//保证pos在0与size之间
  116. //取等时相当于头插/尾插
  117. SLCheckCapacity(ps);//扩容
  118. int end = ps->size - 1;
  119. while (end >= (int)pos)//这里特别注意强制类型转换,不然容易死循环
  120. {
  121. ps->a[end + 1] = ps->a[end];
  122. --end;
  123. }
  124. //或者下面这种写法
  125. //size_t end = ps->size;
  126. //while (end >pos)
  127. //{
  128. // ps->a[end] = ps->a[end-1];
  129. // --end;
  130. //}
  131. ps->a[pos] = x;
  132. ps->size++;
  133. }
  134. // 顺序表删除pos位置的值
  135. void SLErase(SL* ps, size_t pos)
  136. {
  137. assert(ps);//断言
  138. assert(pos >= 0 && pos < ps->size);
  139. //注意:
  140. //pos不能等于size,这里和指定位置插入不一样并且间接防止了size为0的时候,跳过循环,继续减减
  141. int begin = pos + 1;
  142. while (begin <(int)ps->size)
  143. {
  144. ps->a[begin - 1] = ps->a[begin];
  145. ++begin;
  146. }
  147. ps->size--;
  148. }
  149. // 顺序表查找
  150. int SLFind(SL* ps, SLDataType x)
  151. {
  152. assert(ps);
  153. for (int i = 0; i < (int)ps->size; ++i)
  154. {
  155. if (ps->a[i] == x)//如果找到了
  156. {
  157. return i;//则返回要找的值的下标
  158. }
  159. }
  160. return -1;//否则返回-1
  161. }
  162. //顺序表修改pos位置的值
  163. void SLModify(SL* ps, size_t pos, SLDataType x)
  164. {
  165. assert(ps);
  166. assert(pos >= 0 && pos < ps->size);//既防止了size等于0,又规范了pos的位置
  167. ps->a[pos] = x;
  168. }

在 Test.c 下

  1. #include"SeqList.h"//别忘了
  2. //用于接口函数功能的测试
  3. void TestSeqList1()
  4. {
  5. SL s;
  6. SLInit(&s);
  7. SLPushBack(&s, 1);
  8. SLPushBack(&s, 2);
  9. SLPushBack(&s, 3);
  10. SLPushBack(&s, 4);
  11. SLPushBack(&s, 5);
  12. SLPushBack(&s, 6);
  13. SLPrint(&s);
  14. SLPopBack(&s);
  15. SLPopBack(&s);
  16. SLPrint(&s);
  17. SLDestroy(&s);
  18. }
  19. void TestSeqList2()
  20. {
  21. SL s;
  22. SLInit(&s);
  23. SLPushFront(&s, 1);
  24. SLPushFront(&s, 2);
  25. SLPushFront(&s, 3);
  26. SLPushFront(&s, 4);
  27. SLPushFront(&s, 5);
  28. SLPrint(&s);
  29. SLPopFront(&s);
  30. SLPrint(&s);
  31. SLPopFront(&s);
  32. SLPrint(&s);
  33. SLPopFront(&s);
  34. SLPrint(&s);
  35. }
  36. void TestSeqList3()
  37. {
  38. SL s;
  39. SLInit(&s);
  40. SLPushFront(&s, 0);
  41. SLPushFront(&s, 2);
  42. SLInsert(&s,0,5);
  43. SLPrint(&s);
  44. }
  45. void TestSeqList4()
  46. {
  47. SL s;
  48. SLInit(&s);
  49. SLPushFront(&s, 1);
  50. SLPushFront(&s, 2);
  51. SLPushFront(&s, 3);
  52. SLPushFront(&s, 4);
  53. SLPushFront(&s, 5);
  54. SLPushFront(&s, 6);
  55. SLPushFront(&s, 7);
  56. SLPushFront(&s, 8);
  57. SLPushFront(&s, 9);
  58. SLPrint(&s);
  59. SLInsert(&s, 4, 666);
  60. SLPrint(&s);
  61. SLInsert(&s, 0, 666);
  62. SLPrint(&s);
  63. SLErase(&s, 4);
  64. SLPrint(&s);
  65. SLErase(&s, 4);
  66. SLPrint(&s);
  67. }
  68. void TestSeqList5()
  69. {
  70. SL s;
  71. SLInit(&s);
  72. int result = 0;
  73. SLPushFront(&s, 1);
  74. SLPushFront(&s, 2);
  75. SLPushFront(&s, 3);
  76. SLPushFront(&s, 4);
  77. SLPushFront(&s, 5);
  78. SLPrint(&s);
  79. result=SLFind(&s, 3);
  80. printf("%d\n", result);
  81. }
  82. void TestSeqList6()
  83. {
  84. SL s;
  85. SLInit(&s);
  86. SLPushFront(&s, 1);
  87. SLPushFront(&s, 2);
  88. SLPushFront(&s, 3);
  89. SLPushFront(&s, 4);
  90. SLPushFront(&s, 5);
  91. SLPrint(&s);
  92. SLModify(&s, 2, 1);
  93. SLPrint(&s);
  94. }
  95. int main()
  96. {
  97. //TestSeqList1();
  98. //TestSeqList2();
  99. //TestSeqList3();
  100. //TestSeqList4();
  101. //TestSeqList5();
  102. TestSeqList6();
  103. return 0;
  104. }

欢迎指正

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

闽ICP备14008679号