文章首发于「陈树义」公众号及个人博客 shuyi.tech

其实这个问题的完整描述是:Java 中的 PriorityQueue 实现,其数据的逻辑结构是线性结构吗?其数据的物理结构又是什么?

估计很多人的答案是:PriorityQueue 是线性结构,因为 PriorityQueue 是优先级队列的实现,队列不就是线性结构的吗?但在PriorityQueue 的实现中,其数据的逻辑结构是树形结构,其物理结构是顺序存储结构。

要弄明白这个问题,我们必须先弄明白什么是数据的逻辑结构,什么是数据的物理结构。

顾名思义,数据的逻辑结构指的是数据是怎么组织起来的,数据的物理结构指的是数据是怎么存储的。 数据的逻辑结构与物理结构,是数据结构两个非常重要的要素。但你知道数据有几种逻辑结构、几种物理结构吗?

数据的逻辑结构

数据的逻辑结构指的是数据是如何组织起来的,反映数据元素之间的逻辑关系,它更加贴近于现实。 例如现实生活中树干与树叶就是树形结构,排队的队伍就是线性关系。

数据的逻辑结构一般有四种,分别是:线性结构、集合结构、树形结构、网络结构。 其中,我们把集合、树形结构、网络结构统称为非线性结构。

线性结构

线性结构指的是数据结构中的元素存在一对一的相互关系。 例如:数组是一种线性结构,其下标与元素一一对应。链表也是一种线性结构,其元素之间是一个接着一个的。生活中有很多类似的例子,例如排队买票的队伍就是一个线性结构。超市里排布整齐的商品,也是一个线性结构。

集合结构

集合结构指的是元素之间除了「同属一个集合」的关系之外,再无其他关系。 例如数学中的整数就是一个集合,所有小数也是一个集合。

树形结构

树形结构指的是元素存在一对多的关系。 例如水果有香蕉、草莓、西瓜等,这种逻辑结构就是树形结构。

网络结构

网络结构指的是元素存在多对多的关系。 网络结构也叫做网状结构,它是多对多的关系。比如城市的交通网络,每栋房子与其他房子都有许多条路。

数据的物理存储结构

数据的物理结构指的是数据是如何存储的,反映数据的存储结构。 数据的存储结构分为四种:顺序存储、链式存储、索引存储、散列存储。 一般我们将这四种物理结构分为顺序存储结构与非顺序存储结构。顺序存储是顺序存储结构,链式存储、索引存储、散列存储均属于非顺序存储结构。

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

注:有些朋友说数据的物理存储结构只有顺序存储、链式存储两种,索引存储和散列存储是不存在的。对此,后续我专门写篇文章来聊聊这个事情。

顺序存储

顺序存储指的是数据在内存当中是按照顺序存储的,逻辑结构上相邻的元素在物理结构上也是相邻的。Java 中的 ArrayList 就是通过顺序存储的方式实现的。

链式存储

链式存储指的是元素之间的逻辑顺序,并不是通过内存顺序来分配的,而是通过一个引用组织起来的。也就是说,逻辑上相邻的元素,在物理存储位置上是不相邻的。Java 中的 LinkedList 就是通过链式存储的方式实现的。

索引存储

索引存储指的是元素之间的逻辑关系,是通过一张索引表来存储的。这张索引表有很多个索引项,每个索引项存储两个信息:关键字、数据存储地址。我们通过关键字可以找到对应的数据存储地址。这就像书籍的目录一样,关键字就是章节名,数据存储地址就是页码。我们通过章节名可以快速地找到对应的页码,从而快速地找到书籍对应内容。

散列存储

散列存储也称之为哈希存储,其与索引存储非常类似,都是通过索引值以及对应的值来实现快速查找。唯一不同的区别是,索引存储会对索引值进行哈希。应该说散列存储是索引存储的一种更加复杂的实现。

辨别思路

看到这里,我们对数据的逻辑结构、物理结构已经有了基本的认识,也知道它们的常见种类。那我们到底如何去判断它们是属于哪种逻辑结构、哪种物理结构呢?

拿 Java 中对于优先级队列的 PriorityQueue 实现为例。通过阅读源码我们得知其底层使用了二叉堆实现,而二叉堆本身其实就是一颗二叉树。即对于 PriorityQueue 来说,其数组最终是通过下图这种逻辑结构组织起来的,因此 PriorityQueue 的逻辑结构是树形结构。

从 PriorityQueue 的源码,我们可以知道 PriorityQueue 的数据最终是通过一个对象数组存储的,而数组的物理结构是顺序存储的。因此对于 PriorityQueue 来说,其物理结构是顺序存储结构。

通过 PriorityQueue 这个例子,我们可以总结出判断数据的逻辑结构、物理结构的思路:判断逻辑结构,要看数据是如何组织起来的。要判断物理结构,则是要看数据最终是如何存储的。

如果对 PriorityQueue 的源码实现感兴趣,可以阅读:集合系列 Queue(九):PriorityQueue - 陈树义的博客

我们再用这个办法来判断一下 TreeMap 这个类。

TreeMap 是 Java 中非常经典的实现,其底层是基于红黑树的实现,即其最终会将所有数据组织成一颗红黑树,因此 TreeMap 的逻辑结构是树形结构。通过阅读 TreeMap 的源码,我们知道 TreeMap 的数据最终是通过 Entry 这个类存储的,因此 TreeMap 的物理结构是链式存储结构。

如果对 TreeMap 的源码实现感兴趣,可以阅读:集合系列 Map(十五):TreeMap - 陈树义的博客

最后我们拿比较复杂的 LinkedBlockingQueue 来分析一下。

很多人会说队列就是一种特殊的数组,而数组是顺序存储的,因此队列就是顺序存储的。如果将这个结论套用在 LinkedBlockingQueue 上,那是否可以得出同样的结论,即 LinkedBlockingQueue 也是顺序存储的呢?

前面我们说过:不要用直觉去判断,而要根据定义去判断。 即判断数据的逻辑结构、物理结构的思路是:判断逻辑结构,要看数据是如何组织起来的。要判断物理结构,则是要看数据最终是如何存储的。

LinkedBlockingQueue 是 Java 中的阻塞队列实现,其最终会将数组组织成一个队列,因此其逻辑结构上属于线性表。通过阅读源码,我们可以知道 LinkedBlockingQueue 的元素是存储在 Node 节点上的,因此 LinkedBlockingQueue 的物理结构属于链式存储。

总结

本文一开始通过 PriorityQueue 的例子,引入了逻辑结构与物理结构这个话题。接着介绍了四种逻辑结构:线性表、集合、树状结构、网络结构。

紧接着介绍了四种物理存储结构,分别是:顺序存储、链式存储、索引存储、哈希存储。

接着通过 PriorityQueue 的例子,得出判断数据的逻辑结构和物理结构的思路:判断逻辑结构,要看数据是如何组织起来的。要判断物理结构,则是要看数据最终是如何存储的。 最后再通过 TreeMap 和 LinkedBlockingQueue 这两个例子,带大家实践判断思路。

看到这里文章就结束了,如果你喜欢本篇文章,欢迎点赞、在看、转发、留言支持我,我们下次见~

参考资料

PriorityQueue 是线性结构吗?90%的人都搞错了!的更多相关文章

  1. Java引用类型原理深度剖析,看完文章,90%的人都收藏了

    本文为synchronized系列第二篇.主要内容为分析偏向锁的实现. 偏向锁的诞生背景和基本原理在上文中已经讲过了. 本文将分为几块内容: 1.偏向锁的入口 2.偏向锁的获取流程 3.偏向锁的撤销流 ...

  2. 90%的人都不知道的Node.js 依赖关系管理(下)

    转载请注明出处:葡萄城官网,葡萄城为开发者提供专业的开发工具.解决方案和服务,赋能开发者. 原文参考:https://dzone.com/articles/node-dependency-manage ...

  3. 90%的人都不知道的Node.js 依赖关系管理(上)

    转载请注明出处:葡萄城官网,葡萄城为开发者提供专业的开发工具.解决方案和服务,赋能开发者. 原文参考:https://dzone.com/articles/nodejs-dependency-mana ...

  4. 关于 junit4 90% 的人都不知道的特性,详解 junitperf 的实现原理

    前言 上一节介绍了 https://github.com/houbb/junitperf 的入门使用. 这一节我们从源码的角度,剖析一下其实现方式. 性能测试该怎么做? Junit Rules jun ...

  5. 通过有序线性结构构造AVL树

    通过有序线性结构构造AVL树 本博客旨在结局利用有序数组和有序链表构造平衡二叉树(下文使用AVL树代指)问题. 直接通过旋转来构造AVL树似乎是一个不错的选择,但是稍加分析就会发现,这样平白无故做了许 ...

  6. D_S 线性结构

    线性结构的定义:若结构是非空有限集,则有且仅有一个开始结点和一个终端结点,并且所有结点都最多只有一个直接前驱和一个直接后继. 线性结构的特点: 只有一个首结点和尾结点 除首尾结点外,其他结点只有一个直 ...

  7. java数据结构--线性结构

    一.数据结构 数据结构由数据和结构两部分组成,就是将数据按照一定的结构组合起来,这样不同的组合方式有不同的效率,可根据需求选择不同的结构应用在相应在场景.数据结构大致 分为两类:线性结构(如数组,链表 ...

  8. c++(线性结构的处理)

    我们知道,在内存中的空间都是连续的.也就是说,0x00000001下面的地址必然是0x00000002.所以,空间上是不会出现地址的突变的.那什么数据结构类型是连续内部空间呢,其实就是数组,当然也可以 ...

  9. 线性结构与树形结构相互转换(ES6实现)

    前言 当树形结构的层级越来越深时,操作某一节点会变得越来越费劲,维护成本不断增加.所以线性结构与树形的相互转换变得异常重要! 首先,我们约定树形结构如下: node = { id: number, / ...

随机推荐

  1. 数理统计10(习题篇):寻找UMVUE

    利用L-S定理,充分完备统计量法是寻找UMVUE的最方便方法,不过实际运用时还需要一些小技巧,比如如何写出充分完备统计量.如何找到无偏估计.如何求条件期望,等等.课本上的例题几乎涵盖了所有这些技巧,我 ...

  2. 快速计算类似斐波那契数列数列的数列的第N项,矩阵快速幂

    这个题有循环节,可以不用这么做,这个可以当一个模板 #include <iostream> #include <cstdio> using namespace std; typ ...

  3. Cortex-M系列内核 启动文件分析

    最近终于闲了下来了准备好好学习下Cortex-M3/M4系列处理器的架构,经过各种资料的折磨也没法对它的整个工作过程能有个完整的认知,最后看到一片博客打算从程序的运行过程开始探究,所以首先就找到了启动 ...

  4. git commit guidelines

    git-commit-guidelines AngularJS Development Setup Running Tests Coding Rules Commit Message Guidelin ...

  5. React Security Best Practices All In One

    React Security Best Practices All In One Default XSS Protection with Data Binding Dangerous URLs Ren ...

  6. Web 实时通信方案 All In One

    Web 实时通信方案 All In One HTTP 轮询, 单向通信,开销大 HTTP 长轮询, 单向通信,开销较小 WebSocket,双向通信,开销小 (TCP 高延迟,保证数据完整性) Ser ...

  7. 200万枚SPC空投来袭,这样的薅羊毛活动你确定不参加吗?

    在过去的2020年,币圈真的是很火爆,很多人在参与数字货币交易或DeFi挖矿中赚到了大钱.但是转眼到了2021年,DeFi进入了下半场,区块链市场也进入了新的阶段,那么区块链的下一个爆点是什么呢?很多 ...

  8. 「NGK每日快讯」2021.1.8日NGK第66期官方快讯!

  9. C++算法代码——鹅卵石游戏

    题目来自:http://218.5.5.242:9018/JudgeOnline/problem.php?id=2334 题目描述 为了消磨时光,奶牛Bessie和她的朋友Elsie喜欢玩一种她们在农 ...

  10. Mybatis-05 注解开发

    Mybatis-05 注解开发 注解开发 注解的核心是反射机制 面向接口编程的根本原因:解耦,可拓展,提高复用,分层开发中.上层不用管具体的实现,大家都遵守共同的标准,使得开发变得容易,规范性好. 1 ...