
<p id="353AKPSQ">书接上回,我们继续来聊聊图的遍历与实现。</p><p class="f_center"><img src="https://nimg.ws.126.net/?url=http%3A%2F%2Fdingyue.ws.126.net%2F2024%2F1104%2F60a2665ej00smduex001bd000j400n9p.jpg&thumbnail=660x&quality=80&type=jpg"/><br/><br/></p><p><h5>01、遍历</h5></p><p id="353AKPSS">在图的基本功能中有个很重要的功能——遍历,遍历顾名思义就是把图上所有的点都访问一遍,具体来说就是从一个连通的图中某一个点出发,沿着边访问所有的点,并且每个点只能访问一遍。</p><p id="353AKPST">下面我们介绍两种常见的遍历方式:深度优先遍历(DFS)和广度优先遍历(BFS)。</p><p><h5>1、深度优先遍历</h5></p><p id="353AKPSU">如果我们把边当作路,深度优先遍历就是路一直往下走,直到没路了再返回走其他路。其实有点像树的先序遍历从根节点沿着子节点一直向下直到叶子节点再调头。</p><p id="353AKPSV">下面我们梳理一下深度优先遍历大致分为以下几个步骤:</p><p id="353AKPT0">(1)从图中任意一个点A出发,并访问点;</p><p id="353AKPT1">(2)找出点A的第一个未被访问的邻接点,并访问该点;</p><p id="353AKPT2">(3)以该点为新的点,重复步骤(2),直至新的邻接点没有未被访问的邻接点;</p><p id="353AKPT3">(4)返回前一个点并依次访问前一个点为未被访问的其他邻接点,并访问该点;</p><p id="353AKPT4">(5)重复步骤(3)和(4),直至所有点都被访问过;</p><p class="f_center"><img src="https://nimg.ws.126.net/?url=http%3A%2F%2Fdingyue.ws.126.net%2F2024%2F1104%2Ff194ccd6j00smduey002ed000xu00wwp.jpg&thumbnail=660x&quality=80&type=jpg"/><br/><br/></p><p id="353AKPT6">如上图演示了从点A出发进行深度优先遍历过程,其中红色虚线表示前进路线,蓝色虚线表示回退路线。最后输出:A->B->E->F->C->G->D。</p><p><h5>2、广度优先遍历</h5></p><p id="353AKPT7">如果说深度优先遍历是找到一条路一直走到底,那么广度优先遍历就是先把所有的路走一步再说。其实有点像树的层次遍历从根节点出发先遍历其子节点然后再遍历其孙子节点直至遍历完所有节点。</p><p id="353AKPT8">下面我们梳理一下广度优先遍历大致分为以下几个步骤:</p><p id="353AKPT9">(1)从图中任意一点A出发,并访问点A;</p><p id="353AKPTA">(2)依次访问点A所有未被访问的邻接点,访问完邻接点后,然后按邻接点顺序把邻接点作为新的出发执行步骤(1);</p><p id="353AKPTB">(3)重复步骤(1)和(2)直至所有点都被访问到。</p><p class="f_center"><img src="https://nimg.ws.126.net/?url=http%3A%2F%2Fdingyue.ws.126.net%2F2024%2F1104%2Fab7cda61j00smdue9001yd000xg00wwp.jpg&thumbnail=660x&quality=80&type=jpg"/><br/><br/></p><p id="353AKPTD">如上图演示了从点A出发进行广度优先遍历过程,其中红色虚线表示前进路线。最后输出:A->B->C->D->E->F->G。</p><p><h5>02、实现(邻接矩阵)</h5></p><p id="353AKPTE">下面我们就以邻接矩阵的存储方式实现一个无向图。</p><p><h5>1、定义</h5></p><p id="353AKPTF">根据图的定义,我们需要定义点集合、边集合两个私有变量用于存储核心数据,为了操作访问我们再定义点数量和边数量两个私有变量,代码如下:</p><p class="f_center"><img src="https://nimg.ws.126.net/?url=http%3A%2F%2Fdingyue.ws.126.net%2F2024%2F1104%2F18de3240j00smdueb003fd0011s00lup.jpg&thumbnail=660x&quality=80&type=jpg"/><br/><br/></p><p><h5>2、初始化 Init</h5></p><p id="353AKPTH">此方法主要是初始化上面定义的私有变量,同时确定点集合大小,具体代码如下:</p><p class="f_center"><img src="https://nimg.ws.126.net/?url=http%3A%2F%2Fdingyue.ws.126.net%2F2024%2F1104%2Faaa46611j00smduec004cd0011s00nwp.jpg&thumbnail=660x&quality=80&type=jpg"/><br/><br/></p><p><h5>3、获取点数量 VertexCount</h5></p><p id="353AKPTJ">我们可以通过点数量私有变量快速获取图的点数量,代码如下:</p><p class="f_center"><img src="https://nimg.ws.126.net/?url=http%3A%2F%2Fdingyue.ws.126.net%2F2024%2F1104%2Fb18932cfj00smduee0027d0011s00iqp.jpg&thumbnail=660x&quality=80&type=jpg"/><br/><br/></p><p><h5>4、获取边数量 EdgeCount</h5></p><p id="353AKPTL">我们可以通过边数量私有变量快速获取图的点数量,代码如下:</p><p class="f_center"><img src="https://nimg.ws.126.net/?url=http%3A%2F%2Fdingyue.ws.126.net%2F2024%2F1104%2F0d8f1636j00smduef0027d0011s00iqp.jpg&thumbnail=660x&quality=80&type=jpg"/><br/><br/></p><p><h5>5、获取点索引 GetVertexIndex</h5></p><p id="353AKPTN">该方法是通过点元素获取其索引值,具体代码如下:</p><p class="f_center"><img src="https://nimg.ws.126.net/?url=http%3A%2F%2Fdingyue.ws.126.net%2F2024%2F1104%2Fc510de23j00smdueh0032d0011s00lup.jpg&thumbnail=660x&quality=80&type=jpg"/><br/><br/></p><p><h5>6、获取点元素 GetVertexByIndex</h5></p><p id="353AKPTP">该方法通过点索引获取点元素,具体代码如下:</p><p class="f_center"><img src="https://nimg.ws.126.net/?url=http%3A%2F%2Fdingyue.ws.126.net%2F2024%2F1104%2Ff4fb9589j00smduej003qd0011s00lup.jpg&thumbnail=660x&quality=80&type=jpg"/><br/><br/></p><p><h5>7、插入点 InsertVertex</h5></p><p id="353AKPTR">插入点元素时,我们需要先通过点元素获取其索引,如果索引已存在或者点集合已经满了则直接返回,否则添加点元素同时更新点数量,具体代码如下:</p><p class="f_center"><img src="https://nimg.ws.126.net/?url=http%3A%2F%2Fdingyue.ws.126.net%2F2024%2F1104%2Fbb37c3eaj00smduek004pd0011s00v4p.jpg&thumbnail=660x&quality=80&type=jpg"/><br/><br/></p><p><h5>8、插入边 InsertEdge</h5></p><p id="353AKPTT">插入边时可以同时指定边的权值。我们首先需要把两个点元素转换为点索引,同时验证索引,验证不通过则直接返回。否则开始添加边,因为无向图的特性,所以需要添加两点索引相反的边。同时更新边数量,具体代码如下:</p><p class="f_center"><img src="https://nimg.ws.126.net/?url=http%3A%2F%2Fdingyue.ws.126.net%2F2024%2F1104%2Ffdaf296dj00smduen006yd0011s011cp.jpg&thumbnail=660x&quality=80&type=jpg"/><br/><br/></p><p><h5>9、获取边权值 GetWeight</h5></p><p id="353AKPTV">该方法可以获取边的权值,权值可以根据需要在插入边方法中设置,需要对输入的点进行验证,如果点不存在则报错,具体代码如下:</p><p class="f_center"><img src="https://nimg.ws.126.net/?url=http%3A%2F%2Fdingyue.ws.126.net%2F2024%2F1104%2Fj00smduep006wd0011s00y8p.jpg&thumbnail=660x&quality=80&type=jpg"/><br/><br/></p><p><h5>10、深度优先遍历 DFS</h5></p><p id="353AKPU1">深度优先遍历正常有两种实现方法,一种是使用递归调用,一种是使用栈结构实现,下面我们使用递归的方式来实现。</p><p id="353AKPU2">因为我们需要保证每个点只会被访问一次,因此需要定义一个数组用来记录元素已经被访问过。我们这里是以无向图为例,因为无向图的对称性,索引我们选用一维数组即可满足记录被访问元素,而如果是有向图我们则需要使用二维数组记录被访问元素。</p><p id="353AKPU3">具体代码如下:</p><p class="f_center"><img src="https://nimg.ws.126.net/?url=http%3A%2F%2Fdingyue.ws.126.net%2F2024%2F1104%2F23c48fdbj00smduer00a7d0011s01esp.jpg&thumbnail=660x&quality=80&type=jpg"/><br/><br/></p><p><h5>11、广度优先遍历 BFS</h5></p><p id="353AKPU5">广度优先遍历可以借助队列来实现。首先把起始点添加入队列,然后把点出队列,同时把该点的所有邻接点添加入队列,循环往复,一直到把所有元素处理完为止。</p><p class="f_center"><img src="https://nimg.ws.126.net/?url=http%3A%2F%2Fdingyue.ws.126.net%2F2024%2F1104%2F0d4ea1bdj00smduev00bud0011s01n2p.jpg&thumbnail=660x&quality=80&type=jpg"/><br/><br/></p><p id="353AKPU7"><strong>注</strong>:测试方法代码以及示例源码都已经上传至代码库,有兴趣的可以看看。https://gitee.com/hugogoos/Planner</p>
讯享网

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容,请联系我们,一经查实,本站将立刻删除。
如需转载请保留出处:https://51itzy.com/kjqy/177582.html