数据结构基础入门

article/2025/10/13 15:05:43

简单地说,数据结构是以某种特定的布局方式存储数据的容器。这种“布局方式”决定了数据结构对于某些操作是高效的,而对于其他操作则是低效的。首先我们需要理解各种数据结构,才能在处理实际问题时选取最合适的数据结构。

首先列出一些最常见的数据结构,我们将逐一说明:

  • 数组
  • 队列
  • 链表
  • 字典树(这是一种高效的树形结构,但值得单独说明)
  • 散列表(哈希表)

主要基于jdk8, 可能会有些特性与jdk7之前不相同, 例如LinkedList LinkedHashMap中的双向列表不再是回环的,HashMap中的单链表是尾插, 而不是头插入等等。
在这里插入图片描述

【1】数组

数组是最简单、也是使用最广泛的数据结构。栈、队列等其他数据结构均由数组演变而来。下图是一个包含元素(1,2,3和4)的简单数组,数组长度为4。
在这里插入图片描述
每个数据元素都关联一个正数值,我们称之为索引,它表明数组中每个元素所在的位置。大部分语言将初始索引定义为零 index=0。

以下是数组的两种类型:

  • 一维数组(如上所示)
  • 多维数组(数组的数组)

① 数组的基本操作

  • Insert——在指定索引位置插入一个元素
  • Get——返回指定索引位置的元素
  • Delete——删除指定索引位置的元素
  • Size——得到数组所有元素的数量

② 面试中关于数组的常见问题:

  • 寻找数组中第二小的元素
  • 找到数组中第一个不重复出现的整数
  • 合并两个有序数组
  • 重新排列数组中的正值和负值

【2】栈

著名的撤销操作几乎遍布任意一个应用。但你有没有思考过它是如何工作的呢?这个问题的解决思路是按照将最后的状态排列在先的顺序,在内存中存储历史工作状态(当然,它会受限于一定的数量)。有了栈,这就变得非常方便了。

经典的数据结构, 底层也是数组, 继承自Vector, 先进后出FILO, 默认new Stack()容量为10, 超出自动扩容。

可以把栈想象成一列垂直堆放的书。为了拿到中间的书,你需要移除放置在这上面的所有书。这就是LIFO(后进先出)的工作原理。

下图是包含三个数据元素(1,2和3)的栈,其中顶部的3将被最先移除:
在这里插入图片描述
① 栈的基本操作

  • Push——在顶部插入一个元素-入栈/压栈
    在这里插入图片描述
  • Pop——返回并移除栈顶元素-出栈
    在这里插入图片描述
  • isEmpty——如果栈为空,则返回true
  • Top——返回顶部元素,但并不移除它

② 面试中关于栈的常见问题

  • 使用栈计算后缀表达式
  • 对栈的元素进行排序
  • 判断表达式是否括号平衡

③ 后缀表达式

Stack的一个典型应用就是计算表达式如 9 + (3 - 1) * 3 + 10 / 2, 计算机将中缀表达式转为后缀表达式, 再对后缀表达式进行计算.

中缀转后缀

  • 数字直接输出
  • 栈为空时,遇到运算符,直接入栈
  • 遇到左括号, 将其入栈
  • 遇到右括号, 执行出栈操作,并将出栈的元素输出,直到弹出栈的是左括号,左括号不输出。
  • 遇到运算符(加减乘除):弹出所有优先级大于或者等于该运算符的栈顶元素,然后将该运算符入栈
  • 最终将栈中的元素依次出栈,输出。
    在这里插入图片描述

计算后缀表达

  • 遇到数字时,将数字压入堆栈
  • 遇到运算符时,弹出栈顶的两个数,用运算符对它们做相应的计算, 并将结果入栈
  • 重复上述过程直到表达式最右端
  • 运算得出的值即为表达式的结果

在这里插入图片描述


【3】队列

与栈相似,队列是另一种顺序存储元素的线性数据结构。栈与队列的最大差别在于栈是LIFO(后进先出),而队列是FIFO,即先进先出。Stack的删除与添加都在队尾进行, 而Queue删除在队头, 添加在队尾。

一个完美的队列现实例子:售票亭排队队伍。如果有新人加入,他需要到队尾去排队,而非队首——排在前面的人会先拿到票,然后离开队伍。

下图是包含四个元素(1,2,3和4)的队列,其中在顶部的1将被最先移除:
在这里插入图片描述
ArrayBlockingQueue,生产消费者中常用的阻塞有界队列, FIFO。

put(E)
在这里插入图片描述
put(E) 队列满了

 final ReentrantLock lock = this.lock;lock.lockInterruptibly();try {while (count == items.length)notFull.await();//阻塞等待enqueue(e);} finally {lock.unlock();}

在这里插入图片描述
take()

当元素被取出后, 并没有对数组后面的元素位移, 而是更新takeIndex来指向下一个元素.

takeIndex是一个环形的增长, 当移动到队列尾部时, 会指向0, 再次循环。

private E dequeue() {// assert lock.getHoldCount() == 1;// assert items[takeIndex] != null;final Object[] items = this.items;@SuppressWarnings("unchecked")E x = (E) items[takeIndex];items[takeIndex] = null;if (++takeIndex == items.length)takeIndex = 0;count--;if (itrs != null)itrs.elementDequeued();notFull.signal();return x;}

在这里插入图片描述

队列的基本操作

  • Enqueue() —— 在队列尾部插入元素
  • Dequeue() ——移除队列头部的元素
  • isEmpty()——如果队列为空,则返回true
  • Top() ——返回队列的第一个元素

面试中关于队列的常见问题

  • 使用队列表示栈
  • 对队列的前k个元素倒序
  • 使用队列生成从1到n的二进制数

【4】链表

链表是另一个重要的线性数据结构,乍一看可能有点像数组,但在内存分配、内部结构以及数据插入和删除的基本操作方面均有所不同。

链表就像一个节点链,其中每个节点包含着数据和指向后续节点的指针。 链表还包含一个头指针,它指向链表的第一个元素,但当列表为空时,它指向null或无具体内容。

链表一般用于实现文件系统、哈希表和邻接表。这是链表内部结构的展示:
在这里插入图片描述
链表包括以下类型:

  • 单链表(单向)
  • 双向链表(双向)

链表的基本操作:

  • InsertAtEnd - 在链表的末尾插入指定元素
  • InsertAtHead - 在链接列表的开头/头部插入指定元素
  • Delete  - 从链接列表中删除指定元素
  • DeleteAtHead - 删除链接列表的第一个元素
  • Search  - 从链表中返回指定元素
  • isEmpty - 如果链表为空,则返回true

面试中关于链表的常见问题

  • 反转链表
  • 检测链表中的循环
  • 返回链表倒数第N个节点
  • 删除链表中的重复项

LinkedList

经典的双向链表结构, 适用于乱序插入, 删除。指定序列操作则性能不如ArrayList, 这也是其数据结构决定的。

add(E) / addLast(E)
在这里插入图片描述
add(index, E)

这边有个小的优化, 他会先判断index是靠近队头还是队尾, 来确定从哪个方向遍历链入。

if (index < (size >> 1)) {
//如果小于size/2,则表示从队头插入Node<E> x = first;for (int i = 0; i < index; i++)x = x.next;return x;} else {Node<E> x = last;for (int i = size - 1; i > index; i--)x = x.prev;return x;}

靠队头
在这里插入图片描述
靠队尾
在这里插入图片描述
get(index)

也是会先判断index, 不过性能依然不好, 这也是为什么不推荐用for(int i = 0; i < lengh; i++)的方式遍历linkedlist, 而是使用iterator的方式遍历。
在这里插入图片描述
在这里插入图片描述
remove(E)
在这里插入图片描述


ArrayLis
底层就是一个数组, 因此按序查找快, 乱序插入、删除因为涉及到后面元素移位所以性能慢。

add(index, E)
在这里插入图片描述
扩容

一般默认容量是10, 扩容后, 会length*1.5。
在这里插入图片描述
remove(E)

循环遍历数组, 判断E是否equals当前元素, 删除性能不如LinkedList.
在这里插入图片描述


【5】图

图是一组以网络形式相互连接的节点。节点也称为顶点。 一对节点(x,y)称为边(edge),表示顶点x连接到顶点y。边可以包含权重/成本,显示从顶点x到y所需的成本。

在这里插入图片描述
图的类型

  • 无向图
  • 有向图

在程序语言中,图可以用两种形式表示:

  • 邻接矩阵
  • 邻接表

常见图遍历算法

  • 广度优先搜索
  • 深度优先搜索

面试中关于图的常见问题

  • 实现广度和深度优先搜索
  • 检查图是否为树
  • 计算图的边数
  • 找到两个顶点之间的最短路径

【6】树

树形结构是一种层级式的数据结构,由顶点(节点)和连接它们的边组成。 树类似于图,但区分树和图的重要特征是树中不存在环路。

树形结构被广泛应用于人工智能和复杂算法,它可以提供解决问题的有效存储机制。

这是一个简单树的示意图,以及树数据结构中使用的基本术语:
在这里插入图片描述
Root - 根节点

Parent - 父节点

Child - 子节点

Leaf - 叶子节点

Sibling - 兄弟节点

以下是树形结构的主要类型:

  • N元树
  • 平衡树
  • 二叉树
  • 二叉搜索树
  • AVL树
  • 红黑树
  • 2-3树

其中,二叉树和二叉搜索树是最常用的树。

面试中关于树结构的常见问题:

  • 求二叉树的高度
  • 在二叉搜索树中查找第k个最大值
  • 查找与根节点距离k的节点
  • 在二叉树中查找给定节点的祖先节点

【7】字典树(Trie)

字典树,也称为“前缀树”,是一种特殊的树状数据结构,对于解决字符串相关问题非常有效。它能够提供快速检索,主要用于搜索字典中的单词,在搜索引擎中自动提供建议,甚至被用于IP的路由。

以下是在字典树中存储三个单词“top”,“thus”和“their”的例子:
在这里插入图片描述

这些单词以顶部到底部的方式存储,其中绿色节点“p”,“s”和“r”分别表示“top”,“thus”和“theirs”的底部。

面试中关于字典树的常见问题

  • 计算字典树中的总单词数
  • 打印存储在字典树中的所有单词
  • 使用字典树对数组的元素进行排序
  • 使用字典树从字典中形成单词
  • 构建T9字典(字典树+ DFS )

【8】哈希表

哈希法(Hashing)是一个用于唯一标识对象并将每个对象存储在一些预先计算的唯一索引(称为“键(key)”)中的过程。因此,对象以键值对的形式存储,这些键值对的集合被称为“字典”。可以使用键搜索每个对象。

基于哈希法有很多不同的数据结构,但最常用的数据结构是哈希表。哈希表通常使用数组实现。

散列数据结构的性能取决于以下三个因素:

  • 哈希函数
  • 哈希表的大小
  • 碰撞处理方法

下图为如何在数组中映射哈希键值对的说明。该数组的索引是通过哈希函数计算的:
在这里插入图片描述

面试中关于哈希结构的常见问题:

  • 在数组中查找对称键值对
  • 追踪遍历的完整路径
  • 查找数组是否是另一个数组的子集
  • 检查给定的数组是否不相交

【9】HashMap

最常用的哈希表, 内部通过数组 + 单链表的方式实现. jdk8中引入了红黑树对长度 > 8的链表进行优化。

put(K, V)
在这里插入图片描述
put(K, V) 相同hash值
在这里插入图片描述
resize 动态扩容

当map中元素超出设定的阈值后, 会进行resize (length * 2)操作, 扩容过程中对元素一通操作, 并放置到新的位置。

具体操作如下:

  • 在jdk7中对所有元素直接rehash, 并放到新的位置.
  • 在jdk8中判断元素原hash值新增的bit位是0还是1, 0则索引不变, 1则索引变成"原索引 + oldTable.length".
 //定义两条链
//原来的hash值新增的bit为0的链,头部和尾部
Node<K,V> loHead = null, loTail = null;
//原来的hash值新增的bit为1的链,头部和尾部
Node<K,V> hiHead = null, hiTail = null;
Node<K,V> next;
//循环遍历出链条链
do {next = e.next;if ((e.hash & oldCap) == 0) {if (loTail == null)loHead = e;elseloTail.next = e;loTail = e;}else {if (hiTail == null)hiHead = e;elsehiTail.next = e;hiTail = e;}} while ((e = next) != null);//扩容前后位置不变的链if (loTail != null) {loTail.next = null;newTab[j] = loHead;}//扩容后位置加上原数组长度的链if (hiTail != null) {hiTail.next = null;newTab[j + oldCap] = hiHead;}

在这里插入图片描述


【10】LinkedHashMap

继承自HashMap, 底层额外维护了一个双向链表来维持数据有序. 可以通过设置accessOrder来实现FIFO(插入有序)或者LRU(访问有序)缓存。

put(K, V)
在这里插入图片描述
get(K)

accessOrder为false的时候, 直接返回元素就行了, 不需要调整位置。

accessOrder为true的时候, 需要将最近访问的元素, 放置到队尾。

在这里插入图片描述
removeEldestEntry 删除最老的元素

在这里插入图片描述

参考博文:
Java集合概述和总结分析与图示
Java 程序员必须掌握的 8 道数据结构面试题,你会几道?
几张动态图捋清Java常用数据结构及其设计原理


http://chatgpt.dhexx.cn/article/lNRZO2Gg.shtml

相关文章

自从上了数据结构课之后就想自学c++了

所以今天是摆烂的第三天&#xff1a; 就是来总结一下自己刚学c常犯的小错误&#xff08;在注释里&#xff09;和总结吧&#xff1b; 先来看看hello world输出代码&#xff1b; //打了四遍这个代码终于对了TAT //在一整个程序里面如果有多个文件并且不止一个main函数的话&…

如何学好数据结构?

大家好&#xff0c;我是程序员吴师兄。 最近在公众号发布了不少图解 LeetCode 的文章&#xff0c;一些同学在后台打卡&#xff0c;甚是感动&#xff0c;以后也会每天都发布一篇&#xff0c;希望能帮助大家更好的刷题&#xff0c;通过算法面试&#xff0c;进入心仪的大厂。 谈到…

为什么要学数据结构?

文章目录 一、前言二、为什么要学数据结构三、数据结构无处不在3.1 数据库3.2 操作系统3.3 文件压缩3.4 游戏 四、数据结构类型 一、前言 在可视化化程序设计的今天&#xff0c;借助于集成开发环境可以很快地生成程序&#xff0c;程序设计不再是计算机专业人员的专利。很多人认…

如何学习数据结构与算法

经过一段时间的数据结构与算法的学习&#xff0c;和学习了前人的经验&#xff0c;为了更好的指导自己&#xff08;希望也能帮助到别人&#xff09;之后数据结构与算法的学习&#xff0c;总结一下数据结构与算法学习的方法。 一、记住数据结构&#xff0c;记住算法思想&#xf…

怎样学好数据结构

1、数据结构学习思路 &#xff08;1&#xff09;数据结构是计算机专业最重要最基础的一门课&#xff0c;对于有过编程经验的人&#xff0c;结合自己的编程体会去领悟它的思想&#xff1b;对于初学者&#xff0c;选择一种自己最熟悉的语言去分析它。而且&#xff0c;随着编程经…

如何自学《数据结构与算法》?

众所周知&#xff0c;《数据结构与算法》是程序员面试中的重中之重&#xff0c;也是编程中非常重要的组成部分&#xff0c;然而非科班出身的人&#xff0c;学起来有一个相当长的探索期。下面我整理了一个数据结构与算法的思维导图&#xff0c;供大家参考。 1.总览 2.学习方法 …

入门篇|学渣是如何自学数据结构的?

作者 | 小鹿 来源 | 一个不甘平凡的码农 写在前边 ------------------------------------------- 今日明哥推荐一篇文章&#xff0c;小鹿是个勤快并且认知定位非常清晰&#xff0c;有极强的执行能力的小伙子。作为一个大学生&#xff0c;这个就很流弊了。有时候不是你多牛&am…

MATLAB的.fig文件打不开——有效解决

如果没有报错的话&#xff0c;那么可能是显示关了。报错可能是保存方式不对。可以看下面例子。 文章目录 没报错但打不开报错 没报错但打不开 示例正弦函数图像。 x -pi:pi; y sin(x);显示功能关闭打不开。 figure(visible,off); plot(x,y) savefig(1.fig);下面打得开 f…

matlab命令打开Word文档

本博文源于Matlab骚操作系列&#xff0c;旨在讲述文档打开操作。首先要保证自己有Word。然后我们开始实验。 实验步骤 创建Word服务器设置Word服务器可见新建空白文档写入文档内容保存文档 实验内容 创建word服务器 >> try Word actxGetRunningServer(Word.Applicat…

MATLAB无法直接打开M文件

MATLAB无法直接打开M文件 啊这1. 下载MATLAB文件关联&快捷修复文件2. 在MATLAB添加路径3. 运行associateFiles.m4. 打开生成的注册表文件5. 重启电脑 啊这 穷折腾装了个2020试试&#xff0c;发现安装后没有关联M文件。 添加打开方式为MATLAB&#xff0c;打开M文件只能启动…

matlab无法打开excel的问题

matlab无法打开excel problem怎么解决 problem 重装系统时直接移植了matlab和office两个大套件&#xff0c;之前用matlab调用读取电子表格一直没有什么问题&#xff0c;今天在统计手机上网流量的时候想用matlab对表格里的单位处理一下&#xff0c;好家伙这玩意给我报错把我搞懵…

Matlab突然打不开,运行后一闪就消失了,任务管理器也没有的解决办法

记录一下平时遇到的一些bug Matlab官方issue 参考官网链接有3种可能导致标题现象 一种一种试一下&#xff0c;包括删掉Appdata文件夹的Matlab r2020a文件夹(对我的计算机无效) 最后我的计算机试到第三种就可以了 在桌面启动程序属性里目标路径后加 -nodesktop 再双击运行就…

MATLAB安装后出现问题:MTALAB2021安装后闪退打不开

我之前安装的是2017版本&#xff0c;因需要用到一些最新功能&#xff0c;卸载后安装了2021版本。但按要求安装后无法打开&#xff0c;双击后闪一下&#xff0c;打不开。从网上了解到可能是Windows系统预设文件的损坏&#xff08;具体我也不清楚&#xff0c;但按步骤可以实现软件…

打开matlab闪退的原因

1.请确定是闪退打不开&#xff0c;还是启动缓慢&#xff1f; 这两天打算掌握一项新技能——Matlab&#xff0c;于是京东买了一本书《MATLAB 2020 从入门到精通实战案例版》 于是下载安装了&#xff0c;matlab 2020b,文件是真的大。下载加安装花了一个小时左右&#xff0c;实际…

电脑上安装的matlab软件打不开怎么办,电脑软件打不开没反应怎么办?

我们在使用电脑的过程中&#xff0c;经常会碰到电脑软件打不开没反应的情况&#xff0c;而检查软件并未发现任何错误问题&#xff0c;这时该怎么办呢&#xff1f;其实解决方法并不难&#xff0c;下面小编给大家分享电脑软件打不开的应对技巧。 XP系统方法/步骤&#xff1a; 1、…

解决MATLAB帮助文档打不开的情况

解决MATLAB帮助文档打不开的情况 问题描述 今天在MATLAB命令行窗口中输入【doc find】&#xff0c;出现了帮助文档打不开的情况。如图1所示。 图1 帮助文档打不开 解决办法 在MATLAB的【主页】中点击【预设】。如图2所示。 图2 点击【预设】 打开之后&#xff0c;如图3所示。…

matlab 18保存的mat数据,MATLAB7打不开

有时候在我们用MATLAB18或者更高版本保存mat数据&#xff0c;可能出现MATLAB7无法打开的现象&#xff0c;根据其他博主的意思可能是因为路径有中文之类的&#xff0c;还有一种情况&#xff0c;是MATLAB18保存的mat数据版本不同&#xff0c;可以更改默认的保存版本&#xff0c;然…

matlab安装后不能打开怎么办,matlab7.0安装后打不开_matlab7.0安装后不能用

一、MATLAB出现errorstartingdesktop错误 1、首先在桌面上鼠标右键点击MATLAB7.0快捷方式&#xff01;如下图所示 2、进入快捷方式属性界面&#xff0c;点击兼容性选项卡&#xff0c;如下图所示 3、勾选如下图的复选项&#xff01;如下图所示 4、选择windows2000这个选择&#…

MATLAB打不开,选择licenses激活成功后还是要激活

2017国庆前还用matlab写了程序&#xff0c;现在想看看当时的程序&#xff0c;哪知道几个月不用&#xff0c;MATLAB打不开了&#xff0c;提示要激活。 图1.激活页面 因为之前都能用&#xff0c;那肯定是有许可证文件的&#xff0c;所以我选择了不适用Internet手动激活&#xff…

linux 平台下 MATLAB 打不开图形界面

遇到一个问题&#xff0c;在linux系统上打开MATLAB时界面&#xff08;直接输入>>matlab&#xff09;出现到一半就崩溃了。 提示&#xff1a; ** This crash report has been saved to disk as /home/hipeson/matlab_crash_dump.218342-1 ** MATLAB is exiting because…