【数据结构】线性表——顺序表

文章目录


一、线性表

线性表(linear list)是n个具有相同特性的数据元素的有限序列 。 线性表是一种在实际中广泛使用的数据结构,常见的线性表:顺序表、链表、栈、队列、字符串...

线性表逻辑上是线性结构 ,也就说是连续的一条直线(如图一)。但是在物理结构 上并不一定连续 的(如图二)。线性表物理上存储 时,通常以数组和链式结构的形式存储。 (假设在32位机器上)


二、顺序表

2.1概念及结构

顺序表是用一段物理地址连续的存储单元 依次存储数据元素的线性结构,一般情况下采用数组存储。在数组上完成数据的增删查改

顺序表一般可以分为:

  1. 静态顺序表:使用定长数组存储元素 。(如下图)

  2. 动态顺序表:使用动态开辟的数组 存储。

说白了顺序表就是数组 😆没想到把~意不意外

虽说顺序表就是数组,但是也不能说顺序表没用,在高级的储存单元里面(如二叉树)底层就是使用顺序表的。

2.2、顺序表接口实现

静态顺序表只适用于确定知道需要存多少数据的场景。静态顺序表的定长数组导致N定大了,空间开多了浪费,开少了不够用。所以现实中基本都是使用动态顺序表,根据需要动态的分配空间大小,所以下面我们实现动态顺序表。

2.2.1、顺序表的动态存储

函数命名规则借鉴CPP的stl库进行命名。

首先创建一个结构体,用于储存顺序表结构。

c 复制代码
typedef int SLDateType;
typedef struct SeqList
{
	SLDateType* a;
	int size;
	int capacity;
}SeqList;
  • typedef int SLDateType;把顺序表结构的类型重命名为:SLDateType。若将来如果要改变数据顺序表内容的结构类型。可以极为方便的改变。
  • 在结构体中定义了。顺序表的总体大小和当前容量。以便确认是否需要扩容。
  • 定义的SLDateType*用于接收动态开辟的内存。
  • size是顺序表的大小。
  • capacity是顺序表当前的元素数量。

2.2.2、顺序表初始化

c 复制代码
void SeqListInit(SeqList* ps) {
	
	SLDateType* arr = (SLDateType*)malloc(sizeof(SLDateType) * 2);
	if (arr == NULL) {
		perror("malloc in SeqListInit of arr::");
	}
	ps->a = arr;
	ps->size = 2;
	ps->capacity = 0;
}
  • 因为顺序表的结构体是没有进行内存划分的。所以需要把顺序表的结构体进行初始化。
  • 默认开辟两个空间。
  • 在成功开辟后。把size设置为2。capacity设置为0。

2.2.3、检查空间判断进行增容

c 复制代码
void CheckCapacity(SeqList* ps) {
	if (ps->capacity == ps->size) {
		SLDateType* arr = (SLDateType*)realloc(ps->a, sizeof(SLDateType) * ps->size * 2);
		if (arr == NULL) {
			perror("realloc in SeqListPushBack");
		}
		ps->a = arr;
		ps->size *= 2;
	}
}
  • 每次进行插入都需要判断空间是否足够,所以,需要提前完成检查空间函数。
  • 每次扩容扩二倍。

2.2.4、顺序表尾插、尾删

c 复制代码
void SeqListPushBack(SeqList* ps, SLDateType x) {
	assert(ps);
	CheckCapacity(ps);
	//int i = ps->capacity;
	(ps->a)[ps->capacity] = x;
	ps->capacity++;
}
  • 与数组的插入,并无二意。
c 复制代码
void SeqListPopBack(SeqList* ps) {
	assert(ps && ps->capacity);
	ps->capacity--;
}
  • 只要把当前数据。进行减减。无需把顺序表中的内容进行删除 。因为再次尾插数据,就会把之前的数据覆盖。

2.2.5、顺序表头插、头删

c 复制代码
void SeqListPushFront(SeqList* ps, SLDateType x) {
	assert(ps);

	CheckCapacity(ps);


	memmove(((ps->a) + 1), ps->a, sizeof(SLDateType) * ps->capacity);
	ps->a[0] = x;
	ps->capacity++;
}
  • 顺序表的头插需要把全部数据往后移动一位。
  • 移动完成后就插入数据到头部空位。
c 复制代码
void SeqListPopFront(SeqList* ps) {
	assert(ps && ps->capacity);
	ps->capacity--;
	memmove(ps->a, ((ps->a) + 1), sizeof(SLDateType) * ps->capacity);
}
  • 头删 只需要把后面一位的数据全部往前移动一位 。即可覆盖首元素的数据。

2.2.6、顺序表查找

c 复制代码
int SeqListFind(SeqList* ps, SLDateType x) {
	assert(ps && ps->capacity);
	for (int i = 0; i < ps->capacity; i++) {
		if (ps->a[i] == x) {
			return i;
		}
	}
	return -1;
}
  • 与数组查找数据一样,循环遍历即可。

2.2.7、顺序表在pos位置插入x

c 复制代码
void SeqListInsert(SeqList* ps, int pos, SLDateType x) {
	assert(ps && ps->capacity);

	CheckCapacity(ps);

	memmove(ps->a + pos, ps->a + pos - 1, sizeof(SLDateType) * (ps->capacity - pos + 1));
	ps->a[pos - 1] = x;
	ps->capacity++;
}
  • 找到对应位置 后,从当前位置位置到数据结尾的内容全部向后移动一位 。然后再在该位置进行数据的赋值。

2.2.8、顺序表删除pos位置的值

c 复制代码
void SeqListErase(SeqList* ps, int pos) {
	assert(ps && ps->capacity);
	memmove(ps->a + pos - 1, ps->a + pos, sizeof(SLDateType) * (ps->capacity - pos + 1));
	
	ps->capacity--;

}
  • 找到需要删除的pos位置后。把pos后一位的内容全部向前移动一位即可把pos值原先的内容覆盖。做到删除pos位置的值

2.2.9、顺序表销毁

c 复制代码
void SeqListDestroy(SeqList* ps) {
	assert(ps && ps->a);
	free(ps->a);
	ps->a = NULL;
	ps->size = 0;
	ps->capacity = 0;
}
  • 直接把动态开辟的内存释放掉,然后再把ps结构体中全部内容赋为空或零值。

2.2.10、顺序表打印

c 复制代码
void SeqListPrint(SeqList* ps) {
	assert(ps && ps->a);
	for (int i = 0; i < ps->capacity; i++) {
		printf("%d ", ps->a[i]);
	}
	printf("\n");
}
  • 与数组的循环打印并无二样。
  • 把循环结束条件定为capacity,这样做可以把尾删的数据不再打印数据中。

三、顺序表的劣势

  1. 中间/头部的插入删除,时间复杂度为O(N)
  2. 增容需要申请新空间,拷贝数据,释放旧空间。会有不小的消耗。
  3. 增容一般是呈2倍的增长,势必会有一定的空间浪费。例如当前容量为100,满了以后增容到200,我们再继续插入了5个数据,后面没有数据插入了,那么就浪费了95个数据空间。

以上就是本章所有内容。若有勘误请私信不才。万分感激💖💖 如果对大家有帮助的话,就请多多为我点赞收藏吧~~~💖💖

ps:表情包来自网络,侵删🌹

相关推荐
搬砖的小码农_Sky6 小时前
C语言:数组
c语言·数据结构
先鱼鲨生8 小时前
数据结构——栈、队列
数据结构
一念之坤8 小时前
零基础学Python之数据结构 -- 01篇
数据结构·python
IT 青年8 小时前
数据结构 (1)基本概念和术语
数据结构·算法
熬夜学编程的小王8 小时前
【初阶数据结构篇】双向链表的实现(赋源码)
数据结构·c++·链表·双向链表
liujjjiyun9 小时前
小R的随机播放顺序
数据结构·c++·算法
Reese_Cool10 小时前
【数据结构与算法】排序
java·c语言·开发语言·数据结构·c++·算法·排序算法
djk888811 小时前
.net将List<实体1>的数据转到List<实体2>
数据结构·list·.net
搬砖的小码农_Sky11 小时前
C语言:结构体
c语言·数据结构
_OLi_13 小时前
力扣 LeetCode 106. 从中序与后序遍历序列构造二叉树(Day9:二叉树)
数据结构·算法·leetcode