c语言数据结构与算法之顺序表的定义实现详解
作者:程序喵正在路上
顺序表的定义
顺序表 —— 用顺序存储的方式实现线性表顺序存储。
把逻辑上相邻的元素存储在物理位置上也相邻的存储单元中,元素之间的关系由存储单元的邻接关系来体现
线性表是具有相同数据类型的 n (n≥0) 个数据元素的有限序列,数据类型相同说明每个数据元素所占的空间是一样大的
我们假设线性表第一个元素的存放位置(即首地址)是 LOC(L) ,LOC 是 location 的缩写
那么第二个元素的存放位置就是 LOC(L)+数据元素的大小
第三个元素的存放位置就是 LOC(L)+2*数据元素的大小,依此类推…
那么,我们又怎么知道所存放的数据元素的大小呢?
学过 C语言 的小伙伴肯定知道,C语言 中有一个函数 sizeof() 可以帮上我们的忙,我们用 sizeof(ElemType)
这样调用的方式就能得到对应数据元素的大小,其中的 ElemType 就是你的顺序表中存放的数据元素类型,比如 sizeof(int) = 4B
,一个整型一般是 4 个字节;此外,我们还可以传自己定义的类型进去,比如,我们定义一个 Customer 类型
typedef struct { int num; //号数 int people; //人数 } Customer;
相应地,我们使用 sizeof(Customer)
就可以得到这个数据类型的大小为 8B
顺序表的实现 —— 静态分配
#define MaxSize 10 //定义最大长度 typedef struct { ElemType data[MaxSize]; //用静态的 “数组” 存放数据元素 int length; //顺序表的当前长度 } SqList; //顺序表的类型定义(静态分配方式)
ElemType data[MaxSize];
会给各个数据元素分配连续的存储空间,大小为 MaxSize*sizeof(ElemType)
Sq:sequence —— 顺序,序列
#include <stdio.h> #define MaxSize 10 //定义最大长度 typedef int ElemType; typedef struct { ElemType data[MaxSize]; //用静态的 “数组” 存放数据元素 int length; //顺序表的当前长度 } SqList; //顺序表的类型定义 //基础操作 —— 初始化一个顺序表 void InitList(SqList &L) { for(int i = 0; i < MaxSize; i++) { L.data[i] = 0; //将所有数据元素设置为默认初始值 } L.length = 0; } //主函数 int main() { SqList L; //声明一个顺序表 InitList(L); //初始化顺序表 //其他操作 return 0; }
如果在初始化顺序表中不给 data 数组赋值为 0,会怎么样呢?
#include <stdio.h> #define MaxSize 10 //定义最大长度 typedef int ElemType; typedef struct { ElemType data[MaxSize]; //用静态的 “数组” 存放数据元素 int length; //顺序表的当前长度 } SqList; //顺序表的类型定义 //基础操作 —— 初始化一个顺序表 void InitList(SqList &L) { L.length = 0; } //主函数 int main() { SqList L; //声明一个顺序表 InitList(L); //初始化顺序表 //尝试“违规”打印整个数组 for(int i = 0; i < MaxSize; i++) { printf("data[%d]=%d\n", i, L.data[i]); } return 0; }
运行这段代码,你会看到很奇怪的数据,或许和我的运行结果不太一样,这是正常的
为什么会显示这些奇怪的数据呢?
其实啊,程序在给我们这个数组分配内存的时候,我们并不知道这块内存里面之前存储过什么,如果我们不设置数据元素的默认值,就会出现这样的结果
其实,我们这样访问也是违规的,因为初始化顺序表的时候 length 是为 0 的,我们要遍历的条件应该是 i < L.length;
才对,所以数据元素的初始化是可以省略的,不过 length 的初始化这一步骤就不能省略了
如果我们定义的 “数组” 存满了,怎么办呢?
建议直接放弃治疗,顺序表的表长刚开始确定后就无法更改了,因为我们是静态分配空间
有小伙伴就说,那我一开始就声明一个很长的顺序表不就行了,但这样的后果是会浪费我们的内存空间,从这里我们就可以看出来静态分配的局限性了
顺序表的实现 —— 动态分配
#define InitSize 10 //顺序表的初始长度 typedef struct { ElemType *data; //指示动态分配数组的指针 int MaxSize; //顺序表的最大容量 int length; //顺序表的当前长度 } SqList; //顺序表的类型定义
C语言 中提供了 malloc 和 free 这两个函数来让我们动态申请和释放内存空间
malloc 会申请一整片连续的存储空间,然后返回一个指向这一片存储空间开始地址的指针,同时需要我们强制转型为定义的数据元素类型指针
malloc 函数的参数,指明了要分配多大的连续内存空间
L.data = (ElemType *) malloc(sizeof(ElemType) * InitSize);
如果你学习过 C++,那你也可以使用 new 和 delete 这两个函数来实现同样的功能
#include <stdio.h> #include <stdlib.h> //使用 malloc 和 free 函数所需的头文件 #define InitSize 10 //默认最大长度 typedef int ElemType; //方便我们改变类型 typedef struct { ElemType *data; //指示动态分配数组的指针 int MaxSize; //顺序表的最大容量 int length; //顺序表的当前长度 } SqList; //顺序表的类型定义 //初始化顺序表 void InitList(SqList &L); //增加动态数组的长度 void IncreaseSize(SqList &L, int len); //主函数 int main() { SqList L; //声明一个顺序表 InitList(L); //初始化顺序表 IncreaseSize(L, 5); return 0; } //初始化顺序表 void InitList(SqList &L) { //用 malloc 函数申请一片连续的存储空间 L.data = (ElemType *)malloc(sizeof(ElemType)* InitSize); L.length = 0; L.MaxSize = InitSize; } //增加动态数组的长度 void IncreaseSize(SqList &L, int len) { ElemType *p = L.data; //将L数据存储起来 L.data = (ElemType *)malloc(sizeof(ElemType)* (L.MaxSize + len)); for (int i = 0; i < L.length; i++) { L.data[i] = p[i]; //将数据复制到新区域 } L.MaxSize = L.MaxSize + len; //顺序表最大长度增加 len free(p); //释放临时的内存空间 }
注意:realloc 函数也可以实现,但建议初学者使用 malloc 和 free 更能理解背后的过程
顺序表的特点:
- 随机访问,既可以在 O(1) 时间内找到第 i 个元素,代码实现为
data[i - 1]
- 存储密度高,每个节点只存储数据元素
- 拓展容量不方便,即便采用动态分配的方式实现,拓展长度的时间复杂度也比较高
- 插入、删除操作不方便,需要移动大量元素
到此这篇关于c语言数据结构与算法之顺序表的定义实现详解的文章就介绍到这了,更多相关c语言顺序表的定义内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!