线性表入门

news2024/11/19 19:19:28

封面:线性表入门.png

王有志,一个分享硬核Java技术的互金摸鱼侠
加入Java人的提桶跑路群:共同富裕的Java人

从今天开始就进入到数据结构的部分了,整体分为3个部分:线性表,树和图,从认识每种数据结构到它们的高级应用。今天我们先从最简单的线性表和数组开始。

什么是线性表?

线性表是我们工作中最常用的数据结构之一,同时它也是我们接触到的最简单的数据结构。
根据操作节点的自由度,我们可以将线性表分为两大类:非受限线性表受限线性表

  • 非受限线性表:数组,链表
  • 受限线性表:栈,队列

除此之外,字符串也是一种特殊的线性表。
在频繁的使用过程中,你有没有思考过什么是线性表?我们一起来看下百度百科中线性表的定义:

线性表(linear list),是数据结构的一种,一个线性表是n个具有相同特性的数据元素的有限序列。

线性表的概念还是很容易理解的,接着来看点头疼的:

线性表中的个数n定义为线性表的长度,n=0时称为空表。在非空表中每个数据元素都有一个确定的位置,如用ai表示数据元素,则i称为数据元素ai在线性表中的位序。线性表的相邻元素之间存在着序偶关系。如用(a1,…,ai-1,ai,ai+1,…,an)表示一个顺序表,则表中ai-1领先于ai,ai领先于ai+1,称ai-1是ai的直接前驱元素,ai+1是ai的直接后继元素。当i=1,2,…,n-1时,ai有且仅有一个直接后继,当i=2,3,…,n时,ai有且仅有一个直接前驱。

这些看起来是不是就有些头疼了?我们举个简单的例子,糖葫芦都吃过吧?如果我说糖葫芦就是一个线性表呢?图1:线性糖葫芦.png
我们来看看糖葫芦是不是符合线性表的定义:

  • 相同特性的数据元素:都是山楂;
  • 有限:总共5个山楂;
  • 序列:给山楂编上号就是完整的序列。

很多小伙伴可能忘记了序列的特点,序列存在顺序关系(可以是混乱的顺序,但是要固定)和排成一列(不会有分支,前后一对一的关系)
通过这串糖葫芦,也给出位序,前驱节点和后继节点的解释:

  • 位序:山楂在签子上确定位置的编号,就是通过这个编号可以找到指定的山楂;
  • 前驱节点:以2号山楂为例,排在2号前面的都是前驱节点;
  • 直接前驱节点:还是2号山楂,排在2号山楂,并且紧挨2号山楂的1号山楂就是直接前驱节点;
  • 后继节点:和前驱节点反过来;
  • 直接后继节点:和直接前驱节点反过来。

再通俗点解释,可以用“一根线”穿起来的相同物件(元素),并保持固定顺序的就是线性表。这样理解起来是不是比定义中的数学符号简单多了?

数组

知道了什么是线性表之后,我们来看线性表中最简单的数据结构:数组。
还记得我们在预备知识:概念和存储结构#物理存储结构提到的顺序存储结构吗?数组正是使用了顺序存储结构
另外在预备知识:概念和存储结构#内存地址中我们提到过每块内存都有自己的编号。这种顺序存储结构加上内存编号,使得数组具有了强大的随机存取能力。

数组的优点

数组最大的优点就是随机存取的能力,换句话说就是在数据中查找指定下标的元素速度非常快
因为计算机可以通过一步简单的计算得到存储该元素的内存地址:起始地址+下标X类型大小。这是不是数组下标从零开始的原因之一呢?

数组的缺点

计算机的世界中没有能解决一切问题的“银弹”,随机存取的能力不仅仅给了数组快速查找元素的资本,也使得数组在插入和删除元素后必须要“整理”内存,顺序存储结构。
数组在插入元素后,为了保持随机存取的特性,必须要向后移动元素。
图2:数组插入元素.png
数组在删除元素后,为了保持随机存取的特性,必须要向前移动元素。
图3:数组删除元素.png
当然,也并不是全部的插入删除都要移动元素。最好的情况下,在数组的尾部插入和删除元素,不需要移动任何元素,此时的时间复杂度是 O ( 1 ) O(1) O(1)。如果是最坏的情况,需要在数组的头部插入和删除元素,则要移动整个数组,此时的时间复杂度是 O ( n ) O(n) O(n)
除了数组的插入和删除外,还有一种情况我们不得不考虑,如果我们在插入元素时,紧邻数组的内存已经被分配了怎么办?

数组的扩容

我们先来看一段代码:

// 第一种
int numbers1 = {0, 1, 2};

// 第二种
int numbers2 = new int[3];

// 第三种
int[] numbers3 = {};
numbers3[0] = 0;  
numbers3[1] = 1;
numbers3[2] = 2;

这3种创建数组的代码,哪个会有编译时异常?哪个会有运行时异常?
答案是,都能通过编译,但是第三种在运行时会抛出ArrayIndexOutOfBoundsException异常。
强制要求创建数组时进行初始化或者指定数组大小,是为了能够给数组分配合适的内存。但是这么做就带来另一个问题,创建数组时,大小已经固定,如果想添加更多的元素该怎么办?
相信你一定非常熟悉ArrayList了吧?
ArrayList正是Java中提供的可动态扩容的数组,它的底层是Object[],扩容的方式也非常的“粗暴”,当数组大小不足时,重新申请内存(1.5倍),将原数组元素拷贝到新的数组上,并修改引用。

结语

数组的内容就到此结束了,仅仅从数据结构的角度来看数组,还是非常简单的。
可能很多小伙伴会说,工作中都是使用ArrayList了,数组要退出舞台了。
我的想法是,大部分场景选择ArrayList是没有任何问题的,在追求极致性能,且没有插入删除的场景时,数组或许会是一个不错的选择。

练习

  • 尝试实现一个动态数组
  • 1.两数之和
  • 53.最大子数组和
  • 88.合并两个有序数组

如果本文对你有帮助的话,还请多多点赞支持。如果文章中出现任何错误,还请批评指正。最后欢迎大家关注分享硬核Java技术的金融摸鱼侠王有志,我们下次再见!

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

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

相关文章

如何从 Keras 中的深度学习目录加载大型数据集

一、说明 数据集读取,使用、在磁盘上存储和构建图像数据集有一些约定,以便在训练和评估深度学习模型时能够快速高效地加载。本文介绍Keras 深度学习库中的ImageDataGenerator类等工具自动加载训练、测试和验证数据集。 二、ImageDataGenerator加载数据集…

Bom 和 Dom 区别 ----- 真是DOM 和 虚拟Dom区别

DOM和BOM的区别 我们都指代,javascript由三个部分组成: ECMAScript:描述了JS的语法和基本对象 BOM(浏览器对象):与浏览器交互的方法和对象 DOM(文档对象模型):处理网页内容的方法和接 ps:根据宿主&#x…

数学经典教材有什么?

有本书叫做《自然哲学的数学原理》,是牛顿写的,读完之后你就会感叹牛顿的厉害之处! 原文完整版PDF:https://pan.quark.cn/s/5d5eac2e56af 那玩意真的是人写出来的么… 现代教材把牛顿力学简化成三定律,当然觉得很简单。只有读了原…

并发前置知识一:线程基础

一、通用的线程生命周期:“五态模型” 二、java线程有哪几种状态? New:创建完线程Runable:start(),这里的Runnable包含操作的系统的Running(运行状态)和Ready(上面的可运行状态)Blo…

单片机中的PWM(脉宽调制)的工作原理以及它在电机控制中的应用。

目录 工作原理 在电机控制中的应用 脉宽调制(PWM)是一种在单片机中常用的控制技术,它通过调整信号的脉冲宽度来控制输出信号的平均电平。PWM常用于模拟输出一个可调电平的数字信号,用于控制电机速度、亮度、电压等。 工作原理 …

2024,智能座舱不要再过度“装修”了!

文 | AUTO芯球 作者 | 雷慢 还记得2022年小鹏疲劳驾驶检测系统将小眼睛驾驶员识别为“开车睡觉”吗?驾驶员被扣了“智驾分”,你没听错,车主不光要焦虑驾照扣分的时候,还要焦虑被车子扣分。 雷慢还记得另一个奇葩事情是某问界车主…

S7-200SMART实例之冒泡法排序子程序

需求分析 编写程序实现冒泡法排序的算法。 冒泡法排序是一种简单的排序算法。因其过程如同水中气泡最终会上浮到水面一样,故被形象地称为“冒泡法排序”。 实现原理 根据以上需求分析可以按以下步骤实现算法: 1.比较相邻的元素。如果第一个比第二个…

linux 网络基础配置

将Linux主机接入到网络,需要配置网络相关设置一般包括如下内容: 主机名 iP/netmask (ip地址,网关) 路由:默认网关 网络连接状态 DNS服务器 (主DNS服务器 次DNS服务器 第三个DNS服务器) 一、…

多态、抽象类和接口(深拷贝和浅拷贝)

目录​​​​​​​ 前言: 多态: 多态的定义: 向上转型: 方法重写: 再看toString方法: 动态绑定: 向下转型: 小练习: 抽象类: 什么是抽象类&am…

自旋锁和互斥锁的区别

自旋锁和互斥锁的区别_自旋锁和互斥锁有什么区别?-CSDN博客

Fluids —— MicroSolvers DOP

目录 Gas SubStep —— 重复执行对应的子步 Switch Solver —— 切换解算器 Gas Attribute Swap —— 交换、复制或移动几何体属性 Gas Intermittent Solve —— 固定时间间隔计算子解算器 Gas External Forces —— 计算外部力并更新速度或速度场 Gas Particle Separate…

在Vivado下利用Tcl实现IP的高效管理

在Vivado下利用Tcl实现IP的高效管理https://cloud.tencent.com/developer/article/1736645 在Vivado下,有两种方式管理IP。一种是创建FPGA工程之后,在当前工程中选中IP Catalog,生成所需IP,这时相应的IP会被自动添加到当前工程中&…

FineBI实战项目一(18):每小时上架商品个数分析开发

点击新建组件,创建每小时上架商品个数组件。 选择线图,拖拽cnt(总数)到纵轴,拖拽hourStr到横轴。 修改横轴和纵轴的文字。 调节连线样式。 添加组件到仪表板。

vue知识-05

聊天室案例(django接口) # chat.hetm<<script src"/static/axios.js"></script><script src"/static/vue.js"></script><body> <div id"app"><h1>聊天室</h1><button click"handleS…

【无标题】用好Java 8的日期时间类

在 Java 8 之前&#xff0c;我们处理日期时间需求时&#xff0c;使用 Date、Calender 和 SimpleDateFormat&#xff0c;来声明时间戳、使用日历处理日期和格式化解析日期时间。但是&#xff0c;这些类的 API 的缺点比较明显&#xff0c;比如可读性差、易用性差、使用起来冗余繁…

竞赛保研 基于深度学习的行人重识别(person reid)

文章目录 0 前言1 技术背景2 技术介绍3 重识别技术实现3.1 数据集3.2 Person REID3.2.1 算法原理3.2.2 算法流程图 4 实现效果5 部分代码6 最后 0 前言 &#x1f525; 优质竞赛项目系列&#xff0c;今天要分享的是 基于深度学习的行人重识别 该项目较为新颖&#xff0c;适合…

SpringBoot中使用LocalDateTime踩坑记录

文章目录 前言一、为什么推荐使用java.time包的LocalDateTime而不是java.util的Date&#xff1f;二、使用LocalDateTime和LocalDate时遇到了哪些坑&#xff1f;2.1 Redis序列化报错2.1.1 问题现象2.1.2 问题分析2.1.3 解决方案 2.2 LocalDateTime和LocalDate类型的属性返回给前…

Redis主从复制、哨兵及集群

主从复制 主从复制是高可用Redis的基础&#xff0c;哨兵和集群都是在主从复制基础上实现高可用的。主从复制主要实现了数据的多机备份&#xff0c;以及对于读操作的负载均衡和简单的故障恢复。缺陷&#xff1a;故障恢复无法自动化&#xff1b;写操作无法负载均衡&#xff1b;存…

关于httpClient 使用的注意事项

关于httpClient 使用的注意事项 用例 PoolingHttpClientConnectionManager connectionManager new PoolingHttpClientConnectionManager();// 最大连接数-不设置默认20connectionManager.setMaxTotal(200);// 每个路由最大连接数-不设置默认2connectionManager.setDefaultMax…

nginx本地打开vue打包项目

1&#xff0c;首先下载nginx包&#xff0c;然后修改下载的包中的nginx.conf配置文件 其中location后面接的是要增加的域名字段(perbank8)&#xff0c;配置项 index index.html 代表入口文件是index.html 这个在vue项目中也要在nginx配置文件中也要配置同样的路径 在vue项目里…