数据结构_1.0

一、数据结构概述

1.1 概念

在计算机科学中,数据结构是一种数据组织、管理和存储的格式 。它是相互之间存在一种或多种特定关系的数据元素的集合。通常情况下,精心选择的数据结构可以带来更高的运行或者存储效率。数据结构往往同高效的检索算法和索引技术相关。

1.1.1 数据逻辑结构

数据的逻辑结构是指数据元素之间存在的逻辑关系,由数据元素的集合和定义在此集合上的关系组成。数据的逻辑结构与数据的存储无关,独立于计算机,是从具体问题抽象出来的数学模型。

数据的逻辑结构由两个要素构成,分别是:数据元素的集合和关系的集合 。

1.1.2 数据存储结构

数据的逻辑结构在计算机中的存储表示或实现叫做数据的存储结构,也叫物理结构。数据的存储结构依赖于计算机。

一般来说,一种数据结构的逻辑结构根据需要可以表示成多种存储结构,常用的存储结构有顺序存储、链式存储、索引存储哈希存储等。

数据的顺序存储结构的特点是:借助元素在存储器中的相对位置来表示数据元素之间的逻辑关系;非顺序存储的特点是:借助指示元素存储地址的指针表示数据元素之间的逻辑关系。

1.1.3 数据的运算

数据操作是指对数据结构中的数据元素进行运算或处理。数据操作定义在数据的逻辑结构上,每种逻辑结构都需要一组对其数据元素进行处理以实现特定功能的操作,如插入、删除、更新等。数据操作的实现依赖于数据的存储结构。

数据的运算包括:检索、排序、插入、删除、修改等。

二、常见的数据结构

常见的数据结构有:数组(Array)、栈(Stack)、队列(Queue)、链表(Linked List)、树(Tree)、图(Graph)、堆(Heap)、散列表(Hash)。

2.1 数组(Array)

数组是一种线性结构,是可以在内存中连续存储多个元素的结构,在内存中的分配也是连续的,数组中的元素通过数组下标进行访问,数组下标从0开始。

  • 优点:访问数据简单。
  • 缺点:添加和删除数据比较耗时间,因为要移动其他的元素;数组只能存储一种类型的数据;数组的大小固定后就无法扩容了
  • 使用场景:频繁查询,对存储空间要求不大,很少增加和删除的情况。
int[] a = {1,3,4,5,6,8,9,26,30,89};//直接创建并声明容量元素的数组int[] data = new int[100];// 创建一个整型int数组,大小是100个data[0]  = 1;  // 向数组第一个元素赋值1;
data[1]  = 2;  // 向数组第二个元素赋值2;

JDK提供的顺序表有:java.util.ArrayList 其底层实现就是数组

数组(顺序表)时间复杂度分析:

  1. 查询get(i) ,不难看出不论数据元素量N有多大,只需要一次eles[i] 就可以获取到对应的元素,所以时间复杂度为O(1)
  2. 插入insert(int i, T t),每一次插入,都需要把i位置后面的元素移动一次,随着元素数量N的增大,移动的元素也越多,时间复杂度为O(n)
  3. 删除元素remove(int i),每一次删除,都需要把i位置后面的元素移动一次,随着数据量N的增大,移动的元素也越多,时间复杂度为O(n)
  4. 数组长度是固定的,所以在操作的过程中涉及到了容器扩容操作。这样会导致顺序表在使用过程中的时间复杂度不是线性的,在某些扩容的结点处,耗时会突增,尤其是元素越多,这个问题越明显

2.2 链表(Linked List)

链表是一种数据元素按照链式存储结构进行存储的数据结构,这种存储结构具有在物理上非连续、非顺序的特点。链表由一系列数据结点构成,每个数据结点包括数据域和指针域两部分。其中,指针域保存了数据结构中下一个元素存放的地址。

链表结构中数据元素的逻辑顺序通过链表中的指针链接次序实现 。

根据指针的指向,链表能形成不同的结构,例如单链表,双向链表,循环链表等。

链表时间复杂度分析:

  1. get(int i):每一次查询,都需要从链表的头部开始,依次向后查找,随着数据元素N的增多,比较的元素越多,时间复杂度为O(n)
  2. insert(int i, T t):每一次插入,需要先找到i位置的前一个元素,然后完成插入操作,随着数据元素N的增多,查找的元素越多,时间复杂度为O(n)
  3. remove(int i):每一次移除,需要先找到i位置的前一个元素,然后完成插入操作,随着数据元素N的增多,查找的元素越多,时间复杂度为O(n)

ArrayList vs LinkedList

ArrayList

  1. 基于数组,需要连续内存
  2. 随机访问快(指根据下标访问)
  3. 尾部插入、删除性能可以,其它部分插入、删除都会移动数据,因此性能会低
  4. 可以利用 cpu 缓存,局部性原理

LinkedList

  1. 基于双向链表,无需连续内存
  2. 随机访问慢(要沿着链表遍历)
  3. 头尾插入删除性能高
  4. 占用内存多

链表的优点: 

  • 链表是很常用的一种数据结构,不需要初始化容量,可以任意加减元素; 
  • 添加或者删除元素时只需要改变前后两个元素结点的指针域指向地址即可,所以添加,删除很快;

缺点: 

  • 因为含有大量的指针域,占用空间较大; 
  • 查找元素需要遍历链表来查找,非常耗时。

JDK提供的链表有:java.util.LinkedList

适用场景: 

  • 数据量较小,需要频繁增加,删除操作的场景;
  • 快慢指针:求中间值问题、单向链表是否有环问题、有环链表入口问题;
  • 循环链表:约瑟夫问题

2.3 栈(Stack) 

栈是一种特殊的线性表,又称为栈。是一种基于先进后出(FILO)的数据结构,它只能在表的固定端进行数据结点的插入和删除操作。栈按照先进后出、后进先出的原则来存储数据,也就是说,先插入的数据将被压入栈底,最后插入的数据在栈顶,读出数据时,从栈顶开始逐个读出。

栈在汇编语言程序中,经常用于重要数据的现场保护。栈中没有数据时,称为空栈 。

我们称数据进入到栈的动作为压栈,数据从栈中出去的动作为弹栈。

JDK提供的栈有:java.util.Stack 

应用场景:括号匹配问题;逆波兰表达式求值问题;实现递归功能方面的场景,例如斐波那契数列。

2.4 队列(Queue)

队列是一种基于先进先出(FIFO)的数据结构,是一种只能在一端进行插入,在另一端进行删除操作的特殊线性表,它按照先进先出的原则存储数据,先进入的数据,在读取数据时先被读取出来。

入队列:进行插入操作的一端称为队尾 出队列:进行删除操作的一端称为队头

JDK提供的队列接口有:java.util.Queue

使用场景:因为队列先进先出的特点,在多线程阻塞队列管理中非常适用。

2.5 树(Tree)

树是典型的非线性结构,它是由n(n>0)个有限结点组成的一个具有层次关系的集合。在树结构中,有且仅有一个根结点,该结点没有前驱结点。在树结构中的其他结点都有且仅有一个前驱结点。

树具有以下特点:

  1. 每个结点有零个或多个子结点;
  2. 没有父结点的结点为根结点;
  3. 每一个非根结点只有一个父结点;
  4. 除了根节点外,每个子节点可以分为多个不相交的子树;

在日常的应用中,我们讨论和用的更多的是树的其中一种结构,就是二叉树、平衡树、红黑树、B树、B+树。

应用场景:

  1. JDK1.8中 HashMap的底层源码中用到了数组+链表+红黑树;
  2. 磁盘文件中使用B树做为数据组织,B树大大提高了IO的操作效率;
  3. mysql数据库索引结构采用B+树;
2.5.1 二叉树:满二叉树和完全二叉树

二叉树是一种比较有用的折中方案,它添加,删除元素都很快,并且在查找方面也有很多的算法优化,所以,二叉树既有链表的好处,也有数组的好处,是两者的优化方案,在处理大批量的动态数据方面非常有用。

二叉树有很多扩展的数据结构,包括平衡二叉树、红黑树、B+树等,这些数据结构在二叉树的基础上衍生了很多的功能,在实际应用中广泛用到,例如mysql的数据库索引结构用的就是B+树,还有HashMap的底层源码中用到了红黑树。

二叉树是树的特殊一种,具有如下特点:

  • 每个结点最多有两颗子树,结点的度最大为2。
  • 左子树和右子树是有顺序的,次序不能颠倒。
  • 即使某结点只有一个子树,也要区分左右子树。

顺序结构(数组来存储,heap里面讲)
顺序结构存储就是使用数组来存储,一般使用数组只适合表示完全二叉树,因为不是完全二叉树会有空间的浪费。而现实中使用中只有堆才会使用数组来存储,。二叉树顺序存储在物理上是一个数组,在逻辑上是一颗二叉树。

链式结构
二叉树的链式存储结构是指,用链表来表示一棵二叉树,即用链来指示元素的逻辑关系。 通常的方法是链表中每个结点由三个域组成,数据域和左右指针域,左右指针分别用来给出该结点左孩子和右孩子所在的链结点的存储地址 。链式结构又分为二叉链和三叉链,当前我们学习中一般都是二叉链,后面课程学到高阶数据 结构如红黑树等会用到三叉链。

链式结构接口如下:(包括三种遍历方式:前序遍历、中序遍历、后序遍历,以及层序遍历)

2.6 散列表(Hash)

散列表,也叫哈希表,是根据关键码和值 (key和value) 直接进行访问的数据结构,通过key和value来映射到集合中的一个位置,这样就可以很快找到集合中的对应元素。

记录的存储位置=f(key)

这里的对应关系 f 成为散列函数,又称为哈希 (hash函数),而散列表就是把Key通过一个固定的算法函数既所谓的哈希函数转换成一个整型数字,然后就将该数字对数组长度进行取余,取余结果就当作数组的下标,将value存储在以该数字为下标的数组空间里,这种存储空间可以充分利用数组的查找优势来查找元素,所以查找的速度很快。

在存储数据的过程中,如果发生冲突,可以利用链表在已有数据的后面插入新数据来解决冲突。这种方法被称为“链地址法”。除了链地址法以外,还有几种解决冲突的方法。其中,应用较为广泛的是“开放地址法”。

DK提供的哈希表有:java.util.HashMap

散列表应用场景:

  • 哈希表的应用场景很多,当然也有很多问题要考虑,比如哈希冲突的问题,如果处理的不好会浪费大量的时间,导致应用崩溃。
  • 解决哈希冲突问题:1 可以对数组扩容; 2 优化hash计算方式;

2.7 堆(Heap)

堆是一种特殊的树形数据结构,一般讨论的堆都是二叉堆。堆的特点是根结点的值是所有结点中最小的或者最大的,并且根结点的两个子树也是一个堆结构 。

被用于实现“优先队列”(priority queues)。优先队列是一种数据结构,可以自由添加数据,但取出数据时要从最小值开始按顺序取出。在堆的树形结构中,各个顶点被称为“结点”(node),数据就存储在这些结点中。堆有下列特点

  • 每个节点最多有两个子节点
  • 排列顺序必须从上到下,同一行从左到右
  • 堆中某个节点的值总是不大于或不小于其父节点的值;
  • 存放数据时,一般会把新数据放在最下面一行靠左的位置。如果最下面一行没有多余空间时,就再往下另起一行,并把数据添加到这一行的最左端。

堆的性质:

  • 堆是一个完全二叉树
  • 堆中某个结点的值总是不大于或不小于其父结点的值;
  • 除了树的最后一层结点不需要是满的,其它的每一层从左到右都是满的,如果最后一层结点不是满的,那么要求左满右不满;
  • 它通常用数组来实现;
将根结点最大的堆叫做最大堆或大根堆,根结点最小的堆叫做最小堆或小根堆。常见的堆有二叉堆、
斐波那契堆等。
一棵深度为k的有n个结点的二叉树,对树中的结点按从上至下、从左到右的顺序进行编号,
如果编号为i(1≤i≤n)的结点与满二叉树中编号为i的结点在二叉树中的位置相同,则这棵二叉树
称为完全二叉树。
一棵深度为k且有2^k−1个结点的二叉树称为满二叉树。也就是说除了叶子节点都有2个子节点,且
所有的叶子节点都在同一层。

堆应用场景:因为堆有序的特点,一般用来做数组中的排序,称为堆排序。

2.8 图(Graph)

图是另一种非线性数据结构。图的数据结构包含一个有限的集合作为结点集合,以及一个无序对(对应无向图)或有序对(对应有向图)的集合作为边的集合。如果两个结点之间存在一条边,那么就表示这两个结点具有相邻关系 。

无向图:

有向图:

图的搜索:

  • 深度优先搜索:指的是在搜索时,如果遇到一个结点既有子结点,又有兄弟结点,那么先找子结点,然后找兄弟结点。
  • 广度优先搜索:指的是在搜索时,如果遇到一个结点既有子结点,又有兄弟结点,那么先找兄弟结点,然后找子结点。

图的应用场景:

  • 道路畅通工程
  • 最短路径

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

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

相关文章

【开源合规】开源许可证基础知识与风险场景引入

文章目录 什么是开源许可证(License)?开源许可证有什么用?开源许可证分类开源许可证分类及描述公共代码 (Public Domain)CC0无License宽松型许可证 (Permissive)MITApache 2.0BSD弱互惠型许可证 (Weak Copyleft)LGPLMPLEPL互惠型许可证 (Reciprocal)GPLEUPL强互惠许可证 (Str…

读-改-写操作

1 什么是读-改-写操作 “读-改-写”(Read-Modify-Write,简称RMW)是一种常见的操作模式,它通常用于需要更新数据的场景。 这个模式包含三个基本步骤: 1.读(Read):首先读取当前的数据…

从0开始学习pyspark--pyspark的数据分析方式[第2节]

PySpark是Apache Spark的Python API,能够在分布式计算环境中处理大规模数据。本文将详细介绍PySpark中不同的数据分析方式,包括它们的使用场景、操作解释以及示例代码。 1. RDD(Resilient Distributed Dataset)API 概述 RDD是Sp…

Linux——查找文件-find(详细)

查找文件-find 作用 - 按照文件名、大小、时间、权限、类型、所属者、所属组来搜索文件 格式 find 查找路径 查找条件 具体条件 操作 注意 - find命令默认的操作是print输出 - find是检索文件的,grep是过滤文件中字符串 参数 参数 …

简述Vue中的数据双向绑定原理

Vue中的数据双向绑定原理是Vue框架的核心特性之一,它通过数据劫持结合发布者-订阅者模式来实现。下面将详细阐述Vue中数据双向绑定的原理,并尽量按照清晰的结构进行归纳: 一、数据劫持 使用Object.defineProperty(): Vue在组件…

Mojo模板引擎:释放Web开发的无限潜能

🚀 Mojo模板引擎:释放Web开发的无限潜能 Mojolicious是一个基于Perl的现代化、高性能的Web开发框架,它内置了一个功能强大的模板引擎,专门用于快速构建Web应用程序。Mojo的模板引擎不仅简洁易用,而且具备多种高级特性…

《每天5分钟用Flask搭建一个管理系统》第11章:测试与部署

第11章:测试与部署 11.1 测试的重要性 测试是确保应用质量和可靠性的关键步骤。它帮助开发者发现和修复错误,验证功能按预期工作。 11.2 Flask测试客户端的使用 Flask提供了一个测试客户端,可以在开发过程中模拟请求并测试应用的响应。 …

Unity海面效果——4、法线贴图和高光

Unity引擎制作海面效果 大家好,我是阿赵。 继续做海面效果,上次做完了漫反射颜色和水波动画,这次来做法线和高光效果。 一、 高光的计算 之前介绍过高光的光照模型做法,比较常用的是Blinn-Phong 所以我这里也稍微连线实现了一下 …

在线医疗诊断平台开发教程大纲 (Java 后端,Vue 前端)—实践篇-01

项目分析 第一部分:项目概述及技术选型 项目背景: 在线医疗诊断平台的市场需求与发展趋势本平台的目标用户和核心功能,突出解决的痛点竞品分析,差异化优势技术选型: 后端: 核心框架: Spring Boot (简化开发流程)持久层框架: MyBatis (灵活,易于上手)数据库: MySQL (成熟稳…

API 授权最佳实践

API(应用程序编程接口)就像秘密之门,允许不同的软件程序进行通信。但并不是每个人都应该拥有每扇门的钥匙,就像不是每个软件都应该不受限制地访问每个 API 一样。 这些 API 将从银行的移动应用程序到您最喜欢的社交媒体平台的所有…

英语中Would you和Could you的区分用法

Spark: 在英语中,“Would you”和“Could you”都是用来礼貌地提出请求或询问的表达方式,但它们之间存在一定的差异: 语气与礼貌程度: Would you:通常用于更正式或较为礼貌的场合,它体现了一种比较客气的请…

打开wsl显示请启用虚拟机平台 Windows 功能并确保在 BIOS 中启用虚拟化。

安装了个安卓模拟器,后面wsl打开后显示这个 按照很多博客说的运行一串命令 bcdedit /set hypervisorlaunchtype auto 之后重启电脑 没有效果 运行 dism.exe /online /enable-feature /featurename:VirtualMachinePlatform /all /norestart 之后重启成功打开 wsl 来…

某智能装备公司如何实现多个工程师共用1台图形工作站

在当今快速发展的科技领域,资源共享和高效利用已成为企业提升竞争力的关键,特别是在工程设计和研发领域。如何最大化地利用有限的资源,如工作站,成为了许多公司面临的挑战。某智能装备公司便是在这样的背景下,通过云飞…

【自动驾驶汽车通讯协议】深入理解PCI Express(PCIe)技术

文章目录 0. 前言1. PCIe简介1.1 PCIe外观1.2 PCIe的技术迭代 2. PCIe的通道(lane)配置2.1 通道配置详解2.2 通道配置的影响 3. PCIe的架构3.1 架构层次3.2 核心组件 4. PCIe的特性5. PCIe在自动驾驶中的应用 0. 前言 按照国际惯例,首先声明&…

C# --- 如何在代码中开启进程

C# --- 使用代码开启一个进程 方法一 using (Process myProcess new Process()) {myProcess.StartInfo.UseShellExecute false;// You can start any process, HelloWorld is a do-nothing example.myProcess.StartInfo.FileName "C:\\HelloWorld.exe";myProcess…

unity canvas显示相机照射画面的方法

1. 使用 Image 组件显示处理后的图像 如果你的图像数据已经是一个 Texture2D 或 Sprite,你可以将它直接显示在Canvas上的 Image 组件中: 创建 Sprite: 将你的 Texture2D 数据转换为 Sprite,以便可以在 Image 组件中使用。public Sprite CreateSpriteFromTexture(Texture2D…

【产品运营】Saas的核心六大数据

国内头部软件公司的一季度表现惨不忍睹,为啥美国的还那么赚钱呢?其实核心是,没几个Saas产品经理是看数据的,也不知道看啥数据。 SaaS 行业,天天抛头露面、名头叫的响的 SaaS 产品,真没有几个赚钱的。 那为…

电子看板,帮助工厂实现数字化管理

在数字化浪潮的推动下,制造业正经历着深刻的变革,数字工厂成为了行业发展的新趋势。而生产管理看板作为一种重要的管理工具,在提升数字工厂管理效率方面发挥着关键作用。 生产管理看板通过实时数据的展示,为数字工厂提供了清晰的全…

【算法学习】射线法判断点在多边形内外(C#)以及确定内外两点连线与边界的交点

1.前言: 在GIS开发中,经常会遇到确定一个坐标点是否在一块区域的内部这一问题。 如果这个问题不是一个单纯的数学问题,例如:在判断DEM、二维图像像素点、3D点云点等含有自身特征信息的这些点是否在一个区域范围内部的时候&#x…

基于uniapp(vue3)H5附件上传组件,可限制文件大小

代码&#xff1a; <template><view class"upload-file"><text>最多上传5份附件&#xff0c;需小于50M</text><view class"" click"selectFile">上传</view></view><view class"list" v…