图的定义存储和遍历(一级)

图的定义存储和遍历(一级)_第1张图片

图的定义存储和遍历(一级)_第2张图片

图的定义存储和遍历(一级)_第3张图片

图的定义存储和遍历(一级)_第4张图片

图的定义存储和遍历(一级)_第5张图片

图的定义存储和遍历(一级)_第6张图片

图的定义存储和遍历(一级)_第7张图片

图的定义存储和遍历(一级)_第8张图片

图:是一种多对多的关系,图这一块我们不进行过多的说明

我们这里又一个高德地图搜索路径的截图,我们要搜索起点北京大学的总校区,重点是清华大学,我现在选择的是驾车而不是公交,

如果是公交可能有其他的路径,如果是火车可能是达到不了的,是不是一下子给我们提供了几条路径啊,3条路径,为什么有3条路径啊

它有不同的依据,比如说红绿灯最少的,避免频繁停车,拥堵较少的,可能某些路段比较堵,即使没有红绿灯也会有比较长的时间,

还有一个距离最短的,理论上距离短的话时间就会比较少,但是也不见得,这是我们见到的一个非常熟悉的功能,但是我们仔细想一下

后台的实现的话,我不由的想出3个问题,哪三个问题啊

第一个问题:高德地图有那么多的地址,那么多的线路,好复杂啊,那采用了什么数据结构?

第二个问题:有这么多的地点和线路,他在计算机里面是如何存储的,也就是存储的数据结构是什么?

第三个问题:高德地图已经把相关的信息保存起来了,那它是怎么从这么多信息里面找到我们相关的符合各种规则的路径的呢?

并且各种路径有不同的依据
要回答这三个问题


问题1:采用的数据结构叫什么,叫图,不是线性表,不是树,是图,图是一种多对多的网状的关系

问题2:那这些地点和线路是怎么存储的,那就涉及到图的存储结构,简单来说,两种结构,第一个,顺序结构,第二个,链式存储结构

问题3:怎么找到按照不同的标准提供的路径的呢,那有红绿灯少的那就有红绿灯多的,他肯定是通过比较最后找到红绿灯少的,

这就涉及到了一个最短路径的问题


学完了我们这一章之后呢,大家对这三个问题就明白了,我们这一章的讲解也是围绕这这三个问题来说的


先看第一个问题,他采用的是图的存储结构,那就是图的定义,最短路径,讲最短路径之前,我们先讲一下图的遍历,

现在图的定义,什么叫图?

简单来说这就是两张图呗,网状结构,各个节点代表什么含义,比如我们各个公交站,各个地铁站,各个城市,那连线代表什么含义,

表示他们之间是直接相通的,也就是我们这个图是由什么组成的,图是一种网状的数据结构,有顶点,还有描述顶点之间关系组成的

有无向图,也有有方向的,有什么区别吗,有方向的表示a可以到d,看这个箭头的方向,a是不是可以到d,d能到a吗,d直接到a是不可以的,

你要想到,deca,可以这么来到,那无向图是怎么回事,无向图是双向通的,其实还是有向的,都是想通的,既可以从a到d,也可以从d到a,

无向图实际上是有向图,是双向图,adbce我们称之为顶点吧,称之为图的顶点,那一个一个的边我们称之为弧或边,这是一个,明确一下




你看这个图好怪啊,这个图各个连线,都标了不同的数字,那这个数字有什么意义,这个意义可大了,比如这个A代表北京,B代表石家庄,

c代表沈阳,那先代表他们是想通的,那数字可以代表他们之间的距离,是可以代表距离的,或者是代表时间,因为一般时间和距离不一定成正比,

可能会拥堵,有一个有高速公路,有一个可能没有高速公路,一个有高铁,一个没有高铁,那距离长度有时候也不能说明问题,

可能也代表时间,这叫做加权图,3,4,7就成为这条边的权值,这个大家记住:

在实际应用中,图不但需要表示元素之间是否存在某种关系,而且要加一个与实际意义相关的值,那这个值我们称之为权,

代表距离啦,代表时间的消耗啦,这张图我们就称之为加权图,这个我们也能够理解,关于图的定义我们就给大家讲到这里
什么叫图,有向图和无向图,加权图,有顶点和很多的边来组成,这是图的定义,生活中有没有这样的案例,中国的交通网,地铁图,

都是网状结构,再往下看,这样的图在计算机里面到底该怎么存储呢,这实际上只是他的逻辑结构,那我们在计算机里面究竟该怎么

来存,两种方式吧

1. 邻接矩阵:就是二维数组,就相当于顺序结构,可以认为就是顺序结构的,我们来看一下是怎么来存的,先看一下无向图,顶点中间有边,

怎么办,我就一个二维的数组,不是有4个顶点吗,那就4行4列,你这个从a是不是能到b,那我就从a到b写个1呗,那你从b也能到a,那在这里

也写个1,从c能到d吗,从c到d无穷大∞,无穷大的,反过来从d到c有没有,没有,从d到c也是无穷大,有人说那从a到a呢,从b到b呢,

到他自己呢,我们也规定为无穷大,对象线上面的,我们也都给他写成无穷大,这么来表示,那你发现了没,如果用二维数组来表示图像图的话,

你发现这个二维数组有什么特点,它是关于这条对角线对称的,右上半部分和左下半部分是不是一样的,是一样的,这是一个无向图,

有向图一样,一共有4个顶点,从a能到b,有我们用1来表示,那从b能到a吗,不能,所以从b到a我们就认为无穷大∞,从c能不能到d,

从c到d无穷大,从d到c,也是无穷大,从d到a呢,从a到d也是可以的,同样对角线上的还都是无穷大∞,自己到自己我们认为是不可达的,

这是我们所说的有向图,有向图关于这条对角线对称吗,不对称,因为他不是双向的,那我们就用邻接矩阵把这个图给表示了,

但是他这个时候有个缺点,他有个什么缺点,只要路径想通,就用1来表示,那我们从这个图我们能看到什么啊,我们只能看到这两个顶点

有没有路径,但是这两个路径多长花了多少时间,知道吗,不知道,什么时候知道了,那就要使用加权图了

加权图我们怎么来表示,我们还是以有向图来讲,a到b有没有路径,有路径,并且权值是3,a到b权值是3,b到a有没有,没有,

b到a那就是无穷大,c到d是5,d到e无穷大没有,但是反过来e到d是不是就有了,这个时候他就不是和上面一样都是1了,1只能表明有这种关联

这个不仅表示有关联,还表示关联的值,加权图我们这么来表示,这是我们使用邻接矩阵来表示的



2. 邻接表:就是链表,链式存储结构,还有一种就是我们采用链式存储结构呗,叫链表,我们看他该怎么表示,基本上主体结构是一个数组,

每个数组后面引一个链表,首先告诉我他又几个节点,几个顶点,4个,那好,那我整个数组的长度是几,是4,abcd存的编号分别是0123,

这是不是代表着数组的索引,这只能说明我有4个顶点,能说明他们呢顶点之间的关系吗,说明不了,怎么才可以说明可以和b相连,可以

可以和c相连,也可以和d相连,怎么办呢,我们这么来做,a和c相连,还带权值,就在a的后面引入一个链表,第一个节点1代表什么含义,

1是b的索引,e1是权值,告诉我这个2是什么含义,为什么这里写个2,是不是c的索引,e2是a到c的权值,3是d,a和d也是相连的,

e3是什么意思,e3是这条边的权值,后面没有了,与a相连的有三个,他们的索引分别是1,2,3,我想知道c有几个顶点相连,c只有0,

0就是a呗,0代表a,e2就是权值,这是我们所说的链式存储结构,那下面这个图又有什么区别

上面是无向的,下面是有向的,5个顶点怎么办,有一个数组,这个主结构是一个数组,是不是5个元素,从0一直到4,目前我们可以看到,

c可以到1,1是b,权值是e3,然后c还可以到d,d是3,权值是4,而我们只能见到存储结构的,这是我们所讲的图的存储结构,

主要是这两种方式,那种方式用的比较多,还是链式的用的比较多,这是我们所说的一个内容,有人说数组会占用更多的空间,

我们不仅要考虑谁占的空间多,谁占的空间少,还要考虑后续哪个操作简单,哪个复杂,这就是我们所说的图的存储结构,

我们掌握到这个程度就可以了
我们再来看一下图的遍历,图的遍历是怎么回事啊,我们学过树的遍历了,有线性遍历,有树的遍历,先序遍历,中序遍历,后序遍历

按层次遍历,这一块我们已经把它们掌握了,什么叫图的遍历,这概念和树是差不多的,从图的某个顶点出发,按照某种方法

对图中所有的节点访问且仅访问一次,我们遍历就是把所有的节点走一遍,是后面很多算法的一个基础,比如我们后面的关键路径,

拓扑排序,连通性,这都是图后面相关的一些问题,他们都是建立在图的遍历基础上的,首先我要把每个顶点走一遍,我在走一遍的

过程中要做哪些事情,这个大家要知道,图的遍历没有先根,没有后根,没有中根,为什么,因为对于图来说他有没有根啊,它是没有根的,

深度优先遍历,和广度优先遍历,他又这么两种遍历方式,缩写是DFS和BFS,告诉我FS是什么含义,FS是first search优先遍历,

B是breadth广度,D是depth深度,是不是有相应的单词,这个大家记住了,深度优先遍历记住,类似于树的先根遍历,大家想一下,对于树

的先根遍历,我们有几种方式来实现,算法的实现,一种是递归的,一种是非递归的,非递归的我们要应用栈,对于图的深度优先遍历

可以采用递归的方式或者采用栈的非递归的方式来实现,当然他比树的遍历要复杂了,别的不说,首先存储就复杂了,存储就比树要复杂

广度优先遍历,相当于树的层次遍历,按照层次遍历,那你好好想一下,树的层次遍历是怎么来实现的,有没有递归的方式,树的层次遍历

有没有递归的,没有,是借入队列的方式实现的,我们同样图也是,借助队列的非递归方式来实现

下面我给大家走一下过程,我们对于这个图来说,对它进行深度遍历,举个列子来说,这是北京,这是石家庄,这是天津,这是沈阳,

这是郑州,这是武汉,这是长沙,比如我从北京开始,所有的城市都走一遍,怎么走啊,这是不是相当于网状结构啊,铁路是不是连接到一起了,

那我这个时候该怎么走啊,两种方式,第一种方式一条道走到黑,北京-石家庄-郑州-武汉-长沙-广州,一条路下来的,这叫什么,

这叫深度优先遍历,一直找下一个,一直找下一个,是这么来的,相当于先根遍历,最左边的一直往下走,就是这么来的,那你觉得广度优先遍历

是怎么回事啊,我要是如果从北京开始的话,我先访问广度,不是深度,先要访问彼此相邻的城市,谁和他相邻,石家庄,天津,

沈阳,你这儿不是还有济南,这边还有上海,先访问北京相邻的这些,然后访问石家庄相连的,访问天津相连的,访问沈阳相连的,

一级一级来访问,按照远近来访问,这相当于广度优先遍历,不就是按层次吗,那么我们下面来看了,我们给大家准备了三个例子

我就不信大家学不会,我讲了第一个之后第二个要大家自己来写,包括第三个你自己能写出来,先看第一个,目前我们画的图都是无向图的



从0开始,第一个是0,深度优先,一条路往下走,是不是可以走1,也可以走2啊,你总要写一个吧,那我们就写那个数小的吧,

选1就可以了,1怎么办,继续往下,是不是有3也有4,那我们就先写这个3吧,写了3之后怎么办,你的下一步只能是7了,一条路往下走,

然后再往下走,走谁啊,走4,再往下走,1,遍历的时候会进行标记的,1访问过了,访问过了怎么办,这个过程是递归的,或者你利用栈的,

当你访问到4的话,1已经访问过了,一步一步的往回退,先退到7这儿,然后退到3这儿,再退到1这儿,再退到0这儿,因为一路退回来没有

别的顶点,如果我们7这个要是有个顶点,你看先4退到7,就会先访问这个顶点,再往后退,再往后退,没有顶点,这棵树走完,再往后退,

又退到这儿,还有顶点吗,有,你发现这条道走完了,是不是还有另外一条路啊,这好比是从北京到石家庄,郑州武汉到广州了,

到点要回来一趟,把这些城市访问一遍,再开始另外一条路线,从这儿开始再走2,2下面一直往下走,5,然后是多少啊,6,看是不是和

我们下面的结果一样:01374256

这是一个,这是我们说的深度优先遍历,我们下面还有两个例子,广度优先该怎么办,就像我们树的遍历一样,他要借助一个队列来实现,

先把0放到队列里面,然后谁先出去啊,0先出去,0出去之后把它两个直接相连的1和2放到这儿,这些相连的放到这儿,然后让1再出去,

1出去之后再做一件事,与1相邻的3放到这,4也放到这儿,下一个怎么办,让2出去,2出去的话,与2相连的,5和6,放到这儿,然后3再出去,

3出去了,与3相连的,这里有个7,4出去,与4相连的有个7,是不是有个7,那我们这里再放个7,或者我们这里不放7,7可以做个标记,

已经放进去了,这都是算法里面可以来变通的,可以有这些变化的,然后5再出来,5有没有孩子,有没有下一个,这是不是有6啊,

6已经放进来了,可以做一下标记,6再出来,还有2,2已经进去过,最后还有7,还有4,还有3,那都已经标记过了,按照这个方式,

01234567,相当于我们如果把它看成一棵树的话,先第一层,再第二层,再第三层,再第四层,就按照这种方式来访问就可以了,

记住这个队列就可以很轻松的搞定了
我们再来看一个,我们看下面这个,告诉我这个图比上面这个图要复杂一下了,我们首先进行深度优先遍历,下面的结果先不要看,

这是深度优先的一个过程,这是广度优先的一个过程,我们从A开始,首先是A,深度优先啊,先是A,然后有B有C,我们总要写一个呗,

我们就选B,然后选E,然后选F,然后再选一个C,注意下面该怎么办,就往后退了,正好退的时候比较简单,是不是没有其它顶点,

有的话要顺便访问以下,递归遍历,B又退回来了,下一次该怎么办了,D,D怎么办,G,有两个,一个是I,一个是H,我们该访问H,

访问小的呗再访问D了,D访问过了怎么办,往后退,退到G了,还有一个呢,I,把这个I再访问一下,访问I怎么办,继续往后退,

退到最后退这个根,是不是都解决了,abefcdghi,没有问题,还有不清楚的按照这个顺序这个步骤来看就可以了,


广度优先该怎么办,一般使用队列来实现的,借助一个队列来实现的,怎么办,先放谁,先放A,B,C,D,对于B来说有E,

对于C来说有F,对于G来说有H,对于G来说有I,abcdefghi,这是我们讲的广度优先的一个案例,那就给大家讲到这儿了,



把这个图的深度优先和广度优先的写出来,我们继续来看图像图的深度优先和广度优先的遍历,这是我们的第三个例子,

这次听懂,前两个回头一看就知道了,现在讲深度优先,从A开始,有3个路径,B,C,D都可以,选一个呗,选B吧,

选B的话怎么办,选B的话又相连了,有E有C,最后只能走F了,下回在走D,然后怎么办,是不是绕了一圈绕道主目录里面去了

然后怎么办,往后退,F还有一段,是H,然后走I,下边该怎么办了,从I开始退,退到H,再退到F,再退到C,再退到B,

还有一套路径呢,E和G,这是一个哦,明确了,和我们的结果一样吗,一样的,那我们再来看一个

广度优先不是问题吧,广度优先怎么办,你就画一个队列,先是A,然后就是B,C,D,先找直接相邻的,下边该谁了,

跟B相邻的,E,和C相邻的,F,与D相连的,不是F吗,BCD相连的都说了,跟E相连的G,根F相连的H,下边该怎么办了,

跟G相连的没有,跟H相连的,I,ABCDEFJHI,就是他了,这是我们说的一个遍历,A拥有三个相邻的,

不管是广度还是深度优先,里面选B,还是选C,到底是选D,我们现在说选个小的,那实际中它是怎么来的,实际中它是这么来的

比如说你要采用链式存储结构,你要找A相连的节点,他先找第一个,这个结构大家确定了,与a相邻的节点,是访问a,还是访问b,

还是访问d,表里面如果两个节点交换一下顺序,他的顺序就变了,它是按照这个顺序来就可以了,这是我们讲的关于图的相关内容,

图的定义,图的存储,还有图的遍历,给了一些广度深度一些算法,并且举了三个例子,深度优先遍历相当于先根遍历

如果我们要用代码来实现的话,可以采用递归,也可以采用借助栈的方式,广度遍历类似于树的层次遍历,我们要借助队列的非递归方式

 

你可能感兴趣的:(遍历)