02-2.2.1 顺序表的定义

定义

顺序表——用顺序存储的方式实现线性表顺序存储。
逻辑上相邻的元素存储在物理位置上也相邻的存储单元中,元素之间的关系由存储单元的邻接关系来体现。
但是在线性表中,元素的存放位置不是元素的序号,而是要加上数据元素的大小,原因是数据元素在线性表中存储要占用空间,所以每一个数据元素之间的间隔就是前一个数据元素的大小,如下图所示:
![[Pasted image 20240529222039.png]]

那么如何知道一个数据元素的大小呢?
Ans:在C语言中,使用sizeof(ElemType)函数
Eg:sizeof(int) = 4B
还有更复杂的结构,如:

typedef struct{
	int num;  //号数
	int people;  //人数
} Customer;

sizeof(Customer) = 8B;

顺序表的实现——静态分配

#define MaxSize 10  //定义最大长度
typedef struct{
	ElemType data[MaxSize];  //用静态的数组存放数据元素
	int length;  //顺序表的当前长度
}SqList;  //顺序表的类型定义(静态分配方式)

当声明了data数组之后,实际上就是在内存中开辟了一整片的连续空间,如图所示:
![[Pasted image 20240529222941.png]]

给各个数据元素分配连续的存储空间
大小为MaxSize * sizeof(ElemType)
其中ElemType可以是int类型,也可以是更为复杂的struct类型

代码示例:

#include <stdio.h>
#define MaxSize 10  //定义最大长度

typedef struct{
	int data[MaxSize];  //用静态的“数组”存放数据元素
	int length;  //顺序表的当前长度
}SqList;  //顺序表的类型定义

//基本操作——初始化一个顺序表
void InitList(SqList &L){
	for(int i=0; i<MaxSize; i++){
		L.data[i]=0;  //将所有元素设置为默认初始值
	}
	L.length=0;  //顺序表初始长度为0
}

int main(){
	SqList L;  //声明一个顺序表
	InitList(L);  //初始化顺序表
	//...省略后续操作的代码
	return 0;
}

代码分析:

  • 数据元素的类型是int,所以数据元素的大小是4B
  • 内存中有脏数据——将Length的值设为0这一步是不可以省略的,因为不确定之前这一片内存中是什么数据

如果不设置元素的初始值,输出出来会是一串“奇怪”的数字
这是因为内存中有遗留的“脏数据”

Q:如果“数组”存满了怎么办?
A:直接放弃治疗,顺序表的表长开始之后就无法修改(存储空间是静态的)
那么以上也就是静态分配的局限性

顺序表的实现——动态分配

#define InitSize 10  //顺序表的初始长度
typedef struct{
	ElemType *data;  //指示动态分配的数组的指针
	int MaxSize;     //顺序表的最大容量
	int length;      //顺序表的最大长度
}SeqList;            //顺序表的类型定义(动态分配方式)

在C语言中,分别提供了

  • malloc函数动态申请空间
  • free函数释放内存空间

在C++中,提供了

  • new函数
  • delete函数

new函数和delete函数都设计到面向对象相关的内容
所以更建议使用malloc函数和free函数来编写


malloc函数:

  • 在内存里申请了一整片连续的内存空间
  • 空间的大小为:
    • L.data = (ElemType *) malloc (sizeof(ElemType) * InitSize);
    • 并且在malloc函数会返回一个指针,我们需要把返回的这个指针强制转换为定义的数据元素类型的指针
    • 如:如果是int类型,那么在ElemType的位置就需要改成int
      代码示例:
#define InitSize 10  //默认的最大长度
typedef struct{
	int *data;  //指示动态分配数组的指针
	int MaxSize;  //顺序表的最大容量
	int length;  //顺序表的当前长度
}SeqList;

void InitList(SeqList &L){
	//用malloc申请一片内存空间
	L.data=(int *)malloc(InitSize*sizeof(int));
	L.length=0;
	L.MaxSize=InitSize;
}

//增加动态数组的长度
void IncreaseSize(SeqList &L, int len){
	int *p=L.data;
	L.data=(int *)malloc((L.MaxSize+len)*sizeof(int));
	for(int i=0; i<L.length; i++){
		L.data[i]=p[i];  //将数据复制到新区域
	}
	L.MaxSize=L.MaxSize+len;  //顺序表最大长度增加len
	free(p);  //释放原来的内存空间
}

int main(){
	SeqList L;  //声明一个顺序表
	InitList(L);  //初始化顺序表
	//...插入几个元素
	IncreaseSize(L, 5);
	return 0;
}

代码分析:

  • 首先,SeqList L;之后在内存中开辟了一片空间
  • 其次,InitList(L);之后申请了一片连续的存储空间
  • 并且malloc返回了一个名为data的指针,并且在malloc开辟出来的空间中指向data[0]的位置
  • int *p=L.data定义了一个名为p的指针,并且把L.data的值赋给了p,也就是说pdata指向的是同一个位置,也就是data[0]的位置
  • 由于新开辟出来的空间里面没有任何的数据,所以需要让data指向新的data[0]的位置
  • 最后调用free(p)释放原来的内存空间
    ![[Pasted image 20240529232231.png]]

顺序表的特点

  1. 随机访问——可以在O(1)时间内找到第i个元素
    • 代码实现:data[i-1];
    • 静态分配、动态分配都一样
  2. 存储密度高——每个节点只存储数据元素
    • 如果采用链式存储
    • 每个节点除了数据元素之外
    • 还要存储指针
  3. 拓展容量不方便(即便采用动态分配的方式实现,拓展长度的时间复杂度也比较高)
  4. 插入、删除操作不方便,需要移动大量元素
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Beast Cheng

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值