<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom"><channel><title>复习-JavaGuide-Data-Structure on 随记</title><link>https://blog.liuyi2026.asia/zh/tags/%E5%A4%8D%E4%B9%A0-javaGuide-data-structure/</link><description>Recent content in 复习-JavaGuide-Data-Structure on 随记</description><generator>Hugo</generator><language>zh</language><lastBuildDate>Mon, 09 Jan 2023 15:52:34 +0000</lastBuildDate><atom:link href="https://blog.liuyi2026.asia/zh/tags/%E5%A4%8D%E4%B9%A0-javaGuide-data-structure/index.xml" rel="self" type="application/rss+xml"/><item><title>树</title><link>https://blog.liuyi2026.asia/zh/docs/technology/Review/java_guide/cs_basics/data-structure/tree/</link><pubDate>Mon, 09 Jan 2023 15:52:34 +0000</pubDate><guid>https://blog.liuyi2026.asia/zh/docs/technology/Review/java_guide/cs_basics/data-structure/tree/</guid><description>&lt;blockquote class='book-hint '>
&lt;p>转载自https://github.com/Snailclimb/JavaGuide（添加小部分笔记）感谢作者!&lt;/p>&lt;/blockquote>&lt;ul>
&lt;li>
&lt;p>树是一种类似现实生活中的树的数据结构（&lt;strong>倒置的树&lt;/strong>）&lt;/p>
&lt;/li>
&lt;li>
&lt;p>任何一颗非空树&lt;strong>只有一个根节点&lt;/strong>&lt;/p>
&lt;/li>
&lt;li>
&lt;p>一棵树具有以下特点：&lt;/p>
&lt;ol>
&lt;li>一棵树中的任何两个节点有且仅有唯一的一条路相通 （因为每个结点只会有一个父节点）&lt;/li>
&lt;li>一棵树如果有n个节点，那么它一定恰好有n-1条边&lt;/li>
&lt;li>一棵树不包括回路&lt;/li>
&lt;/ol>
&lt;/li>
&lt;li>
&lt;p>下面是一颗&lt;strong>二叉树&lt;/strong>
&lt;img src="img/ly-20241212141852140.png" alt="ly-20241212141852140" />
深度和高度是对应的；根节点所在层为1层&lt;/p>
&lt;/li>
&lt;li>
&lt;p>常用概念&lt;/p>
&lt;ol>
&lt;li>
&lt;p>节点：树中每个元素都可以统称为节点&lt;/p>
&lt;/li>
&lt;li>
&lt;p>根节点：顶层节点，或者说没有父节点的节点。上图中A节点就是根节点&lt;/p>
&lt;/li>
&lt;li>
&lt;p>父节点：若一个节点含有子节点，则这个节点称为其子节点的父节点。上图中的 B 节点是 D 节点、E 节点的父节点&lt;/p>
&lt;/li>
&lt;li>
&lt;p>兄弟节点：具有&lt;strong>相同父节点的节点&lt;/strong>互称为兄弟节点。上图中 D 节点、E 节点的共同父节点是 B 节点，故 D 和 E 为兄弟节点。&lt;/p>
&lt;/li>
&lt;li>
&lt;p>叶子节点：&lt;strong>没有子节点&lt;/strong>的节点。上图中的 D、F、H、I 都是叶子节点&lt;/p>
&lt;/li>
&lt;li>
&lt;p>节点的高度**（跟叶子节点有关，同一层不一定一样）&lt;strong>：&lt;strong>该节点到叶子节点&lt;/strong>的&lt;/strong>最长&lt;strong>路径&lt;/strong>所包含的&lt;strong>边数&lt;/strong>。&lt;/p>
&lt;/li>
&lt;li>
&lt;p>节点的深度**（跟根节点有关，同一层是一样的）&lt;strong>：&lt;strong>根节点到该节点&lt;/strong>的路径所包含的&lt;/strong>边数**&lt;/p>
&lt;/li>
&lt;li>
&lt;p>节点的层数：节点的深度+1&lt;/p>
&lt;/li>
&lt;li>
&lt;p>树的高度：根节点的高度&lt;/p>
&lt;/li>
&lt;/ol>
&lt;/li>
&lt;/ul>
&lt;h1 id="二叉树的分类">二叉树的分类&lt;a class="anchor" href="#%e4%ba%8c%e5%8f%89%e6%a0%91%e7%9a%84%e5%88%86%e7%b1%bb">#&lt;/a>&lt;/h1>
&lt;ul>
&lt;li>**二叉树（Binary tree）**是每个节点最多只有两个分支（即不存在分支度大于2的节点）的树结构&lt;/li>
&lt;li>&lt;strong>二叉树&lt;/strong>的分支，通常被称为&lt;strong>左子树&lt;/strong>或&lt;strong>右子树&lt;/strong>，并且，&lt;strong>二叉树&lt;/strong>的分支具有左右次序，不能随意颠倒&lt;/li>
&lt;li>&lt;strong>二叉树&lt;/strong>的第i层至多拥有&lt;strong>2^(i-1)&lt;/strong> 个节点&lt;br>
深度为&lt;strong>k&lt;/strong>的二叉树至多总共有 &lt;strong>2^(k+1) -1&lt;/strong> 个节点 （深度为k，最多k + 1 层，最多为满二叉树的情况）&lt;br>
至少有2^(k) 个节点，即 深度为k-1的二叉树的最多的节点再加1&lt;/li>
&lt;/ul>
&lt;blockquote class='book-hint '>
&lt;p>（关于节点的深度的定义国内争议比较多，我个人比较认可维基百科对
&lt;a target="_blank" href="https://zh.wikipedia.org/wiki/%E6%A0%91_%28%E6%95%B0%E6%8D%AE%E7%BB%93%E6%9E%84%29#/%E6%9C%AF%E8%AF%AD">节点深度的定义open in new window&lt;/a>）。
&lt;img src="img/ly-20241212141852434.png" alt="ly-20241212141852434" />&lt;/p>&lt;/blockquote>&lt;h2 id="满二叉树">满二叉树&lt;a class="anchor" href="#%e6%bb%a1%e4%ba%8c%e5%8f%89%e6%a0%91">#&lt;/a>&lt;/h2>
&lt;p>一个二叉树，如果每一个&lt;strong>层&lt;/strong>的结点数都达到最大值，则这个二叉树就是 &lt;strong>满二叉树&lt;/strong>。也就是说，如果一个&lt;strong>二叉树的层数&lt;/strong>为 K，且结点总数是(2^k) -1 ，则它就是 &lt;strong>满二叉树&lt;/strong>。
&lt;img src="img/ly-20241212141852640.png" alt="ly-20241212141852640" />&lt;/p></description></item><item><title>堆</title><link>https://blog.liuyi2026.asia/zh/docs/technology/Review/java_guide/cs_basics/data-structure/heap/</link><pubDate>Fri, 06 Jan 2023 10:46:19 +0000</pubDate><guid>https://blog.liuyi2026.asia/zh/docs/technology/Review/java_guide/cs_basics/data-structure/heap/</guid><description>&lt;blockquote class='book-hint '>
&lt;p>转载自https://github.com/Snailclimb/JavaGuide（添加小部分笔记）感谢作者!&lt;/p>&lt;/blockquote>&lt;h1 id="什么是堆">什么是堆&lt;a class="anchor" href="#%e4%bb%80%e4%b9%88%e6%98%af%e5%a0%86">#&lt;/a>&lt;/h1>
&lt;ul>
&lt;li>
&lt;p>堆是&lt;strong>满足以下条件&lt;/strong>的树
堆中每一个节点值都&lt;strong>大于等于（或小于等于）子树中所有节点&lt;/strong>。或者说，任意一个节点的值**都大于等于（或小于等于）**所有子节点的值&lt;/p>
&lt;blockquote class='book-hint '>
&lt;p>大家可以把堆(最大堆)理解为一个公司,这个公司很公平,谁能力强谁就当老大,不存在弱的人当老大,老大手底下的人一定不会比他强。这样有助于理解后续堆的操作。&lt;/p>&lt;/blockquote>&lt;ul>
&lt;li>&lt;strong>堆不一定是完全二叉树&lt;/strong>，为了方便&lt;strong>存储&lt;/strong>和&lt;strong>索引&lt;/strong>，我们通常用完全二叉树的形式来表示堆&lt;br>
广为人知的&lt;strong>斐波那契堆&lt;/strong>和&lt;strong>二项堆&lt;/strong>就不是完全二叉树，它们甚至都&lt;strong>不是二叉树&lt;/strong>&lt;/li>
&lt;li>(二叉)堆是一个数组，它可以被看成是一个&lt;strong>近似的完全二叉树&lt;/strong>&lt;/li>
&lt;/ul>
&lt;/li>
&lt;li>
&lt;p>下面给出的图是否是堆（通过定义）&lt;/p>
&lt;p>1，2是。
3不是。
&lt;img src="img/ly-20241212141845610.png" alt="ly-20241212141845610" />&lt;/p>
&lt;/li>
&lt;/ul>
&lt;h1 id="堆的用途">堆的用途&lt;a class="anchor" href="#%e5%a0%86%e7%9a%84%e7%94%a8%e9%80%94">#&lt;/a>&lt;/h1>
&lt;ul>
&lt;li>
&lt;p>当我们&lt;strong>只关心&lt;/strong>所有数据中的&lt;strong>最大值&lt;/strong>或者&lt;strong>最小值&lt;/strong>，存在&lt;strong>多次获取最大值&lt;/strong>或者&lt;strong>最小值&lt;/strong>，多次插入或删除数据时，就可以使用堆。&lt;/p>
&lt;blockquote class='book-hint '>
&lt;p>有小伙伴可能会想到用&lt;strong>有序数组&lt;/strong>，初始化一个有序数组时间复杂度是 &lt;code>O(nlog(n))&lt;/code>&lt;strong>[也就是将一堆数字乱序排序，最快是O(nlog(n))]&lt;/strong>，查找最大值或者最小值时间复杂度都是 &lt;code>O(1)&lt;/code>，但是，涉及到更新（插入或删除）数据时，时间复杂度为 &lt;code>O(n)&lt;/code>，即使是使用复杂度为 &lt;code>O(log(n))&lt;/code> 的二分法找到要插入或者删除的数据，在移动数据时也需要 &lt;code>O(n)&lt;/code> 的时间复杂度。&lt;/p>&lt;/blockquote>&lt;/li>
&lt;li>
&lt;p>相对于有序数组而言，堆的主要优势在于更新数据效率较高&lt;/p>
&lt;ul>
&lt;li>堆的&lt;strong>初始化时间复杂度&lt;/strong>为O(nlog(n))，堆可以做到&lt;strong>O(1)&lt;strong>的时间复杂度取出&lt;/strong>最大值&lt;/strong>或者&lt;strong>最小值&lt;/strong>，&lt;strong>O(log(n))&lt;strong>的时间复杂度&lt;/strong>插入或者删除&lt;/strong>数据&lt;/li>
&lt;/ul>
&lt;/li>
&lt;/ul>
&lt;h1 id="堆的分类">堆的分类&lt;a class="anchor" href="#%e5%a0%86%e7%9a%84%e5%88%86%e7%b1%bb">#&lt;/a>&lt;/h1>
&lt;ul>
&lt;li>堆分为&lt;strong>最大堆&lt;/strong>和&lt;strong>最小堆&lt;/strong>，二者的区别在于节点的&lt;strong>排序方式&lt;/strong>
&lt;ul>
&lt;li>最大堆：堆中的每一个节点的值&lt;strong>都大于&lt;/strong>子树中&lt;strong>所有节点&lt;/strong>的值&lt;/li>
&lt;li>最小堆：堆中的每一个节点的值&lt;strong>都小于&lt;/strong>子树中&lt;strong>所有节点&lt;/strong>的值&lt;/li>
&lt;/ul>
&lt;/li>
&lt;li>如图，图1是最大堆，图2是最小堆
&lt;img src="img/ly-20241212141845906.png" alt="ly-20241212141845906" />&lt;/li>
&lt;/ul>
&lt;h1 id="堆的存储">堆的存储&lt;a class="anchor" href="#%e5%a0%86%e7%9a%84%e5%ad%98%e5%82%a8">#&lt;/a>&lt;/h1>
&lt;ul>
&lt;li>由于&lt;strong>完全二叉树的优秀性质&lt;/strong>，&lt;strong>利用数组存储二叉树&lt;/strong>即节省空间，又&lt;strong>方便索引&lt;/strong>（若根结点的序号为1，那么对于树中任意节点i，其左子节点序号为 &lt;code>2*i&lt;/code>，右子节点序号为 &lt;code>2*i+1&lt;/code>）。&lt;/li>
&lt;li>为了&lt;strong>方便存储&lt;/strong>和&lt;strong>索引&lt;/strong>，&lt;strong>（二叉）堆&lt;/strong>可以用&lt;strong>完全二叉树&lt;/strong>的形式进行存储。存储的方式如下图所示
&lt;img src="img/ly-20241212141846083.png" alt="ly-20241212141846083" />&lt;/li>
&lt;/ul>
&lt;h1 id="堆的操作">堆的操作&lt;a class="anchor" href="#%e5%a0%86%e7%9a%84%e6%93%8d%e4%bd%9c">#&lt;/a>&lt;/h1>
&lt;ul>
&lt;li>
&lt;p>堆的更新操作主要包括两种：&lt;strong>插入元素&lt;/strong>和&lt;strong>删除堆顶元素&lt;/strong>&lt;/p>
&lt;blockquote class='book-hint '>
&lt;p>堆是一个公平的公司，&lt;strong>有能力的人&lt;/strong>自然会走到与他能力所匹配的位置&lt;/p>&lt;/blockquote>&lt;/li>
&lt;/ul>
&lt;h2 id="插入元素">插入元素&lt;a class="anchor" href="#%e6%8f%92%e5%85%a5%e5%85%83%e7%b4%a0">#&lt;/a>&lt;/h2>
&lt;ol>
&lt;li>将要插入的元素放到&lt;strong>最后&lt;/strong>
&lt;img src="img/ly-20241212141846259.png" alt="ly-20241212141846259" />&lt;/li>
&lt;li>从底向上，如果&lt;strong>父节点&lt;/strong>比&lt;strong>该元素小&lt;/strong>，则该节点和父节点交换（其实就是一棵树有3个（最多）节点，与树上最大的节点比较）
直到无法交换（已经与根节点比较过）
&lt;img src="img/ly-20241212141846433.png" alt="ly-20241212141846433" />
&lt;img src="img/ly-20241212141846614.png" alt="ly-20241212141846614" />&lt;/li>
&lt;/ol>
&lt;h2 id="删除堆顶元素">删除堆顶元素&lt;a class="anchor" href="#%e5%88%a0%e9%99%a4%e5%a0%86%e9%a1%b6%e5%85%83%e7%b4%a0">#&lt;/a>&lt;/h2>
&lt;ul>
&lt;li>
&lt;p>根据堆的性质可知，&lt;strong>最大堆&lt;/strong>的堆盯元素为所有元素中最大的，&lt;strong>最小堆&lt;/strong>的堆顶元素是所有元素中最小的&lt;/p>
&lt;/li>
&lt;li>
&lt;p>当我们需要多次查找&lt;strong>最大元素&lt;/strong>或者&lt;strong>最小元素&lt;/strong>的时候，可以利用堆来实现&lt;/p>
&lt;/li>
&lt;li>
&lt;p>删除堆顶元素后，为了保持&lt;strong>堆的性质&lt;/strong>，需要对堆的结构进行调整，我们可以将这个过程称之为&lt;strong>堆化&lt;/strong>&lt;/p>
&lt;ol>
&lt;li>&lt;strong>自底向上&lt;/strong>的堆化，上述的&lt;strong>插入元素&lt;/strong>所使用的，就是自顶向上的&lt;strong>堆化&lt;/strong>，元素从最底部向上移动&lt;/li>
&lt;li>&lt;strong>自顶向下&lt;/strong>的堆化，元素由&lt;strong>顶部向下&lt;/strong>移动。在讲解删除堆顶元素的方法时，我将阐述这&lt;strong>两种操作的过程&lt;/strong>&lt;/li>
&lt;/ol>
&lt;/li>
&lt;li>
&lt;p>&lt;strong>自底向上堆化&lt;/strong>&lt;/p>
&lt;blockquote class='book-hint '>
&lt;p>在堆这个公司中，会出现老大离职的现象，老大离职之后，它的位置就空出来了&lt;/p>&lt;/blockquote>&lt;ol>
&lt;li>
&lt;p>首先删除堆顶元素，使得数组中下标为1的位置空出
&lt;img src="img/ly-20241212141846789.png" alt="ly-20241212141846789" />&lt;/p>
&lt;blockquote class='book-hint '>
&lt;p>那么他的位置由谁来接替呢，当然是他的直接下属了，谁能力强就让谁上&lt;/p>&lt;/blockquote>&lt;/li>
&lt;li>
&lt;p>比较&lt;strong>根节点（当前节点）&lt;strong>的&lt;/strong>左子节点&lt;/strong>和&lt;strong>右子节点&lt;/strong>，也就是下标为 2 ，3 的数组元素，将较大的元素填充到**根节点（下标为1）（当前遍历节点）**的位置
&lt;img src="img/ly-20241212141846962.png" alt="ly-20241212141846962" />&lt;/p></description></item><item><title>图</title><link>https://blog.liuyi2026.asia/zh/docs/technology/Review/java_guide/cs_basics/data-structure/graph/</link><pubDate>Mon, 26 Dec 2022 08:47:25 +0000</pubDate><guid>https://blog.liuyi2026.asia/zh/docs/technology/Review/java_guide/cs_basics/data-structure/graph/</guid><description>&lt;blockquote class='book-hint '>
&lt;p>转载自https://github.com/Snailclimb/JavaGuide（添加小部分笔记）感谢作者!&lt;/p>&lt;/blockquote>&lt;ul>
&lt;li>图是一种较为复杂的&lt;strong>非线性&lt;/strong>结构&lt;/li>
&lt;li>&lt;strong>线性&lt;/strong>数据结构的元素满足唯一的线性关系，&lt;strong>每个元素&lt;/strong>（除第一个和最后一个外）只有一个&lt;strong>直接前驱&lt;/strong>和一个&lt;strong>直接后继&lt;/strong>&lt;/li>
&lt;li>&lt;strong>树形&lt;/strong>数据结构的元素之间有着明显的&lt;strong>层级关系&lt;/strong>&lt;/li>
&lt;li>&lt;strong>图形&lt;/strong>结构的元素之间的关系是任意的
&lt;ul>
&lt;li>图就是由&lt;strong>顶点&lt;/strong>的&lt;strong>有穷非空集合&lt;/strong>和顶点之间的&lt;strong>边&lt;/strong>组成的集合，通常表示为：&lt;strong>G（V，E）&lt;/strong>，其中，G表示一个图，V表示顶点的集合，E表示边的集合&lt;/li>
&lt;li>下面显示的即&lt;strong>图&lt;/strong>这种数据结构，而且还是一张&lt;strong>有向图&lt;/strong>
&lt;img src="img/ly-20241212141841748.png" alt="ly-20241212141841748" />&lt;/li>
&lt;/ul>
&lt;/li>
&lt;/ul>
&lt;h1 id="图的基本概念">图的基本概念&lt;a class="anchor" href="#%e5%9b%be%e7%9a%84%e5%9f%ba%e6%9c%ac%e6%a6%82%e5%bf%b5">#&lt;/a>&lt;/h1>
&lt;h2 id="顶点">顶点&lt;a class="anchor" href="#%e9%a1%b6%e7%82%b9">#&lt;/a>&lt;/h2>
&lt;ul>
&lt;li>图中的&lt;strong>数据元素&lt;/strong>，我们称之为&lt;strong>顶点&lt;/strong>，图至少有一个&lt;strong>顶点&lt;/strong>（&lt;strong>有穷非空&lt;/strong>集合）&lt;/li>
&lt;li>对应到好友关系图，&lt;strong>每一个用户&lt;/strong>就代表&lt;strong>一个顶点&lt;/strong>&lt;/li>
&lt;/ul>
&lt;h2 id="边">边&lt;a class="anchor" href="#%e8%be%b9">#&lt;/a>&lt;/h2>
&lt;ul>
&lt;li>顶点之间的&lt;strong>关系&lt;/strong>用&lt;strong>边&lt;/strong>表示&lt;/li>
&lt;li>对应到好友关系图，两个用户是好友的话，那两者之间就存在一条&lt;strong>边&lt;/strong>&lt;/li>
&lt;/ul>
&lt;h2 id="度">度&lt;a class="anchor" href="#%e5%ba%a6">#&lt;/a>&lt;/h2>
&lt;ul>
&lt;li>度表示一个顶点包含多少条边&lt;/li>
&lt;li>有向图中，分为&lt;strong>出度&lt;/strong>和&lt;strong>入度&lt;/strong>，出度表示&lt;strong>从该顶点出去的边&lt;/strong>的条数，入度表示&lt;strong>从进入该顶点的边&lt;/strong>的条数&lt;/li>
&lt;li>对应到好友关系图，度就代表了某个人的&lt;strong>好友数量&lt;/strong>&lt;/li>
&lt;/ul>
&lt;h2 id="无向图和有向图">无向图和有向图&lt;a class="anchor" href="#%e6%97%a0%e5%90%91%e5%9b%be%e5%92%8c%e6%9c%89%e5%90%91%e5%9b%be">#&lt;/a>&lt;/h2>
&lt;p>边表示的是顶点之间的关系，有的关系是双向的，比如同学关系，A是B的同学，那么B也肯定是A的同学，那么在表示A和B的关系时，就不用关注方向，用&lt;strong>不带箭头的边&lt;/strong>表示，这样的图就是&lt;strong>无向图&lt;/strong>。&lt;/p>
&lt;p>有的关系是有方向的，比如父子关系，师生关系，微博的关注关系，A是B的爸爸，但B肯定不是A的爸爸，A关注B，B不一定关注A。在这种情况下，我们就用&lt;strong>带箭头的边&lt;/strong>表示二者的关系，这样的图就是&lt;strong>有向图&lt;/strong>。&lt;/p>
&lt;h2 id="无权图和带权图">无权图和带权图&lt;a class="anchor" href="#%e6%97%a0%e6%9d%83%e5%9b%be%e5%92%8c%e5%b8%a6%e6%9d%83%e5%9b%be">#&lt;/a>&lt;/h2>
&lt;p>对于一个关系，如果我们只关心关系的有无，而&lt;strong>不关心关系有多强&lt;/strong>，那么就可以用&lt;strong>无权图&lt;/strong>表示二者的关系。&lt;/p>
&lt;p>对于一个关系，如果我们既&lt;strong>关心关系的有无&lt;/strong>，也关心&lt;strong>关系的强度&lt;/strong>，比如描述地图上&lt;strong>两个城市的关系&lt;/strong>，需要用到&lt;strong>距离&lt;/strong>，那么就用&lt;strong>带权图&lt;/strong>来表示，&lt;strong>带权图中的每一条边一个数值表示权值&lt;/strong>，代表&lt;strong>关系的强度&lt;/strong>。&lt;/p>
&lt;p>下图就是一个&lt;strong>带权有向图&lt;/strong>。&lt;/p>
&lt;p>&lt;img src="img/ly-20241212141842057.png" alt="ly-20241212141842057" />&lt;/p>
&lt;h1 id="图的存储">图的存储&lt;a class="anchor" href="#%e5%9b%be%e7%9a%84%e5%ad%98%e5%82%a8">#&lt;/a>&lt;/h1>
&lt;h2 id="邻接矩阵存储">邻接矩阵存储&lt;a class="anchor" href="#%e9%82%bb%e6%8e%a5%e7%9f%a9%e9%98%b5%e5%ad%98%e5%82%a8">#&lt;/a>&lt;/h2>
&lt;ul>
&lt;li>邻接矩阵将图用&lt;strong>二维矩阵&lt;/strong>存储，是一种比较&lt;strong>直观&lt;/strong>的表示方式&lt;/li>
&lt;li>如果第i个顶点和第j个顶点&lt;strong>有关系&lt;/strong>，且&lt;strong>关系权值&lt;/strong>为n，则A[i] [j] = n&lt;/li>
&lt;li>在无向图中，我们只关心关系的有无，所以当&lt;strong>顶点i&lt;/strong>和&lt;strong>顶点j&lt;/strong>有关系时，A[i] [j]=1 ; 当顶点i和顶点j没有关系时，A[i] [j] = 0 ，如下图所示&lt;br>
&lt;img src="img/ly-20241212141842233.png" alt="ly-20241212141842233" />
无向图的邻接矩阵是一个&lt;strong>对称&lt;/strong>矩阵，因为在无向图中，&lt;strong>顶点i&lt;/strong>和&lt;strong>顶点j&lt;/strong>有关系，则&lt;strong>顶点j&lt;/strong>和&lt;strong>顶点i&lt;/strong>必有关系&lt;/li>
&lt;li>有向图的邻接矩阵存储
&lt;img src="img/ly-20241212141842414.png" alt="ly-20241212141842414" />
邻接矩阵存储的方式优点是&lt;strong>简单直接（直接使用一个二维数组即可）&lt;/strong>，并且在获取两个顶点之间的关系的时候也非常高效*直接获取指定位置的&lt;strong>数组&lt;/strong>元素。但是这种存储方式的确定啊也比较明显&lt;strong>即 比较浪费空间&lt;/strong>&lt;/li>
&lt;/ul>
&lt;h2 id="邻接表存储">邻接表存储&lt;a class="anchor" href="#%e9%82%bb%e6%8e%a5%e8%a1%a8%e5%ad%98%e5%82%a8">#&lt;/a>&lt;/h2>
&lt;ul>
&lt;li>
&lt;p>针对上面邻接矩阵比较浪费内存空间的问题，诞生了图的另一种存储方法&amp;ndash;&lt;strong>邻接表&lt;/strong>&lt;/p>
&lt;/li>
&lt;li>
&lt;p>邻接链表使用一个&lt;strong>链表&lt;/strong>来存储某个顶点的&lt;strong>所有后继相邻顶点&lt;/strong>。对于图中每个顶点Vi ，把所有邻接于Vi 的顶点Vj 链接成一个&lt;strong>单链表&lt;/strong>&lt;/p>
&lt;ul>
&lt;li>无向图的邻接表存储
&lt;img src="img/ly-20241212141842597.png" alt="ly-20241212141842597" />&lt;/li>
&lt;li>有向图的邻接表存储
&lt;img src="img/ly-20241212141842773.png" alt="ly-20241212141842773" />&lt;/li>
&lt;/ul>
&lt;/li>
&lt;li>
&lt;p>邻接表中存储的元素的个数（顶点数）以及图中&lt;strong>边的条数&lt;/strong>&lt;/p>
&lt;ul>
&lt;li>
&lt;p>无向图中，&lt;strong>邻接表&lt;/strong>的元素个数等于&lt;strong>边的条数&lt;/strong>的两倍，如下图
7条边，邻接表存储的元素个数为14 （即&lt;strong>每条边存储了两次&lt;/strong>）&lt;/p>
&lt;p>&lt;img src="img/ly-20241212141842952.png" alt="ly-20241212141842952" />&lt;/p>
&lt;/li>
&lt;li>
&lt;p>有向图中，邻接表元素个数等于边的条数，如图所示的有向图中，边的条数为8，邻接表
&lt;img src="img/ly-20241212141843127.png" alt="ly-20241212141843127" />&lt;/p>
&lt;/li>
&lt;/ul>
&lt;/li>
&lt;/ul>
&lt;h1 id="图的搜索">图的搜索&lt;a class="anchor" href="#%e5%9b%be%e7%9a%84%e6%90%9c%e7%b4%a2">#&lt;/a>&lt;/h1>
&lt;h2 id="广度优先搜索">广度优先搜索&lt;a class="anchor" href="#%e5%b9%bf%e5%ba%a6%e4%bc%98%e5%85%88%e6%90%9c%e7%b4%a2">#&lt;/a>&lt;/h2>
&lt;ul>
&lt;li>
&lt;p>广度优先搜索：像水面上的波纹一样，一层一层向外扩展，如图
&lt;img src="img/ly-20241212141843300.png" alt="ly-20241212141843300" />&lt;/p></description></item><item><title>线性数据结构</title><link>https://blog.liuyi2026.asia/zh/docs/technology/Review/java_guide/cs_basics/data-structure/linear-data-structure/</link><pubDate>Tue, 20 Dec 2022 13:34:59 +0000</pubDate><guid>https://blog.liuyi2026.asia/zh/docs/technology/Review/java_guide/cs_basics/data-structure/linear-data-structure/</guid><description>&lt;blockquote class='book-hint '>
&lt;p>转载自https://github.com/Snailclimb/JavaGuide（添加小部分笔记）感谢作者!&lt;/p>&lt;/blockquote>&lt;h1 id="数组">数组&lt;a class="anchor" href="#%e6%95%b0%e7%bb%84">#&lt;/a>&lt;/h1>
&lt;ul>
&lt;li>数组（Array）是一种常见数据结构，由&lt;strong>相同类型的元素（element）&lt;strong>组成，并且是使用一块&lt;/strong>连续的内存&lt;/strong>来存储&lt;/li>
&lt;li>直接可以利用元素的**索引（index）**可以计算出该元素对应的存储地址&lt;/li>
&lt;li>数组的特点是：提供&lt;strong>随机访问&lt;/strong>并且&lt;strong>容量有限&lt;/strong>&lt;/li>
&lt;/ul>
&lt;blockquote class='book-hint '>
&lt;p>假设数组长度为n：&lt;br>
访问：O(1) //访问特定位置的元素&lt;/p>
&lt;p>插入：O(n) //最坏的情况插入在数组的&lt;strong>首部&lt;/strong>并需要&lt;strong>移动所有元素&lt;/strong>时&lt;/p>
&lt;p>删除：O(n) //最坏的情况发生在删除数组的&lt;strong>开头&lt;/strong>并需要移动&lt;strong>第一元素&lt;/strong>后面所有的元素时&lt;/p>&lt;/blockquote>&lt;p>&lt;img src="img/ly-20241212141849981.png" alt="ly-20241212141849981" />&lt;/p>
&lt;h1 id="链表">链表&lt;a class="anchor" href="#%e9%93%be%e8%a1%a8">#&lt;/a>&lt;/h1>
&lt;h2 id="链表简介">链表简介&lt;a class="anchor" href="#%e9%93%be%e8%a1%a8%e7%ae%80%e4%bb%8b">#&lt;/a>&lt;/h2>
&lt;ul>
&lt;li>
&lt;p>链表（LinkedList）虽然是一种&lt;strong>线性表&lt;/strong>，但是并&lt;strong>不会按线性&lt;/strong>的顺序&lt;strong>存储&lt;/strong>数据，使用的&lt;strong>不是&lt;/strong>连续的内存空间来&lt;strong>存储数据&lt;/strong>&lt;/p>
&lt;/li>
&lt;li>
&lt;p>链表的&lt;strong>插入&lt;/strong>和&lt;strong>删除&lt;/strong>操作的复杂度为O(1)，只需要直到目标位置元素的&lt;strong>上一个元素&lt;/strong>即可。但是，在&lt;strong>查找一个节点&lt;/strong>或者&lt;strong>访问特定位置&lt;/strong>的节点的时候复杂度为&lt;strong>O(n)&lt;/strong>&lt;/p>
&lt;/li>
&lt;li>
&lt;p>使用链表结构可以&lt;strong>克服数组需要预先知道数据大小&lt;/strong>的缺点，链表结构可以充分利用&lt;strong>计算机内存空间&lt;/strong>，实现灵活的&lt;strong>内存动态管理&lt;/strong>&lt;/p>
&lt;blockquote class='book-hint '>
&lt;p>但链表&lt;strong>不会节省空间&lt;/strong>，相比于数组会&lt;strong>占用&lt;/strong>更多空间，因为链表中&lt;strong>每个节点&lt;/strong>存放的还有&lt;strong>指向其他节点&lt;/strong>的指针。除此之外，链表不具有&lt;strong>数组随机读取&lt;/strong>的优点&lt;/p>&lt;/blockquote>&lt;/li>
&lt;/ul>
&lt;h2 id="链表分类">链表分类&lt;a class="anchor" href="#%e9%93%be%e8%a1%a8%e5%88%86%e7%b1%bb">#&lt;/a>&lt;/h2>
&lt;p>&lt;strong>单链表&lt;/strong>、&lt;strong>双向链表&lt;/strong>、&lt;strong>循环链表&lt;/strong>、&lt;strong>双向循环链表&lt;/strong>&lt;/p>
&lt;blockquote class='book-hint '>
&lt;p>假设链表中有&lt;strong>n个元素&lt;/strong>&lt;br>
访问：O(n) //访问特地给位置的元素&lt;/p>
&lt;p>插入删除：O(1) //必须要知道插入元素的位置&lt;/p>&lt;/blockquote>&lt;h3 id="单链表">单链表&lt;a class="anchor" href="#%e5%8d%95%e9%93%be%e8%a1%a8">#&lt;/a>&lt;/h3>
&lt;ul>
&lt;li>&lt;strong>单链表&lt;/strong>只有一个方向，结点&lt;strong>只有一个后继指针next&lt;/strong>指向后面的节点。因此，链表这种数据结构通常在&lt;strong>物理内存&lt;/strong>上是&lt;strong>不连续&lt;/strong>的&lt;/li>
&lt;li>我们习惯性地把&lt;strong>第一个结点&lt;/strong>叫做&lt;strong>头结点&lt;/strong>，链表通常有一个&lt;strong>不保存任何值的head节点&lt;/strong>（头结点），通过头结点我们可以&lt;strong>遍历整个链表&lt;/strong>，尾结点通常&lt;strong>指向null&lt;/strong>&lt;/li>
&lt;li>如下图
&lt;img src="img/ly-20241212141850281.png" alt="ly-20241212141850281" />&lt;/li>
&lt;/ul>
&lt;h3 id="循环链表">循环链表&lt;a class="anchor" href="#%e5%be%aa%e7%8e%af%e9%93%be%e8%a1%a8">#&lt;/a>&lt;/h3>
&lt;ul>
&lt;li>循环链表是一种&lt;strong>特殊的单链表&lt;/strong>，和单链表不同的是&lt;strong>循环链表的尾结点&lt;/strong>不是指向null，而是&lt;strong>指向链表的头结点&lt;/strong>&lt;/li>
&lt;li>如图
&lt;img src="img/ly-20241212141850545.png" alt="ly-20241212141850545" />&lt;/li>
&lt;/ul>
&lt;h3 id="双向链表">双向链表&lt;a class="anchor" href="#%e5%8f%8c%e5%90%91%e9%93%be%e8%a1%a8">#&lt;/a>&lt;/h3>
&lt;ul>
&lt;li>双向链表包含&lt;strong>两个指针&lt;/strong>，一个&lt;strong>prev&lt;/strong>指向&lt;strong>前一个节点&lt;/strong>，另一个&lt;strong>next&lt;/strong>指向&lt;/li>
&lt;li>如图
&lt;img src="img/ly-20241212141850726.png" alt="ly-20241212141850726" />&lt;/li>
&lt;/ul>
&lt;h3 id="双向循环链表">双向循环链表&lt;a class="anchor" href="#%e5%8f%8c%e5%90%91%e5%be%aa%e7%8e%af%e9%93%be%e8%a1%a8">#&lt;/a>&lt;/h3>
&lt;p>双向循环链表的&lt;strong>最后一个节点的next&lt;/strong>指向head，而head的&lt;strong>prev&lt;/strong>指向最后一个节点，构成一个环&lt;/p>
&lt;p>&lt;img src="img/ly-20241212141850919.png" alt="ly-20241212141850919" />&lt;/p>
&lt;h2 id="应用场景">应用场景&lt;a class="anchor" href="#%e5%ba%94%e7%94%a8%e5%9c%ba%e6%99%af">#&lt;/a>&lt;/h2>
&lt;ul>
&lt;li>如果需要支持&lt;strong>随机访问&lt;/strong>的话，链表无法做到&lt;/li>
&lt;li>如果需要&lt;strong>存储的数据元素个数不确定&lt;/strong>，并且需要经常&lt;strong>添加&lt;/strong>和&lt;strong>删除&lt;/strong>数据的话，使用&lt;strong>链表&lt;/strong>比较合适&lt;/li>
&lt;li>如果需要&lt;strong>存储的数据元素&lt;/strong>的个数确定，并且不需要&lt;strong>经常添加&lt;/strong>和&lt;strong>删除&lt;/strong>数据的话，使用数组比较合适&lt;/li>
&lt;/ul>
&lt;h2 id="数组-vs-链表">数组 vs 链表&lt;a class="anchor" href="#%e6%95%b0%e7%bb%84-vs-%e9%93%be%e8%a1%a8">#&lt;/a>&lt;/h2>
&lt;ul>
&lt;li>数组支持&lt;strong>随机访问&lt;/strong>，链表不支持&lt;/li>
&lt;li>数组使用的是&lt;strong>连续内存空间&lt;/strong> &lt;strong>对CPU缓存机制&lt;/strong>友好，链表则&lt;strong>相反&lt;/strong>&lt;/li>
&lt;li>数组的&lt;strong>大小固定&lt;/strong>，而链表则&lt;strong>天然支持动态扩容&lt;/strong>。如果生命的数组过小，需要另外申请一个&lt;strong>更大的内存空间&lt;/strong>存放数组元素，然后将&lt;strong>原数组拷贝进去&lt;/strong>，这个操作比较耗时&lt;/li>
&lt;/ul>
&lt;h1 id="栈">栈&lt;a class="anchor" href="#%e6%a0%88">#&lt;/a>&lt;/h1>
&lt;h2 id="栈简介">栈简介&lt;a class="anchor" href="#%e6%a0%88%e7%ae%80%e4%bb%8b">#&lt;/a>&lt;/h2>
&lt;ul>
&lt;li>栈（stack）只允许在&lt;strong>有序的线性数据集合&lt;/strong>的&lt;strong>一端&lt;/strong>（称为栈顶top）进行&lt;strong>加入数据（push）&lt;strong>和&lt;/strong>移除数据（pop）&lt;/strong>。因而按照**后进先出（LIFO，Last In First Out）**的原理运作。&lt;/li>
&lt;li>栈中，&lt;strong>push&lt;/strong>和&lt;strong>pop&lt;/strong>的操作都发生在栈顶&lt;/li>
&lt;li>栈常用&lt;strong>一维数组&lt;/strong>或&lt;strong>链表&lt;/strong>来实现，用数组实现的叫&lt;strong>顺序栈&lt;/strong>，用链表实现的叫做&lt;strong>链式栈&lt;/strong>&lt;/li>
&lt;/ul>
&lt;blockquote class='book-hint '>
&lt;p>假设堆栈中有n个元素。
访问：O（n）//最坏情况
插入删除：O（1）//顶端插入和删除元素&lt;/p></description></item></channel></rss>