小奥的学习笔记

  • Home
  • Learning & Working
    • Speech Enhancement Notes
    • Programming language
    • Computer & DL
    • MOOC
  • Life
    • Life Time
    • Thinking & Comprehension
    • Volunteer
    • Plan
    • Travel
  • Footprints
  • GuestBook
  • About
    • About Me
    • 个人履历
    • 隐私策略
  1. 首页
  2. Study-notes
  3. Computer & DL
  4. Data Structure
  5. 正文

数据结构【浙江大学】(第7节)整理

2018年5月9日 1621点热度 0人点赞 0条评论

第七节:最短路径问题

7.1 概述

最短路径问题的抽象:

在网络中,求两个不同顶点之间的所有路径中,边的权值之和最小的那一条路径。这条路径就是两点之间的最短路径。第一个顶点称为源点,最后一个顶点为终点。

问题分类:

(1)单源最短路径问题:从某固定源点触发,求其到所有其他顶点的最短路径。又分为(有无向)有权图和(有无向)无权图两种。

(2)多源最短路径问题:求任意两顶点间的最短路径。

7.2 无权图的单源最短路

按照递增(非递减)的顺序找出到各个顶点的最短路。例如图1:

 1.jpg

图1

我们以v3作为源点,与v3距离为0的点为v3;与v3距离为1的点为v1和v6;与v3距离为2的点(也就是距离v1为1,距离v6为1)的点为v2和v4;距离v3距离为3的点(也就是距离v2为1,距离v4为1)的点为v5和v7。至此,距离各点距离v3都已经清楚。

这个算法类似于BFS算法。但是与BFS不同的是,我们不需要定义一个已经访问的变量,需要重新定义一个数组为

(1)dist[W]=S到W的最短距离。初始情况下,默认距离可以为-1、负无穷或者正无穷。

(2)dist[S]=0

(3)path[W]=S到W的路上经过的某顶点。

代码如下:

void Unweighted(Vertex S)
{
       Enqueue(S,Q);
       while(!IsEmpty(Q)){
              V = Dequeue(Q);
              for(V的每个邻接点W)
                     if(dist[W]==-1){
                            dist[W]=dist[V]+1;
                            path[W]=V;
                            Enqueue(W,Q);
                     }
       }
}

path这个数组的作用就是记录从S到W路径中所经过的点,这个算法就是利用刚刚讲的那个每次基于前面那个点加1来得到下面一个点的这个方法。

时间复杂度为T=O(|V|+|E|)。看这个代码中while的部分,由于它都Dequeue和Enqueue了一次,所以总的次数为2V;又由于for循环遍历了V的每个邻接点W,个数为E,所以时间复杂度是O(|V|+|E|)。

7.3 无权图的单源最短路示例

这里,我们以图1中的图来做示例,仍将v3看做是源点,因此,dist和path做以下初始化:

下标W

1

2

3

4

5

6

7

dist

-1

-1

0

-1

-1

-1

-1

path

-1

-1

-1

-1

-1

-1

-1

调用Unweighted(3),然后将v3入队列。然后while循环,判断队列不为空,让v3出队列给V。然后开始for循环,对于V(即v3)的每个邻接点W,如果这个点没有访问过(即该点的dist[W]==-1),则将该点的dist赋值为前一点的dist+1(刚开始的时候前一点的dist为0),然后把前一点(刚开始是v3)赋值给path的第w个值,然后把下一个点压入队列。然后把v1压出,开始for循环,对于V(即v1)的每个邻接点,再进行上面的操作,如此循环直到最后。到最后的时候,dist和path数值为:

下标W

1

2

3

4

5

6

7

dist

1

2

0

2

3

1

3

path

3

1

-1

1

2

3

4

具体代码:

/* 邻接表存储 - 无权图的单源最短路算法 */
 
/* dist[]和path[]全部初始化为-1 */
void Unweighted ( LGraph Graph, int dist[], int path[], Vertex S )
{
    Queue Q;
    Vertex V;
    PtrToAdjVNode W;
    
    Q = CreateQueue( Graph->Nv ); /* 创建空队列, MaxSize为外部定义的常数 */
    dist[S] = 0; /* 初始化源点 */
    AddQ (Q, S);
 
    while( !IsEmpty(Q) ){
        V = DeleteQ(Q);
        for ( W=Graph->G[V].FirstEdge; W; W=W->Next ) /* 对V的每个邻接点W->AdjV */
            if ( dist[W->AdjV]==-1 ) { /* 若W->AdjV未被访问过 */
                dist[W->AdjV] = dist[V]+1; /* W->AdjV到S的距离更新 */
                path[W->AdjV] = V; /* 将V记录在S到W->AdjV的路径上 */
                AddQ(Q, W->AdjV);
            }
    } /* while结束*/
}

7.4 有权图的单源最短路

仍然是按照递增的顺序找出到各个顶点的最短路。解决这个问题的经典算法就是:Dijkstra算法。

(1)Dijkstra算法

①令S={源点s+已经确定了最短路径的顶点vi}

②对任一未收录的顶点v,定义dist[v]为s到v的最短路径长度,但该路径仅经过S中的顶点,即路径{s->(vi∈S)->v}的最小长度。

若路径是按照递增(非递减)的顺序生成的,则:

真正的最短路径必须只经过s中的顶点;

每次从未收录的顶点中选一个dist最小的收录(贪心算法)

增加一个v进入S,可能影响另外一个w的dist值(若使w的dist值缩小,则v必定在s到w的路径上,并且v到w有一条边),dist[w]=min{dist[w],dist[v]+<v,w>的权重}。代码如下:

void Dijkstra(Vertex s)
{
       while(1){
              V=未收录顶点中dist最小者;
              if(这样的V不存在)
                     break;
              collected[V] = true;
              for(V的每个邻接点W)
              if(collected[W] == false)
                     if(dist[V]+E<k,w> < dist[W])
                     {
                            dist[W] = dist[V] +E<v,w>;
                            path[W] =V;
                     }
       }
}

注意:该算法不能解决有负边的情况。

若只看这段伪码,我们无法判断其复杂度,这主要是因为未收录顶点中dist最小者的这个算法的复杂度我们无法判断。这个算法有以下几种:

①直接扫描所有未收录顶点-O(|V|),则T=O(|V|2+|E|)。对稠密图效果好。

②将dist存在最小堆中-O(log|V|)。更新dist[w]的值-O(log|V|)。总体复杂度为T=O(|V|log|V|+|E|log|V|)=O(|E|log|V|)。对稀疏图效果好。

7.5 有权图的单源最短路示例

图如图2所示。

2.jpg 

图2

这里我们以v1位源点。dist和path初始化结果如下所示:

下标W

1

2

3

4

5

6

7

dist

0

2

无穷

1

无穷

无穷

无穷

path

-1

1

-1

1

-1

-1

-1

当首先访问v4的时候,结果如下

下标W

1

2

3

4

5

6

7

dist

0

2

3

1

3

9

5

path

-1

1

4

1

4

4

4

然后看v2,由于v4已经访问过了,因此接下来看v5,由于到v5的距离为12,大于前面的距离,因此跳出循环。由于v2的邻接点只有v4和和v5,因此跳出v2。

接下来看v3和v5距离一样,那么就先看v3。v3的邻接点有v1和v6,v1已经被访问过,所以无视,直接看v6,此时可以看出v3到v6距离为5,所以总距离为8,小于原来的9。因此更新dis[6]=9,path[6]=3。然后看v5,v5只有一个邻接点,就是v7,这样经过v5到v7的距离为9,大于原来的距离,不更新。

在v6和v7中,v7的距离更短一点,所以先看v7。v7的邻接点只有v6。若经过v7访问v6的距离为6,小于原来的8,更新dis[6]=6,path[6]=7。

由于v6没有任何邻接点,所以v6直接不做判断。最后更新的结果如下:

下标W

1

2

3

4

5

6

7

dist

0

2

3

1

3

6

5

path

-1

1

4

1

4

7

4

 

7.6 多源最短路算法

方法1:直接将单源最短路算法调用|V|遍,T=O(|V|3+|E|×|V|),适合稀疏图。

方法2:Floyd算法,复杂度T=O(|V|3),更适合稠密图。

(1)Floyd算法

①Dk[i][j]=路径{i->{l<=k}->j}的最小长度。

②D0,D1,…,D[V]-1[i][j]即给出了i到j的真正最短距离。

③最初的D-1是带权的邻接矩阵,对角元素是0。

④若i和j之间没有直接的边,D[i][j]定义为正无穷。

⑤当Dk-1已经完成,递推到Dk时:

或者k∉最短路径{i->{l<=k}->j},则Dk=Dk-1;

或者k∈{i->{l<=k}->j},则该路径必定由两段最短距离组成:Dk [i][j]= Dk-1[i][k]+ Dk-1[k][j]。

源代码为:

void Floyd()
{
       for(i=0;i<N;i++)
              for(j=0lj<N;j++){
                     D[i][j]=G[i][j];
                     path[i][j]=-1;
              }
              for(k=0;k<N;k++)
                     for(i=0;i<N;i++)
                            if(D[i][k]+D[k][j]<D[i][j])
                            {
                                   D[i][j]=D[i][k]+D[k][j];
                                   path[i][j]=k;
                            }
}

本作品采用 知识共享署名 4.0 国际许可协议 进行许可
标签: 数据结构
最后更新:2018年5月9日

yszhang

这个人很懒,什么都没留下

打赏 点赞
< 上一篇
下一篇 >

文章评论

razz evil exclaim smile redface biggrin eek confused idea lol mad twisted rolleyes wink cool arrow neutral cry mrgreen drooling persevering
取消回复

搜索
欢迎关注我的个人公众号
最新 热点 随机
最新 热点 随机
DEEPFILTERNET:一种基于深度滤波的全频带音频低复杂度语音增强框架 奥地利匈牙利九日游旅程 论文阅读之Study of the General Kalman Filter for Echo Cancellation 小奥看房之鸿荣源珈誉府 杭州往返旅途及西溪喜来登和万怡的体验报告 2022年的第一篇碎碎念
奥地利匈牙利九日游旅程论文阅读之Study of the General Kalman Filter for Echo CancellationDEEPFILTERNET:一种基于深度滤波的全频带音频低复杂度语音增强框架
计算机组成原理笔记第五章(5.6) 2011年高考莱芜一中再创佳绩 WordPress将文章同步到新浪微博的几种方法(三种) 语音信号处理笔记(2) WP 嘀:嘀咕的 WordPress 插件 计算机组成原理笔记第五章(5.1~5.4)
标签聚合
学习 linux 算法 生活 Java 鸟哥的linux私房菜 Python python学习 leetcode 高中
最近评论
davidcheung 发布于 6 个月前(02月09日) The problem has been fixed. May I ask if you can s...
tk88 发布于 6 个月前(02月07日) Hmm is anyone else having problems with the pictur...
cuicui 发布于 10 个月前(10月20日) :wink:
niming 发布于 11 个月前(09月19日) 同级校友,能刷到太巧了
davidcheung 发布于 2 年前(08月16日) 我得找一下我之前整理的word文档看一下,如果找到了我就更新一下这篇文章。
Nolan 发布于 2 年前(07月25日) 您的笔记非常有帮助。贴图不显示了,可以更新一下吗?
davidcheung 发布于 3 年前(06月19日) 到没有看webrtc的代码。现在主要在看我们公司的代码了。。。只是偶尔看一看webrtc的东西。。。
aobai 发布于 3 年前(03月13日) gain_change_hangover_ 应该是每三个block 只能够调整一次,这样保证每帧...
匿名 发布于 5 年前(12月30日) 烫
小奥 发布于 5 年前(12月12日) webRTC里面的NS本身我记得就是在C++里面呀

COPYRIGHT © 2025 小奥的学习笔记. ALL RIGHTS RESERVED.

Theme Kratos Made By Seaton Jiang

陕ICP备19003234号-1

鲁公网安备37120202000100号