数据结构之线性表(顺序表的实现)

news2024/9/8 23:37:49

目录

一、线性表的原理

二、线性表的实现(顺序表)

1.定义顺序表

2.初始化顺序表

3.判断顺序表是否为空

4.获取顺序表的长度

5.向顺序表中插入元素

6.删除指定位置的元素

7.遍历顺序表

8.得到指定位置的元素

三、打印测试功能

1.测试

2.结果输出

3.总代码 

四、顺序表的优缺点

1.顺序表的优点:

2.顺序表的缺点


一、线性表的原理

       线性表,从名字上你就能感觉到,是具有像线一样的性质的表。在广场上,有很多人分散在各处,当中有些是小朋友,可也有很多大人,甚至还有不少宠物,这些小朋友的数据对于整个广场人群来说,不能算是线性表的结构。

        但像刚才提到的那样,一个班级的小朋友,一个跟着一个排着队,有一个打头,有一个收尾,当中的小朋友每一个都知道他前面一个是谁,他后面一个是谁,这样如同有一根线把他们串联起来了。就可以称之为线性表。

线性表(List) : 零个多个数据元素的有限序列。

二、线性表的实现(顺序表)

1.定义顺序表

         主要完成一些常量的定义以及创建线性表的操作。

#define MAX_SIZE 20
#define OK 1
#define ERROR 0
#define TRUE 1
#define FALSE 0
typedef int Status;
typedef int ElemType;

typedef struct
{
	ElemType data[MAX_SIZE];
	int length;
}SqList;
2.初始化顺序表

         初始化主要指对表的数量置为0。

// 初始化顺序表
Status InitList(SqList* L)
{
	if (L == NULL)
	{
		return ERROR;
	}
	L->length = 0;
	return OK;
}
// 重置顺序表
Status ClearList(SqList* L)
{
	if (L == NULL)
	{
		return ERROR;
	}
	L->length = 0;
	return OK;
}
3.判断顺序表是否为空

        对表中的length长度进行判断。

// 判断是否为空
Status isEmpty(SqList* L)
{
	if (L->length > 0)
	{
		return FALSE;
	}
	else if(L->length == 0 || L->length == NULL)
	{
		return TRUE;
	}
}
4.获取顺序表的长度

       getter操作,返回length长度。

// 获取长度
int ListLength(SqList* L)
{
	return L->length;
}
5.向顺序表中插入元素

        主要用到for循环操作,让后一位的值等于前一位的值,其中 index 指的是第几个元素

需要注意:要用的for循环的逆向循环,因为正向循环最后一位元素无法向后进一。

如图所示: 

        代码主要为: 

// 插入元素
Status InsertList(SqList* L, int index, const ElemType e)
{
	if ( (index >= 1) && (L->length < MAX_SIZE))
	{
		if ((index <= L->length))
		{
			for (int k = L->length - 1; k >= index - 1; k-- )
			{
				L->data[k + 1] = L->data[k];
			}
		}
		L->data[index - 1] = e;
		L->length++;
		return OK;
	}
	return ERROR;
}
6.删除指定位置的元素

         原理和插入元素一样,都是用到for循环,对数据进行赋值操作。同样这里需要用的for循环的正向遍历。

        如图所示:

        代码为:

// 删除元素
Status DeleteList(SqList* L, int index, ElemType* e)
{ 
	if (L->length == 0 || index < 1 || index > L->length) return ERROR;
	if (index < L->length)
	{
		*e = L->data[index - 1];
		for (int k = index - 1; k < L->length; k++)
		{
			L->data[k] = L->data[k + 1];
		}
		L->length--;
		return OK;
	}
}
7.遍历顺序表

        很简单,就是简单的数组遍历。

Status visit(ElemType e)
{
	printf("%d->", e);
	return OK;
}
// 遍历
Status ListTraverse(SqList* L)
{
	for (int i = 0; i < L->length; i++)
	{
		visit(L->data[i]);
	}
	printf("\n");
	return OK;
}
8.得到指定位置的元素

        根据索引位置,获取指定元素的值。

Status GetElem(SqList* L, int index, ElemType* e)
{
	if (L->length == 0 || index < 1 || index > L->length) return ERROR;
	*e = L->data[index - 1];
	return OK;
}

三、打印测试功能

1.测试

        输入以下代码,测试功能:

int Createlist()
{
	SqList L;
	ElemType e;
	Status ret;
	ret = InitList(&L);
	for (int i = 0; i < 5; i++)
	{
		ret = InsertList(&L, 1, i);
	}
	ListTraverse(&L);

	ret = isEmpty(&L);
	printf("L是否为空, %d(1: 空; 0: 否)\n",ret);

	DeleteList(&L, 2, &e);
	printf("删除的第二个元素为:%d\n", e);
	ListTraverse(&L);

	GetElem(&L, 3, &e);
	printf("得到第三个的元素为:%d\n", e);


	for (int i = 5; i < 10; i++)
	{
		ret = InsertList(&L, 2, i);
	}
	ListTraverse(&L);

	// 清空
	ClearList(&L);
	return 0;
}
2.结果输出

        如图所示:

3.总代码 

        代码如下:

#include <iostream>


#define MAX_SIZE 20
#define OK 1
#define ERROR 0
#define TRUE 1
#define FALSE 0
typedef int Status;
typedef int ElemType;

typedef struct
{
	ElemType data[MAX_SIZE];
	int length;
}SqList;

// 初始化顺序表
Status InitList(SqList* L)
{
	if (L == NULL)
	{
		return ERROR;
	}
	L->length = 0;
	return OK;
}
// 重置顺序表
Status ClearList(SqList* L)
{
	if (L == NULL)
	{
		return ERROR;
	}
	L->length = 0;
	return OK;
}

// 判断是否为空
Status isEmpty(SqList* L)
{
	if (L->length > 0)
	{
		return FALSE;
	}
	else if(L->length == 0 || L->length == NULL)
	{
		return TRUE;
	}
}
 
// 获取长度
int ListLength(SqList* L)
{
	return L->length;
}

// 插入元素
Status InsertList(SqList* L, int index, const ElemType e)
{
	if ( (index >= 1) && (L->length < MAX_SIZE))
	{
		if ((index <= L->length))
		{
			for (int k = L->length - 1; k >= index - 1; k-- )
			{
				L->data[k + 1] = L->data[k];
			}
		}
		L->data[index - 1] = e;
		L->length++;
		return OK;
	}
	return ERROR;
}

// 删除元素
Status DeleteList(SqList* L, int index, ElemType* e)
{ 
	if (L->length == 0 || index < 1 || index > L->length) return ERROR;
	if (index < L->length)
	{
		*e = L->data[index - 1];
		for (int k = index - 1; k < L->length; k++)
		{
			L->data[k] = L->data[k + 1];
		}
		L->length--;
		return OK;
	}
}

Status visit(ElemType e)
{
	printf("%d->", e);
	return OK;
}
// 遍历
Status ListTraverse(SqList* L)
{
	for (int i = 0; i < L->length; i++)
	{
		visit(L->data[i]);
	}
	printf("\n");
	return OK;
}

Status GetElem(SqList* L, int index, ElemType* e)
{
	if (L->length == 0 || index < 1 || index > L->length) return ERROR;
	*e = L->data[index - 1];
	return OK;
}

int Createlist()
{
	SqList L;
	ElemType e;
	Status ret;
	ret = InitList(&L);
	for (int i = 0; i < 5; i++)
	{
		ret = InsertList(&L, 1, i);
	}
	ListTraverse(&L);

	ret = isEmpty(&L);
	printf("L是否为空, %d(1: 空; 0: 否)\n",ret);

	DeleteList(&L, 2, &e);
	printf("删除的第二个元素为:%d\n", e);
	ListTraverse(&L);

	GetElem(&L, 3, &e);
	printf("得到第三个的元素为:%d\n", e);

	// 继续添加元素
	for (int i = 5; i < 10; i++)
	{
		ret = InsertList(&L, 2, i);
	}
	ListTraverse(&L);

	// 清空
	ClearList(&L);
	return 0;
}

int main()
{
	return Createlist();
}

四、顺序表的优缺点

1.顺序表的优点:

(1)无须为表示表中元素之间的逻辑关系而增加额外的存储空间

        这是个什么意思呢?就是这为什么是一个优点啊?我们实际上顺序表当中这个元素,它们之间的这个逻辑关系呢,是一个单纯的就是个什么线性关系,就是一个挨着一个一个挨着一个。所以你不用去额外的有一个东西去记录它们之间的这样一个关系。

        很快,我们就会学习到链表。那么,在链表当中呢?我们就额外用了一些东西去记录前一个元素和后一个元素之间的一个关系。所以那个地方是要消耗额外的存储空间的啊,这个但是在顺序表当中呢,它是不需要的。这是它的一个优点,这就意味着你记下来的数据全都是有效数据。基本上没有什么这个冗余数据,但是像比如说我们后面学到链表或者是以后我们学到其他数据结构,它多多少少还是一些冗余数据,有一些东西它是用来表达或者是记录元素和元素之间关系的,但顺序表是不需要的 。

(2)可以快速地读取表中任一位置的元素 

         这一点也是其他结构,或者说其他数据结构很难做到的一个事情。不要看这个东西很简单。呃,但是它其实是很难做到,就是你在用这样的一些数据结构的时候,你一定要搞清楚你的主要诉求是什么?如果这个写入或者是新增这样的操作,在你的这个里面占比并不是很大的情况下。那么,你读取将是一个很重要的一个性能指标。

2.顺序表的缺点

(1)插入和删除操作需要移动大量元素

        那它缺点肯定也是一样,那首先第一个就是你插入和删除的话,需要移动大量元素。为什么?因为你元素之间没有逻辑关系的额外存储空间呐。我删掉了一个,比如说这样的一个线性表是吧?我把中间这块删掉了,你就得把后面的往前挪。你不挪的话,那这中间就空了一个元素出来,这个元素不在这个里面,它是个空的空的,那这样子行不行?不行为什么?因为我没有额外的东西记录啊,我这后面一个可以跳一个没有这样的存储空间给它,所以这个东西它是它的优点。到了这里,就是它的缺点。

        你就必须要移动,你在中间删了一个就要移动,你移你要删除了这个头部的,你得把所有的都往前面移动一次。所以它最坏的情况下呢,你要移动n次也就这个移动的这个玩意儿,它是一个O(n)的时间复杂度,随着你的规模是线性增增加的。啊,移动最坏情况下是O(n)那么最差的情况下呢?那你也是要平均水平也是一半吧?对吧,随机出现的话,平均水平也是要一半吧,当然如果是删除尾巴上的是最轻松的,直接把它删掉就完就完事儿了,把长度缩减一就OK了。

(2)当线性表长度变化较大时,难以确定存储空间的容量 

        当这个线性表长度变化较大的时候,很难确定存储空间的容量,因为你看我们的这个线性表顺序表它是一开始我们就给了20最大的空间。然后呢?根据这个长度呢去?实际使用的这个长度会根据呃,这个东西去变化啊,它的这个长度变量length变量会根据实际使用的长度去变化。那么你在这个20范围以内。当然是OK的,没问题,这个效率都很高,不管你是增加还是减少,都还比较高,但是一旦这个变化很大。

        如果比如说你从20变成200的时候,这个时候就不好说了,当然现在的计算机来讲的话,你额外增加的180个元素,它也许是有内存空间的。但是如果你存的每一个结构,每一个这个单元,它的数据本身就很大的情况下,你再增加180个。这个东西你能增加的上去吗?不好说对不对,然后你如果这个使用的长度又突然一下缩减,就是一下子增的很长。一下子呢,又减的很厉害,这种情况有没有有什么样的情况?

        就是比如说像这个数据包的这样一个队列。啊,数据包的一个队列,我们要去做一个数据包啊,我从客户端收到数据包,那高峰时期它就是很长啊。它可能一瞬间能达到1000多。1000多个包,瞬间发过来很正常啊,然后但是有时候出现问题,可能到了晚上三四点钟可能一个,两个包发过来,甚至一个包都没有啊。那这个存储空间弹性就非常变化,非常大,这个东西就比较麻烦,如果你申请多了吧,浪费存储空间,因为这个东西你申请了占着没用它。 

(3)造成存储空间的"碎片" 

        这个就是我们实际上就是遇到过这样的一些情况,我们这个里面是20,但是我们用到用满了20吗?在我们的测试当中,一直没有对不对?我们最多的时候用到了10。剩下的这些东西都是都是空的啊,那么当我在这里面删除一个以后,我要把所有东西都往前面移,都往前面移,那么在这个移动过程中,最后又会空出来一个这个东西,一直在这里。如果你有大量的这种队列是吧?你有一个两个三个这样的队列,每个队列多多少少是吧?就有一点空的。那这些东西是不是没有用的?这些东西算是一个碎片呢。

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

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

相关文章

【Ant Design Vue的更新日志】

🌈个人主页: 程序员不想敲代码啊 🏆CSDN优质创作者,CSDN实力新星,CSDN博客专家 👍点赞⭐评论⭐收藏 🤝希望本文对您有所裨益,如有不足之处,欢迎在评论区提出指正,让我们共同学习、交流进步! 以下是Ant Design Vue的更新日志 版本1.7.0(发布日期:2023年4月) …

python之代码简化式(列表、字典生成式,递归函数,迭代器(iter)和生成器(yield)、匿名函数(lambda)的使用)(12)

文章目录 前言1、列表、字典生成式2、递归函数2.1 python中代码的递归深度&#xff08;扩展&#xff09; 3、拓展&#xff1a;迭代器和生成器3.1 迭代器&#xff08;iter&#xff09;3.2 生成器&#xff08;yield&#xff09; 4、匿名函数&#xff08;lambda&#xff09;4.1 ma…

康师傅JAVA核心内容

链接&#xff1a;康师傅JAVA核心内容 (qq.com)

LeetCode刷题笔记第682题:棒球比赛

LeetCode刷题笔记第682题&#xff1a;棒球比赛 题目&#xff1a; 想法&#xff1a; 遍历输入的列表&#xff0c;按照规则将分数和操作依次进行&#xff0c;存储在新建的列表中&#xff0c;最终输出列表中的元素和&#xff0c;代码如下&#xff1a; class Solution:def calPo…

Ubuntu、centos、openEuler安装docker

目录 1.在 Ubuntu 上安装 Docker 1. 1 更新软件包 1. 2 安装必要的依赖 1.3 添加 Docker 的 GPG 密钥 1.4 添加 Docker 仓库 1.5 更新软件包 1.6 安装 Docker 1.7 启动并启用 Docker 服务 1.8 验证安装 1.9 运行测试容器 1.10 非 root 用户运行 Docker 2.在 CentOS…

前端基于 axios 实现批量任务调度管理器 demo

一、背景介绍 这是一个基于 axios 实现的批量任务调度管理器的 demo。它使用了axios、promise 等多种技术和原理来实现批量处理多个异步请求&#xff0c;并确保所有请求都能正确处理并报告其状态。 假设有一个场景&#xff1a;有一个任务列表&#xff0c;有单个任务的处理功能…

OpenGL学习 1

一些唠叨&#xff1a; 很多时候&#xff0c;都被Live2d吸引&#xff0c;去年想给网页加个live2d看板娘&#xff0c;结果看不懂live2d官方给的SDK&#xff0c;放弃了。今天又想弄个live2d桌宠&#xff0c;都已经在网上找到Python 的 Live2D 拓展库了&#xff0c;并提供了用QT实现…

领航者-跟随者编队算法 定义+特性+原理+公式+Python示例代码(带详细注释)

文章目录 引言定义特性基本原理和公式推导基本原理公式推导运动模型领航者的控制跟随者的控制 示例推导 实现步骤和代码实现实现步骤Python代码实现&#xff08;带详细注释&#xff09;代码运行结果代码和图表说明 应用案例优化和挑战优化挑战 结论 引言 在现代科技的发展中&a…

PointCLIP: Point Cloud Understanding by CLIP

Abstract 近年来&#xff0c;基于对比视觉语言预训练(CLIP)的零镜头和少镜头学习在二维视觉识别中表现出了令人鼓舞的效果&#xff0c;该方法在开放词汇设置下学习图像与相应文本的匹配。然而&#xff0c;通过大规模二维图像-文本对预训练的CLIP是否可以推广到三维识别&#x…

【状语从句】

框架 概念&#xff0c;特点主将从现连接词时间条件地点结果方式让步原因目的比较省略倒装 解读 1【概念&#xff0c;特点】 一个完整的句子&#xff0c;去修饰另一个完整句子中的动词&#xff0c;称为状语从句&#xff1b;特点&#xff1a;从句完整&#xff0c;只用考虑连接词是…

扩展------正向代理和反向代理怎么理解?

今天看博客园&#xff0c;突然看到正向代理和反向代理&#xff0c;发现自己还不会就稍微研究了一下。 正向代理----(看做是服务员) 当我们进饭店吃饭&#xff0c;我们不可能会直接去后厨叫厨师给我们做菜&#xff0c;而是通过服务员去通知&#xff0c;这个就叫做正向代理。 再…

keras在GPU环境下配置,conda虚拟环境并安装TensorFlow,cudatoolkit,cudann和jupyter等

前言&#xff1a;要有版本意识 在我个人的多次配置环境过程中&#xff0c;很多时候失败或者后序出现问题&#xff0c;往往都是版本不匹配的问题。所以在本次安装中&#xff0c;提前重点了解了下版本匹配情况。各位千万不要跳过这部分&#xff0c;因为这不仅是基础知识了解的过…

君子学习,是为了修养自己

98天 保护自己最好的方式&#xff1a; 恢复良知的明和诚&#xff0c;就能照见万物&#xff0c;能常觉、常照&#xff0c;任何东西都无所遁形。&#xff08;相信直觉&#xff09; 君子学习&#xff0c;是为了修养自己。 从不担忧别人会欺骗自己&#xff0c;只是永远不欺骗自己的…

docker笔记7-dockerfile

docker笔记7-dockerfile 一、dockerfile介绍二、dockerfile指令三、构建自己的镜像 一、dockerfile介绍 Dockerfile是用来构建Docker镜像的构建文件&#xff0c;是由一系列命令和参数构成的脚本。 以下是常用的 Dockerfile 关键字的完整列表和说明&#xff1a; 二、docker…

实时捕获数据库变更

1.CDC概述 CDC 的全称是 Change Data Capture &#xff0c;在广义的概念上&#xff0c;只要能捕获数据变更的技术&#xff0c;我们都可以称为 CDC 。我们目前通常描述的CDC 技术主要面向数据库的变更&#xff0c;是一种用于捕获数据库中数据变更的技术&#xff0c;CDC 技术应用…

C语言进阶 10. 字符串

C语言进阶 10. 字符串 文章目录 C语言进阶 10. 字符串10.1. 字符串10.2. 字符串变量10.3. 字符串输入输出10.4. 字符串数组10.5. 单字符输入输出10.6. 字符串函数strlen()10.7. 字符串函数strc()10.8. 字符串函数strcpy()10.9. 字符串搜索函数10.10. PAT10-0. 说反话 (20)10-1.…

RK3568平台(input篇)input数据上报分析

一.input设置事件类型 __set_bit 是一个位操作函数&#xff0c;用于设置一个位图中的特定位&#xff0c;例如可以通过下面的代码将 输入设备设置为支持按键事件&#xff1a; __set_bit(EV_KEY,myinput_dev->evbit) 第一位为设置设置事件类型。 第二位为输入设备的能力 和…

6 网络

6 网络 1、概念2 IP地址3、套接字4、TCP协议4.1 TCP协议的基本特征4.2 建立连接4.4 终止连接4.5 编程模型 5、UDP协议5.1 UDP协议的基本特性5.2 常用函数5.3 UDP通信模型 6、域名解析 1、概念 计算机网络是实现资源共享和信息传递的计算机系统 ISO/OSI网络协议模型 TCP/IP协…

应急响应靶场

靶场搭建 靶场环境搭建&#xff1a;首先确定目标靶机的IP地址&#xff1a; 端口探测&#xff1a;发现只开放了22号端口 尝试利用hydra进行爆破&#xff1a; 成功找到了密码。ssh远程登录之后&#xff0c;添加后门账号: msfvenom生成msf的木马&#xff1a; 利用python快速搭建h…