【数据结构——顺序表的实现】

news2024/9/28 23:26:50

前言:
在之前我们已经对复杂度进行的相关了解,因此现在我们将直接进入数据结构的顺序表的相关知识的学习。

在这里插入图片描述

目录

  • 1.线性表
  • 2.顺序表
    • 2.1概念及结构
    • 2.2 接口实现
      • 2.2.1.打印顺序表
      • 2.2.2初始化顺序表
      • 2.2.3.容量的检查
      • 2.2.4.销毁顺序表
      • 2.2.5.尾插操作
      • 2.2.6.尾删操作
      • 2.2.7.头插操作
      • 2.2.8.头删操作
      • 2.2.9指定位置处插入数据
      • 2.2.10删除指定位置数据
      • 2.2.11begin查找x的起始位置

1.线性表

定义:

线性表(linear list)是n个具有相同特性的数据元素的有限序列。
线性表是一种在实际中广泛使用的数据结构,常见的线性表:顺序表、链表、栈、队列、字符串…
线性表在逻辑上是线性结构,也就说是连续的一条直线。但是在物理结构上并不一定是连续的,
线性表在物理上存储时,通常以数组和链式结构的形式存储

线性表的顺序存储示意图如下:
在这里插入图片描述

2.顺序表

2.1概念及结构

定义:

顺序表是用一段物理地址连续的存储单元依次存储数据元素的线性结构,顺序表中存放数据的特点和数组这种数据类型完全吻合,所以顺序表的实现使用的是数组。在数组上完成数据的增删查改。

注意事项:

数组实现顺序表的存储结构时,一定要注意预先申请足够大的内存空间,避免因存储空间不足,造成数据溢出,导致不必要的程序错误甚至崩溃

顺序表一般可以分为:

  1. 静态顺序表:使用定长数组存储元素。
#define N  7
typedef int SLDataType;
typedef struct SeqList
{
	SLDataType a[N];
	int size; // 记录存储多少个有效数据
}SL;

在这里插入图片描述

静态的顺序表(相当于一个数组,数组长度固定的,存储有效个数据)

  1. 动态顺序表:使用动态开辟的数组存储。
// 动态顺序表 -- 按需扩空间
typedef int SLDataType;
typedef struct SeqList
{
	SLDataType* a;
	int size;       // 记录存储多少个有效数据
	int capacity;   // 空间容量大小 
}SL;

在这里插入图片描述
注意:

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

2.2 接口实现

通常有以下几种接口(接口其实就是实现功能的函数,数据结构以接口称之)

//打印顺序表
void SLPrint(SL* ps);
//初始哈顺序表
void SLInit(SL* ps);
//销毁顺序表
void SLDestroy(SL* ps);

// 尾插尾删
void SLPushBack(SL* ps, SLDataType x);
void SLPopBack(SL* ps);

// 头插头删
void SLPushFront(SL* ps, SLDataType x);
void SLPopFront(SL* ps);

// 中间插入删除
// 在pos位置插入数据
void SLInsert(SL* ps, int pos, SLDataType x);
// 删除pos位置数据
void SLErase(SL* ps, int pos);

//int SLFind(SL* ps, SLDataType x);

// begin查找x的起始位置
int SLFind(SL* ps, SLDataType x, int begin);

接下来我们便开始一一实现相应的功能:

2.2.1.打印顺序表

void SLPrint(SL* ps)
{
	assert(ps);

	for (int i = 0; i < ps->size; ++i)
	{
		printf("%d ", ps->a[i]);
	}
	printf("\n");
}

2.2.2初始化顺序表

void SLInit(SL* ps)
{
	assert(ps);

	ps->a = NULL;
	ps->size = 0;
	ps->capacity = 0;
}

assert函数断言传过来的指针是否为空,若为空就直接结束程序 。

2.2.3.容量的检查

void SLCheckCapacity(SL* ps)
{
	assert(ps);
	if (ps->size == ps->capacity)
	{
		int newCapacity = ps->capacity == 0 ? 4 : ps->capacity * 2;
		SLDataType* tmp = (SLDataType*)realloc(ps->a, newCapacity * sizeof(SLDataType));
		if (tmp == NULL)
		{
			perror("realloc fail");
			exit(-1);
		}

		ps->a = tmp;
		ps->capacity = newCapacity;
	}
}

我们在思考如何在顺序表的尾部插入数据时我们会想到一个问题,如果顺序表满了该怎么办呢?我们可以进行扩容,但是扩大多少呢?扩大的容量过大会导致空间的浪费,扩大的太小会导致频繁申请内存,拖慢程序运行速度

这里采用的是检查容量的方式来实现顺序表的动态存储,(size)是已经存入的数据个数,(capacity)是可以存储数据的个数,当存入和容量相等即空间满了的时候,这里采用realloc函数对顺序表进行扩容。因为realloc函数实在堆区申请空间的所以一次扩容不宜过多这里是一次扩容到原来的两倍。

2.2.4.销毁顺序表

void SLDestroy(SL* ps)
{
	assert(ps);
	if (ps->a)
	{
		free(ps->a);
		ps->a = NULL;
		ps->size = ps->capacity = 0;
	}
}

2.2.5.尾插操作

思想:在开始进行尾插操作时我们需要先对顺序表进行空间检查的操作来判断是否可以直接进行插入操作。

void SLPushBack(SL* ps, SLDataType x)
{
	assert(ps);

	SLCheckCapacity(ps);
	ps->a[ps->size] = x;
	ps->size++;
}

2.2.6.尾删操作

思想:尾删操作我们可以直接进行size–操作,size是我们存入数据的大小,

void SLPopBack(SL* ps)
{
	//assert(ps);

	// 温柔的检查
	///*if (ps->size == 0)
	//{
	//return;
	//}*/

	// 暴力的检查
	assert(ps->size > 0);

	ps->a[ps->size - 1] = 0;
	ps->size--;
}

2.2.7.头插操作

思想:首先我们还是先对容量进行检查,看线性表的容量是否充足。具体的思想就是每次插入就将第一个数据位置空出来,将每个元素依次向后移动一个位置,我们采用从后向前移动的方法,因为从前往后覆盖的话会导致我们后一个数据被覆盖。

void SLPushFront(SL* ps, SLDataType x)
{
	assert(ps);
	SLCheckCapacity(ps);

	// 挪动数据
	int end = ps->size - 1;
	while (end >= 0)
	{
		ps->a[end + 1] = ps->a[end];
		end--;
	}
	ps->a[0] = x;
	ps->size++;
}

注意:
我们可以看出头插操作我们的时间复杂度为O(n),而尾插操作的时间复杂度为O(1)。因此我们看出两种方法的优劣。

2.2.8.头删操作

思想:还是先检查我们线性表的容量大小,因为删除一个数据我们就需要进行相应的覆盖的操作,具体思路还是将线性表的第二个元素开始后继整体向前移动一个元素,这里是从前向后进行操作,如果从后向前依次挪动,则会造成顺序表中数据被覆盖导致内容未被修改。

void SLPopFront(SL* ps)
{
	assert(ps);
	assert(ps->size > 0);

	int begin = 1;
	while (begin < ps->size)
	{
		ps->a[begin - 1] = ps->a[begin];
		begin++;
	}

	ps->size--;
}

2.2.9指定位置处插入数据

思想:对指定的位置进行插入操作,如果我们进行插入的位置不符合我们的规范,检查顺序表的空间是否充足才能用来进行插入数据,在指定位置进行插入操作,将我们要插入位置向后进行移动,腾出相应的空间位置在进行插入操作,具体代码如下:

void SLInsert(SL* ps, int pos, SLDataType x)
{
	assert(ps);
	assert(pos >= 0);
	assert(pos <= ps->size);

	SLCheckCapacity(ps);
	int end = ps->size - 1;
	while (end >= pos)
	{
		ps->a[end + 1] = ps->a[end];
		end--;
	}

	ps->a[pos] = x;
	ps->size++;
}

2.2.10删除指定位置数据

思想:我们进行指定位置删除操作,具体思想就是将指定位置之后的所有元素向前挪移一个元素,将我们要删除元素的位置覆盖掉,采用从后向前覆盖的方式,值得注意的是越界的问题。

void SLErase(SL* ps, int pos)
{
	assert(ps);
	assert(pos >= 0);
	assert(pos < ps->size);
	//assert(ps->size > 0);

	// 挪动数据覆盖
	int begin = pos + 1;
	while (begin < ps->size)
	{
		ps->a[begin - 1] = ps->a[begin];
		begin++;
	}

	ps->size--;
}

2.2.11begin查找x的起始位置

思想:begin为我们查找的位置,查找到begin位置所对应的下标,即找到我们的所需,如果找不到则返回-1

int SLFind(SL* ps, SLDataType x, int begin)
{
	assert(ps);

	for (int i = begin; i < ps->size; ++i)
	{
		if (ps->a[i] == x)
		{
			return i;
		}
	}

	return -1;
}

总结:以上就是对于线性表的实现操作,大家认真整理,下期我们用相应的题目进行相应的练习加深认识,最后祝大家新年快乐!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/174822.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Ubuntu下的LGT8F328P MiniEVB Arduino开发和烧录环境

基于 LGT8F328P LQFP32 的 Arduino MiniEVB, 这个板型资料较少, 记录一下开发环境和烧录过程以及当中遇到的问题. 关于 LGT8F328P 芯片参数 8位RISC内核32K字节 Flash, 2K字节 SRAM最大支持32MHz工作频率 集成32MHz RC振荡器集成32KHz RC振荡器 SWD片上调试器工作电压: 1.8V…

C语言文件操作(3)

TIPS 1. 文件是不是二进制文件&#xff0c;不是后缀说了算&#xff0c;而是内容说了算 2. 文件的随机读写 文件的随机读写也就是说我指哪打哪 fseek() 人为调整指针指向的位置 1. 根据文件指针FILE*的当前位置和你给出的偏移量来让它这个文件指针呢定位到你想要的位置上…

Flutter 这一年:2022 亮点时刻

回看 2022&#xff0c;展望 Flutter Forward 2022 年&#xff0c;我们非常兴奋的看到 Flutter 社区持续发展壮大&#xff0c;也因此让更多人体验到了令人难以置信的体验。每天有超过 1000 款使用 Flutter 的新移动应用发布到 App Store 和 Google Play&#xff0c;Web 平台和桌…

实战打靶集锦-002-SolidState

**写在前面&#xff1a;**谨以此文纪念不完美的一次打靶经历。 目录1. 锁定主机与端口2. 服务枚举3. 服务探查3.1 Apache探查3.1.1 浏览器手工探查3.1.2 目录枚举3.2 JAMES探查3.2.1 搜索公共EXP3.2.2 EXP利用3.2.2.1 构建payload3.2.2.2 netcat构建反弹shell3.2.3 探查JAMES控…

三十一、Kubernetes中Service详解、实例第一篇

1、概述 在kubernetes中&#xff0c;pod是应用程序的载体&#xff0c;我们可以通过pod的ip来访问应用程序&#xff0c;但是pod的ip地址不是固定的&#xff0c;这也就意味着不方便直接采用pod的ip对服务进行访问。 为了解决这个问题&#xff0c;kubernetes提供了Service资源&…

NX二开ufun函数UF_MODL_ask_curve_points(获取曲线信息)

根据曲线tag&#xff0c;返回曲线相关信息&#xff1a;弦宽容、弧度、最大步长、点数组的点。 实例返回结果截图如下&#xff1a; 实例创建曲线截图如下&#xff1a; 1、函数结构 int UF_MODL_ask_curve_points &#xff08;tag_t curve_id&#xff0c; double ctol&#xf…

【SpringCloud19】SpringCloud Alibaba Sentinel实现熔断与限流

1.概述 官网 中文文档 1.1 是什么 一句话解释&#xff0c;之前我们讲解过的Hystrix 1.2 怎么下 下载网址 1.3 作用 1.4 如何使用 官网学习 服务使用中的各种问题&#xff1a; 服务雪崩服务降级服务熔断服务限流 2.安装Sentinel控制台 2.1 组成部分 核心库&#x…

Golang之实战篇(1)

"千篇一律&#xff0c;高手寂寞。几十不惑&#xff0c;全都白扯"上篇介绍了golang这门新的语言的一些语法。那么我们能用golang简单地写些什么代码出来呢&#xff1f;一、猜数字这个游戏的逻辑很简单。系统随机给你生成一个数&#xff0c;然后读取你猜的数字&#xf…

老杨说运维 | AIOps如何助力实现全面可观测性(上)

前言&#xff1a; 嗨&#xff0c;今天是大年三十&#xff0c;大家是不是已经在家坐享团圆之乐了&#xff1f;还是说在奔向团圆的路上呢&#xff1f;不论如何&#xff0c;小编先祝大家新年如意安康&#xff0c;平安顺遂~ 熟悉我们的朋友肯定都知道&#xff0c;关于《老杨说运维…

30.字符串处理函数

文章目录1.测字符串长度函数2.字符串拷贝函数1.strcpy函数2.strncpy函数3.字符串追加函数1.strcat函数2.strncat函数4.字符串比较函数1.strcmp函数2.strncmp函数5.字符查找函数1.strchr函数2.strrchr函数6.字符串匹配函数7.空间设定函数8.字符串转换数值9.字符串切割函数strtok…

【Java开发】Spring Cloud 04 :服务治理Nacos

本章节正式进入 Spring Cloud 环节了&#xff0c;首先介绍微服务架构中一个最重要的原理概念&#xff1a;服务治理&#xff0c;在概念讲解之后&#xff0c;讲解介绍 Nacos 服务注册中心的体系结构。1 服务治理1.1 服务治理介绍首先通过一个例子告诉你服务治理解决了什么问题。比…

GD32F4——外部中断

一、NVIC中断系统 Cortex-M4集成了嵌套式矢量型中断控制器&#xff08;Nested Vectored Interrupt Controller&#xff0c;NVIC&#xff09;来实现高效的异常和中断处理。 中断系统包含外部中断、定时器中断、DMA中断和串口中断等。 二、EXTI外部中断 EXTI&#xff08;中断…

go的基本语法介绍之变量的声明与初始化

1.常见基本数据类型 uint8&#xff1a;无符号8位整形&#xff0c;取值范围&#xff1a;0-255 uint16&#xff1a;无符号16位整形&#xff0c;取值范围&#xff1a;0-65535 uint32&#xff1a;无符号32位整形&#xff0c;取值范围&#xff1a;0-4294967295 uint64&#xff1…

opencv arm交叉编译与仿真验证详细流程

【关键内容】 1.将opencv编译为能在arm上运行的库 2.在没有板子的情况下&#xff0c;仿真验证opencv库 1.将opencv编译为能在arm上运行的库 1.在下方链接中选择某个版本 Releases - OpenCVhttps://opencv.org/releases/点击“Sources”即可开始下载&#xff0c;得到opencv-…

「数据结构、逻辑结构、物理结构」基本概念简析

前言 前言&#xff1a;简析数据结构、逻辑结构、物理结构。 文章目录前言一、数据结构1. 简介2. 数据3. 结构4. 分析5. 分类1&#xff09;线性结构&#xff08;线性表&#xff09;2&#xff09;树结构3&#xff09;图结构二、逻辑结构与物理结构1. 为什么要有逻辑结构和物理结构…

【leetcode合集】如何知道自己是否掌握了数组与链表?试试这几道题目吧!

目录 1.数组题目合集 1.1 leetcode.27 移除元素 1.2 leetcode.26 删除有序数组中的重复项 1.3 leetcode.88 合并两个有数数组 2.链表题目合集 2.1 leetcode.203 移除链表元素 2.2 leetcode.206 反转链表 2.3 leetcode.876 链表的中间结点 2.4 牛客 链表中倒数第k个结点…

零基础学JavaWeb开发(十七)之 mybatis(2)

5、MyBatis - 映射文件标签 5.1、映射文件的顶级元素 select&#xff1a;映射查询语句 insert&#xff1a;映射插入语句 update&#xff1a;映射更新语句 delete&#xff1a;映射删除语句 sql&#xff1a;可以重用的 sql 代码块 resultMap&#xff1a;最复杂&#xff0c…

章鱼网络 2022 虎年全回顾

全长5606字&#xff0c;预计阅读20分钟2022年对章鱼网络而言颇为特别。这是章鱼网络建设应用链多链生态历程的第一年&#xff0c;整个 Web3 行业都经历了极其糟糕的市场环境&#xff0c;但是我们在「生态建设」、「基础设施优化」、「社区治理」和「市场拓展」等都有长足进展&a…

31.Isaac教程--规划器代价

规划器代价 ISAAC教程合集地址: https://blog.csdn.net/kunhe0512/category_12163211.html 文章目录规划器代价组件入门通过应用程序图自定义成本导航本地规划器基于线性二次调节器 (LQR) 规划器。 它通过生成最小化成本函数的轨迹来工作。 不幸的是&#xff0c;没有适用于所有…

Allegro如何输出第三方网表操作指导

Allegro如何输出第三方网表操作指导 在做PCB设计的时候,会需要输第三方网表,Allegro支持快速输出第三方网表,如下图 具体操作如下 选择File选择Export