第四章    图
This presentation is the property of its rightful owner.
Sponsored Links
1 / 119

第四章 图 PowerPoint PPT Presentation


  • 67 Views
  • Uploaded on
  • Presentation posted in: General

第四章 图. 主讲老师:刘 震. $4.1 图 — 引子. 右图为一个新兴小镇 . 其中 6 个红色小块为社区房屋 , 2 个白色小块为商店 . 现在要铺设天然气管道 , 造价和天然气管长度成正比 . 如何铺设管道使得所有房屋和商店都通气且造价最低 ?. $4.1 图 — 引子. 问题 1: 造价和管线长度成正比 , 如何表示管线长度 ?. $4.1 图 — 引子. 问题 2: 如何以最少连线连通所有房屋和商店 ? 问题 3: 如何连通所有房屋和商店且造价最低 ?. $4.1 图 — 引子.

Download Presentation

第四章 图

An Image/Link below is provided (as is) to download presentation

Download Policy: Content on the Website is provided to you AS IS for your information and personal use and may not be sold / licensed / shared on other websites without getting consent from its author.While downloading, if for some reason you are not able to download a presentation, the publisher may have deleted the file from their server.


- - - - - - - - - - - - - - - - - - - - - - - - - - E N D - - - - - - - - - - - - - - - - - - - - - - - - - -

Presentation Transcript


4621563

第四章 图

主讲老师:刘 震


4621563

$4.1 图—引子

右图为一个新兴小镇.其中6个红色小块为社区房屋, 2个白色小块为商店. 现在要铺设天然气管道, 造价和天然气管长度成正比. 如何铺设管道使得所有房屋和商店都通气且造价最低?


4621563

$4.1 图—引子

  • 问题1: 造价和管线长度成正比,如何表示管线长度?


4621563

$4.1 图—引子

  • 问题2: 如何以最少连线连通所有房屋和商店?

  • 问题3: 如何连通所有房屋和商店且造价最低?


4621563

$4.1 图—引子

  • 问题4: 如何用计算机技术解决现实中大量社区的最优化管道铺设问题?


4621563

$4.1 图—引子

  • 思路

    • 现实问题图形化: 社区(房屋,商店)为点, 连通的点之间用线表示,点之间距离(管线长度)用权值表示,得到一个有权图

    • 计算机存储图形数据: 存储点,线,权值

    • 最优管线问题分析: 求连通图的最小权值和

    • 解决算法思路: ?


4621563

$4.1 图—引子

  • 深入思考:

    • 有哪些解决方案? 哪个方案更优? 如何分析算法优劣?

    • 这种解决方案还可以解决哪种类型的实际问题?


4621563

$4.1 图—图的基本概念

  • 图是常用的重要的一类数据结构,上一章的树可以看成是图的特例,树中每个数据元素至多允许一个前驱,只能反映数据元素之间一对多的关系,而图中没有该限制,允许数据元素可以有多个前驱,因此可以反映数据元素之间多对多的关系。


4 1 1

$4.1 图—图的基本概念1

  • 有向图

  • 无向图


4 1 11

G1

$4.1 图—图的基本概念1

  • 有向图

    • G=(V,{A}) 其中,V为顶点的有穷非空集合 {A}为顶点之间的关系集合

G1=(V,{A})

V={v1, v2, v3, v4}

A={<v1, v2>, <v1, v3>, <v3, v4>, <v4, v1>}

其中<x, y>表示从x到y的一条弧(arc),A为弧集合,x为弧尾(tail),y为弧头(head)


4 1 12

G2

$4.1 图—图的基本概念1

  • 无向图

    • G=(V,{E}) 其中,V同有向图,{E}为顶点之间的关系集合,E为边集合

G2=(V,{A})

V={v1, v2, v3, v4, v5}

E={(v1, v2),(v1, v4),v2, v3),(v3, v4),(v2,v5),(v3,v5)}

其中,(x, y)表示x与y之间的一条连线,称为边(edge)


4 1 13

$4.1 图—图的基本概念1

  • 图的顶点数为n, 边数为e,请找出n与e的关系

设n为顶点数,e为边或弧的条数

对无向图有: 0<=e<=n(n-1)/2

有向图有: 0<=e<=n(n-1)


4 1 2

$4.1 图—图的基本概念2

完全图: 边达到最大的图

  • 无向完全图:边数为n(n-1)/2的无向图

  • 有向完全图:弧数为n(n-1)的有向图

  • 权:与图的边或弧相关的数

  • 网:边或弧上带有权值的图


4 1 3

$4.1 图—图的基本概念3

顶点的度 TD(V)

无向图:为依附于顶点V的边数

有向图:等于以顶点V为弧头的弧数(称为V的入度,记为ID(V))与以顶点V为弧尾的弧的出度,记为OD(V))之和。即:TD(V)=ID(V)+OD(V)

无向图的度数为依附于顶点v

的边数;有向图的度数等于以

顶点v 为弧头的弧数与以顶点v

为弧尾的弧数之和

结论:

  • 无向图 e= 1/2(∑TD(vi))

  • i=1

  • 有向图 n n

  • e= ∑ID(vi)=∑OD(vi)

  • i=1 i=1


4 1 4

$4.1 图—图的基本概念4-路径

无向图:顶点v到v’的路径是一个顶点序列(v=vi0, vi1, … , vim=v’)

其中,(vij-1,vij )∈E, 1<=j<=m

有向图: 顶点v 到v’的路径是有向的顶点序列(v=vi0, vi1, … , vim=v’)

其中,<vij-1,vij >∈A, 1<=j<=m

几个概念:

路径长度:路径上边或弧的数目

回路或环:首尾顶点相同的路径,称为回路或环。即:

(v=vi0, vi1, … , vim=v’=v)

简单路径:路径中不含相同顶点的路径

简单回路:除首尾顶点外,路径中不含相同顶点的回路


4 1 5

$4.1 图—图的基本概念5-连通

顶点连通:若顶点v到顶点v’有路径,则称顶点v与v’是连通的

连 通 图 :包括无向连通图和有向连通图

无向图:若图中任意两个顶点vi,vj都是连通的,则称该图是连通图(vi<>vj)

有向图:若图中任意两个顶点vi,vj,都存在从vi到vj和从vj到vi的路径,则称该有向图为强连通图(vi<>vj)

连通分量:

无向图:无向图中极大连通子图,称为连通分量

有向图:有向图中极大强连通子图,称为强连通分量


4 1 51

G1

$4.1 图—图的基本概念5-连通

G1有两个强连通分量


4 1 6

生成树

n-1条边

$4.1 图—图的基本概念6-生成树

定义:设无向图G是含有n个顶点的连通图, 则图G的生成树是含有n

个顶点,且只有n-1条边的连通子图

三要素: n个顶点

n-1条边

连通


4 1 7

$4.1 图—图的基本概念7-子图

子图是图的一部分,它本身也是一

个图。如果有图G=(V,E)和G′=(V′,E′),

且V′是V的子集,E′是E的子集,则称G′是G的子图。图4-1实际上是中国铁路交通图的一个子图。


4 1 8

$4.1 图—图的基本概念8-邻接顶点

邻接顶点在无向图中,若两个顶点之间有边连接,则这两个顶点互为邻接顶点


4621563

$4.2 图—图的存储

  • 回忆: 天然气管道铺设问题中, 需要存储社区房屋和商店信息,相互之间是否有通路及管道长度三个信息. 即使部分问题不牵涉管道长度(图的权值), 也至少需要存储图的顶点和边的两方面信息,如何存储?

仍然有顺序存储和链式存储2种方法!


4 2 1

$4.2 图—图的存储1-邻接矩阵

一、数组表示法(邻接矩阵)

设图G=(V,{E})有n个顶点,则G的邻接矩阵定义为n阶方阵A。

其中:

例如:G1、G2的邻接矩阵


4621563

  • n n

  • 无向图中:TD(Vi)=∑A[i,j]=∑A[j,i]

  • j=1 j=1

即顶点Vi的度等于邻接矩阵中第i行(或第i列)的元素之和(非0元素个数)。

  • 有向图中: TD(Vi)=OD(Vi)+ID(Vi)

  • n n

  • = ∑A[i,j]+∑A[j,i]

  • j=1 j=1

即顶点Vi的出度为邻接矩阵中第i行元素之和

顶点Vi的入度为邻接矩阵中第i列元素之和

邻接矩阵的特点:

1. 判定两个顶点Vi与Vj是否关联, 只需判A[i,j]是否为1;

2. 求顶点的度容易:


4 2 11

$4.2 图—图的存储1-邻接矩阵

如果G是带权图,wij是边(vi,vj)或<vi,vj>的权,则其邻接

矩阵定义为:


4 2 12

$4.2 图—图的存储1-邻接矩阵

  • 请采用邻接矩阵存储右图数据

答: 设G={‘房屋1’,’房屋2’,’房屋3’,’商场1’}

4个顶点,则邻接矩阵为


4 2 2

adjvex

nextarc

vexdata

firstarc

$4.2 图—图的存储2-邻接表

1. 无向图邻接表

对图中每个顶点Vi建立一个单链表,链表中的结点表示依附于顶点Vi的边,每个链表结点为两个域:

其中:邻接点域(adjvex)记载与顶点Vi邻接的顶点信息;

链域(nextarc)指向下一个与顶点Vi邻接的链表结点

每个链表附设一个头结点,头结点结构为:

其中:vexdata存放顶点信息(姓名、编号等);

fristarc指向链表的第一个结点。


4 2 21

3

2

1

4

3

4

5

3

1

1

2

3

4

5

2

2

5

3

G2

4

1

5

2

$4.2 图—图的存储2-邻接表

如图G2的邻接表为:

无向图邻接表特点:

1.n个顶点,e条边的无向图,需n个头结点和2e个链表结点

2.顶点Vi的度 TD(Vi)=链表i中的链表结点数


4 2 22

$4.2 图—图的存储2-邻接表

  • 请采用邻接表存储右图数据

答:


4 2 23

1

1

4

3

1

2

3

4

2

G1

2

3

4

$4.2 图—图的存储2-邻接表

2. 有向图邻接表

与无向图的邻接表结构一样。只是在第i条链表上的结点是以Vi为

弧尾的各个弧头顶点

G1的邻接表

有向图邻接表特点:

1. n个顶点,e条弧的有向图,需n个表头结点,e 个链表结点

2. 第i条链表上的链表结点数,为Vi的出度(求顶点的出度易,求入度难)


4 2 24

4

1

1

3

1

2

3

4

G1

2

3

4

$4.2 图—图的存储2-邻接表

3. 有向图逆邻接表

与无向图的邻接表结构一样。只是在第i条链表上的结点是以Vi为弧头的各个弧尾顶点

G1的逆邻接表

此时,第i条链表上的结点数,为Vi的入度


4 2 3 orthogonal list

tailvex

data

headvex

firstin

hlink

firstout

tlink

顶点结点

弧结点

data: 存放顶点的有关信息

(如顶点的名称,或位置)

firstin: 指向以该顶点为弧头的

第一个弧结点;

firstout: 指向以该顶点为弧尾

的第一个弧结点。

tailvex: 指示该弧的弧尾顶点;

headvex: 指示该弧的弧头顶点;

hlink: 指向弧头相同的下一条弧;

tlink: 指向弧尾相同的下一条弧

$4.2 图—图的存储3十字链表(orthogonal list)

十字链表是将有向图的邻接表和逆邻接表结合起来的一种有向图链式存储结构

有向图的每一条弧有一个弧结点,每一个顶点有一个顶点结点,

其结构为:


4 2 3 orthogonal list1

1

2

3

4

G1

e12

e13

1

1

3

4

1

4

3

2

e34

e41

$4.2 图—图的存储3十字链表(orthogonal list)

2. 整体结构

  • 通过hlink将弧头相同的弧连在一个链表上;

  • 通过tlink将弧尾相同的弧连在一个链表上

  • 而hlink链和tlink链的头结点就是顶点结点


4 2 3 orthogonal list2

$4.2 图—图的存储3十字链表(orthogonal list)

4.十字链表的特点:

① 顶点结点数=顶点数

弧结点数=弧的条数

② 求入度:从顶点Vi的firstin出发,沿着弧结点中的hlink所经过的弧结点数。

求出度:从顶点Vi的firstout出发,沿着弧结点中的tlink所经过的弧结点数。


4 2 4

ivex

ilink

jvex

jlink

data

firstedge

$4.2 图—图的存储4-邻接多重表

邻接多重表是无向图的另一种链式存储结构。

图的每一条边有一个边结点,边结点的结构为:

每一个顶点有一个顶点结点,顶点结点结构为:

其中:ivex 和jvex为该边所依附的两个顶点。

ilink指向下一条依附于顶点ivex的边。

jlink指向下一条依附于顶点jvex 的边。

data存放顶点的信息。

firstedge指向第一条依附于该顶点的边结点。


4 2 41

1

2

3

4

5

1

2

G2

3

2

3

3

5

1

5

2

4

4

$4.2 图—图的存储4-邻接多重表

如图G2的邻接多重表:

邻接多重表特点:

1.顶点结点数为n,边结点数为e

2.对需要得到边的两个顶点的一类操作很方便

(如删除一条边,判一条边是否已访问)


4621563

电子科技.计算机学院.数据结构与算法

$4.3 图—图的遍历

怎么知道图的顶点都被访问了?

怎么知道没有重复访问?


4621563

电子科技.计算机学院.数据结构与算法

$4.3 图—图的遍历

从图中某个顶点出发,沿路径使图中每个顶点被

访问且仅被访问一次的过程,称为遍历图。

深度优先搜索

两种常用遍历图的方法

广度优先搜索


4621563

电子科技.计算机学院.数据结构与算法

$4.3 图—图的遍历

一、深度优先搜索(depth-first-search)

1. 深度优先搜索法遍历图的过程为:

1). 访问指定的某顶点V,将V作为当前顶点

2). 访问当前顶点的下一未被访问过的邻接点,并将该顶点作为当前顶点

3). 重复2,直到当前顶点的所有邻接点都被访问过

4). 沿搜索路径回退,退到尚有邻接点未被访问过的某结点,将该结点

作为当前结点,重复2,直到所有顶点被访问过的为止


4621563

电子科技.计算机学院.数据结构与算法

深到底

回退

深到底

深到底

(V2V8均已访问)

V1V2V4V8V5

V3V6V7

V1

访问

V2

V3

V4

V5

V6

V7

回退

V8

$4.3 图—图的遍历

如图G4:


4621563

电子科技.计算机学院.数据结构与算法

$4.3 图—图的遍历

怎么写程序实现深度优先遍历?

可以采用递归和非递归2种方法

实现相同的深度优先遍历算法!


4621563

电子科技.计算机学院.数据结构与算法

$4.3 图—图的遍历

深度优先遍历的递归算法:

算法4.1 从顶点v0出发深度优先遍历g中能访问的各个顶点

void dfs(int v0)

{ visited[v0]=1; /*访问标志置为 1,表示已被访问*/

w=firstadj(g,v0); /* w是vo的第一个邻接点 */

while (w!=0)

{ if(visited[w]==0) dfs(w); /*顶点未被访问,则递归的进行深度遍历 */

w=nextadj(g,v0,w) /*顶点已访问,则取顶点v0在w后面的下一个邻接点 */

}

}


4621563

电子科技.计算机学院.数据结构与算法

1, 已访问过

visited[Vi]=

0, 未访问过(初值)

1. visited[1..n]是一个辅助数组,记载顶点是否被访问过

$4.3 图—图的遍历

几点说明:

2.firstadj (g,V0)和nextadj(g,V0,w)两个函数的实现与图的具体存储结构有关


4621563

电子科技.计算机学院.数据结构与算法

思考:travergraph调用 dfs的次数由什么决定?

图若采用邻接矩阵存储,编写相应的firstadj(g,V0)和nextadj(g,V0,w)

$4.3 图—图的遍历

算法4.2 图的深度优先遍历算法

void travergraph(g) { /* 对图g进行深度优先遍历 */

for(i=1;i<=n;i++) visited[i]=0; /* 标志数组初始化 */

for(i=1;i<=n;i++)

if(visited[i]==0) dfs(i); /* 深度优先遍历时调

用dfs(i) */

}

算法4.1 从顶点v0出发深度优先遍历g中能访问的各个顶点

void dfs(int v0){

visited[v0]=1; /*访问标志置为 1,表示已被访问*/

w=firstadj(g,v0); /* w是vo的第一个邻接点 */

while (w!=0) {

if(visited[w]==0) dfs(w); /*顶点未被访问,则递归的进行深度遍历 */

w=nextadj(g,v0,w) /*顶点已访问,则取顶点v0在w后面的下一个邻接点 */

}

}


4621563

电子科技.计算机学院.数据结构与算法

$4.3 图—图的遍历

如何实现非递归算法?

当然是栈了!


4621563

电子科技.计算机学院.数据结构与算法

V1

V2

V3

V4

V5

V6

V7

V8

$4.3 图—图的遍历

二、广度优先搜索(breadth-first-search)

  • 首先访问指定顶点v0,将v0作为当前顶点;

  • 访问当前顶点的所有未访问过的邻接点,

  • 并依次将访问的这些邻接点作为当前顶点;

  • 重复2, 直到所有顶点被访问为止。

对右图广度优先搜索,访问顶点序列为:

V1 V2 V3 V4 V5 V6 V7 V8


4621563

电子科技.计算机学院.数据结构与算法

$4.3 图—图的遍历

广度优先遍历的 非递归算法怎么实现?

对每一个当前访问顶点,

一次性访问其所有的邻接点,

您认为采用什么数据结构可以实现非递归算法?

队列!

Smarter!


4621563

电子科技.计算机学院.数据结构与算法

$4.3 图—图的遍历

算法4.3 从顶点v0出发广度优先遍历g中能访问的各个顶点

Void bfs(Graph g,int v0) { /* 从v0出发广度优先遍历图g */

visited[v0]=1;

Enqueue(Q,v0);

While (!Empty(Q)){

v=Dlqueue(Q); /* 取队头元素v */

w=Firstadj(g,v); /* 求v的第一个邻接点 */

while(w!=0){

if(visited[w]==0){

visited[w]=1;

Enqueue(Q,w);

}

w=Nextadj(g,v,w); /* 求下一个邻接点 */

}

}

}


4621563

$4.4 图—图的应用-最小生成树

右图为一个新兴小镇.其中6个红色小块为社区房屋, 2个白色小块为商店. 现在要铺设天然气管道, 造价和天然气管长度成正比. 如何铺设管道使得所有房屋和商店都通气且造价最低?


4621563

Target : 1. 求出图的具有最少边数的连通子图

2. 求出上述子图图中边取值和最小的连通子图

Idea : 实质是求图的包含所有顶点的具有最少边数的连通图,且边权值和最小.

$4.4 图—图的应用-最小生成树


4621563

$4.4 图—图的应用-最小生成树

一、最小生成树概念

1. 设无向连通图G=(V,{E}),

其子图G’=(V,{T})满足:

① V(G’)=V(G) n个顶点

② G’是连通的

③ G’中无回路

则G’是G的生成树


4621563

$4.4 图—图的应用-最小生成树

  • 具有n个顶点的无向连通图G

  • 其任一生成子图G’恰好含n-1条边

  • 生成树不一定唯一

4个顶点选择3条边有

如下5种形状(5×4= 20种):

其中16种为生成树,(保证了连通)


4621563

$4.4 图—图的应用-最小生成树

生成树代价

对图中每条边赋于一个权值(代价),则构成一个网,

网的生成树G’=(V,{T})的代价是T中各边的权值之和,

最小生成树就是网上所有可能的生成树中,代价最小的一类生成树。

最小生成树也不一定唯一。


4621563

$4.4 图—图的应用-最小生成树

您能够想出更多采用

最小生成树解决问题的实例吗?


4621563

$4.4 图—图的应用-最小生成树

顶点表示computer

边表示通讯线

N台计算机之间建立通讯网

例1:

权值表示通讯线的代价(通讯

线长度,computer间距离等)

要求:

① n台计算机中的任何两台能通过网进行通讯;

② 使总的代价最小。-------求最小生成树[T]


4621563

顶点表示投递点

例2:

邮递员送信线路[T]

边表示街道

权值表示街道的长度

要求:

① 完成n个投递点的投递;

② 使总路径长度最短, 即求最小生成树[T]

$4.4 图—图的应用-最小生成树


4621563

Problem :如何求解带权图的最小生成树?

$4.4 图—图的应用-最小生成树


4621563

u

v-u

u

v

u’

v’

$4.4 图—图的应用-最小生成树

二、最小生成树性质MST

设N=(V,{E})是一个连通网,

U是顶点集V的一个非空子集。

若(u,v)是一条具有最小权值的边,其中u∈U,v∈V-U,

即(u,v)=Min{cost(x,y)|x∈U,y∈V-U}

则必存在一棵包含边(u,v)的最小生成树。

含义:将顶点分为两个不相交的集合U和V-U,

若边(u,v)是连接这两个顶点集的最小权值边,则边(u,v)必然是某最小生成树的边。


4621563

$4.4 图—图的应用-最小生成树

  • 普里姆(Prim)最小生成树算法

基本思想:

取图中任意一个顶点 v 作为生成树的根,之后往生成树上添加新的顶点 w。在添加的顶点 w 和已经在生成树上的顶点u 之间必定存在一条边,并且该边的权值在所有连通顶点 u 和 w 之间的边中取值最小。之后继续往生成树上添加顶点,直至生成树上含有 n个顶点为止。


4621563

$4.4 图—图的应用-最小生成树

例如:

19

a

a

b

b

5

5

12

14

14

c

c

7

18

e

e

8

8

16

16

3

3

所得生成树权值和

g

g

d

d

= 14+8+3+5+16+21 = 67

21

21

27

f

f


4621563

$4.4 图—图的应用-最小生成树

  • 普里姆(Prim)最小生成树算法

设 N=(V,{E})是一个连通网,

V=[1,2,…,n}是N的顶点集合,

辅助集合U,初值为{Uo},

用来存放当前所得到的最小生成树的顶点;

辅助集合TE,初值为{},

用来存放当前所得到的最小生成树的边。


4621563

U

V-U

$4.4 图—图的应用-最小生成树

所添加的顶点应满足下列条件:

在生成树的构造过程中,图中 n 个顶点分属两个集合:已落在生成树上的顶点集 U 和尚未落在生成树上的顶点集V-U ,则应在所有连通U中顶点和V-U中顶点的边中选取权值最小的边。


4621563

第3步:

初始化:

4

2

6

5

1

1

1

6

1

5

5

第1步:

1

4

1

4

2

第4步:

3

6

5

6

2

6

4

6

第2步:

第5步:

5

4

2

3

6

$4.4 图—图的应用-最小生成树

1. TE=Ф,U={u0}

2. 当U≠V,重复下列步骤:

(1)选取(u0,v0)=min{cost(u,v)|u∈U,v∈V-U},保证不形成回路

(2)TE=TE+(u0,v0), 边(u0,v0)并入TE

(3)U=U+{V0},顶点V0 并入U

Prim

算法

步骤

特点: 以连通为主

选代价最小的邻接边


4621563

/* 用prim算法从序号为0的顶点出发构造有vtxnum个顶点的邻接矩阵存储结构的网gn的最小生成树T,并输出T的各条边 */

void minispantree_PRIM(int gn[][max],int vtxnum) {

int v,i,j,k;

float min;

for(v=1;v< vtxnum;v++) { /* 根据邻接矩阵的值对结构数组进行初始化 */

Closedge[v].vex=0;

Closedge[v].lowcost=gn[0][v];

}

/* 从序号为0的顶点出发生成最小生成树 */

Closedge[0].lowcost=0; Closedge[0].vex=0;

for(i=1;i< vtxnum;i++) { /* 寻找当前最小权值的边的顶点 */

k=minimum(closedge);

/* 使closedge[k].lowcost=MIN( closedge[v].lowcost | v ∈V-U && closedge[v].lowcost>0) * /

printf(“<%i,%i>”,closedge[k].vex, k); /* 输出生成树的边 */

closedge[k].lowcost=0; /* 顶点k并入U */

for(v=1;v<vtxnum;v++) /*新顶点并入U后,重选最小代价边*/

if(gn[k][v]<closedge[v].lowcost) {

Closedge[v].lowcost=gn[k][v];

Closedge[v].vex=k;

}

}

}

时间复杂度为O(n2)


4621563

$4.4 图—图的应用-最小生成树

/* 此函数求得k值,使closedge[k].lowcost=MIN( closedge[v].lowcost | v ∈V-U and closedge[v].lowcost>0) * /

int minimum(closedge) {

int min,h,k;

min=∞; h=1;

for(k=1;k<vtxnum;k++){

if (closedge[k].lowcost!=0 && closedge[k].lowcost< min)

{ min=closedge[k].lowcost; h=k;}

return h;

}


4621563

$4.4 图—图的应用-最小生成树

  • 算法的几点说明:

  • 1. gn为 网的邻接矩阵

  • 即 gn[i, j]=wij 或 为无穷大

  • 2. 辅助数组closedge[1..n] 有两个分量:

  • closedge[k].vex存放边(k, j)依附的另一顶点j( j∈U)

  • closedge[k].lowcost存放边(k, j)的权值,当值为0时, 表示顶点k已加入到集合U中。

  • 区别顶点 ∈U或∈V-U,是根据,.lowcost=0 ∈U . lowcost〉0 ∈V-U

  • closedge[k].vex ∈U 而 k ∈V-U


4621563

6

5

1

5

5

4

2

3

6

6

$4.4 图—图的应用-最小生成树

例子:


4621563

$4.4 图—图的应用-最小生成树

  • 克鲁斯卡尔(Kruskal)最小生成树算法

考虑问题的出发点: 为使生成树上边的权值之和达到最小,则应使生成树中每一条边的权值尽可能地小。

具体做法: 先构造一个只含 n 个顶点的子图 T,然后从权值最小的边开始,若它的添加不使T 中产生回路,则在 T中加上这条边,如此重复,直至加上 n-1 条边为止。


4621563

$4.4 图—图的应用-最小生成树

Kruskal 算法是逐步给生成树T中添加不和T中的边构成回路的当前最小代价边。

特点: 以最小代价边主。

设N=(V,{E})是个连通网, 算法步骤为:

1. 置生成树T的初始状态为T=(V,{Ф})

2. 当T中边数<n-1时, 重复下列步骤:

从E中选取代价最小的边(v, u), 并删除之;

若(v, u)依附的顶点v和u落在T中不同的连同分量上,

则将边(v, u)并入到T的边集中;

否则,舍去该边,选择下一条代价最小的边.


4621563

$4.4 图—图的应用-最小生成树

例如:

19

19

a

a

b

b

5

5

12

12

14

14

c

c

7

7

18

18

e

e

16

16

8

8

3

3

g

g

d

d

21

21

27

f

f


4621563

$4.4 图—图的应用-最小生成树

算法描述

构造非连通图 T=( V,{ } );

k = i = 0; // k 计选中的边数

while (k<n-1) {

++i;

检查边集 E 中第 i 条权值最小的边(u,v);

若(u,v)加入T后不使T中产生回路,

则 输出边(u,v);且 k++;

}


4621563

$4.4 图—图的应用-最小生成树

  • 普里姆和克鲁斯卡尔最小生成树算法比较

  • 普里姆最小生成树算法

  • 以连通为主

  • 选保证连通的代价最小的邻接边(n-1次)

  • 普里姆算法的时间复杂度与边无关,为O(n2)

  • 适合于求边稠密网的最小生成树。

  • 克鲁斯卡尔最小生成树算法

  • 以最小代价边主

  • 添加不形成回路的当前最小代价边

  • 算法时间复杂度与边相关,为Ο(elog2e)

  • 适合于求边稀疏网的最小生成树


4621563

$4.4 图—图的应用-拓扑排序

〖Example〗 Courses needed for a computer science degree at a hypothetical university

How shall we convert this list

into a graph?


4621563

Idea :假设以有向图表示一个工程的施工图,则图中不允许出现回路。

$4.4 图—图的应用-拓扑排序

这种课程安排合理吗?

如果每学期最多安排3门课程,

5学期安排学完所有课程,

如何安排?


4 4 topological sort

$4.4 图—图的应用-拓扑排序topological sort

拓扑排序是一种对非线性结构的有向图进行线性化的重要手段。

检查有向图中是否存在回路的方法之一,是对 有向图进行拓扑排序。


4621563

Java

DS

a3

a8

Compiler

C

a1

a7

OS

a4

a9

a5

a2

a6

$4.4 图—图的应用-拓扑排序

1、AOV网(Activity on vertex network)

一个有向图可用来表示一个施工流程图、一个产品生产流程图、或一个程序框图等。

课程安排

施工从活动 a1、 a2开始,到达活动 a8和 a9时,整个施工结束。

有向图中,顶点表示活动,弧< ai, aj >表示活动 ai优先于活动 aj ,

称这类有向图为顶点表示活动的网(AOV网)。


4621563

a3

a8

a1

a7

a4

a9

a5

a2

a6

$4.4 图—图的应用-拓扑排序

AOV网可解决如下两个问题:

(1)判定工程的可行性。显然,有回路,整个工程就无法结束

(2)确定各项活动在整个工程执行中的先后顺序。

称这种先后顺序为拓扑有序序列。

如图有如下拓扑有序序列: a1 a2 a3a4 a6 a5 a7 a8 a9

a2 a6 a1 a3 a4 a5 a7 a9 a8


4621563

$4.4 图—图的应用-拓扑排序

对于下列有向图

B

A

D

C

不能求得它的拓扑有序序列。

因为图中存在一个回路 {B, C, D}


4621563

$4.4 图—图的应用-拓扑排序

我已经知道什么叫

拓扑排序了,但是具体怎么做呢?

一个工程什么时候能够开始?

我的意思是怎么写

算法和程序?

Good! 如何判断一个工程

前面的工程都已经完成?

当然是在这个工程之前

的其他工程都已经完成了!

Smart!

AOV网中没有

前驱的顶点!


4621563

$4.4 图—图的应用-拓扑排序

算法步骤

(1) 在AOV网中,选取一个没有前驱的顶点输出;

(2) 删除该顶点和所有以它为弧尾的弧;

(3) 重复以上两步,直到

AOV网中全部顶点都已输出(得到拓扑有序序列)

或者,图中再无没有前驱的顶点(AOV网中有环)

拓扑排序算法


4621563

$4.4 图—图的应用-拓扑排序

【例4.2】P156:

顶点C0入度为0,选择输出C0,并删除C0及其所有出边得图(b)。这时入度为0的顶点是C1和C3,选择输出C1,并删除C1和它的所有出边,得图(c)。

依次选择C2,C3,C4,C5,C6,C7输出。

最后得到的拓扑序列为C0, C1 ,C2,C3,C4,C5,C6,C7


4621563

$4.4 图—图的应用-拓扑排序

如何实现算法中的(1)和(2)?

对于(1),没有前驱的顶点即入度为0的顶点;

对于(2),删除以它为弧尾的所有弧,即让该顶点的所有直接后继的入度减1。

  • 由此分析知:拓扑排序算法的实现与顶点的入度有密切关系,因此,在选取存储结构时,应考虑:

  • 能容易得到各顶点的入度;

  • 有利于寻找任一顶点的所有直接后继。

  • 为此,采用邻接表作为AOV网的存储结构,并在头结点中增加一个存放顶点入度的域(indegree)


4621563

V1

V2

V4

V3

4

3

2

V1

0

V2

2

V6

V5

5

2

V3

1

V4

2

5

V5

3

V6

0

4

5

$4.4 图—图的应用-拓扑排序

Void findIndegree(algraph g ,int *indegree) /* 求出图中所有顶点的入度 */

{ int i;

arcnode * p;

for(i=0;i<g.vexnum;i++)

indegree[i]=0;

for(i=0;i<g.vexnum;i++)

{ p=g.vertices[i].firstarc;

while(p){

++indegree[p->adjvex];

p=p->nextarc;

}

}

}


4621563

V1

V2

V4

V3

4

3

2

V1

0

V2

2

V6

V5

5

2

V3

1

V4

2

5

V5

3

V6

0

4

5

步骤 0 1 2 3 4 5 6

3

2

6

1

4

4

输出V6 V1 V3 V2 V4 V5

m 0 1 2 3 4 5 6=n

栈 TOP

0

0

2

0

0

0

1

4

1

1

0

0

2

0

5

1

0

2

0

0

0

入度域

1

0

0

0

0

3

0

1

1

0

2

0

2

0

0

0

0

0

$4.4 图—图的应用-拓扑排序

  • 使用栈记载入度为0的顶点(没有前驱或前驱已经输出的顶点)

  • 先将入度为0的顶点入栈;

  • 用栈进行控制: 输出栈顶顶点,并将其后继顶点的入度减1,若为0,则将该顶点入栈;

  • 直到栈空,若输出顶点数=图的顶点数,则图无回路,得到一个拓扑有序序列,否则图存在回路。


4621563

电子科技.计算机学院.数据结构与算法

$4.4 图—图的应用-关键路径

下表给出了某工程各工序之间的优先关系和各工序所需的时问(其中“一”表示无先驱工序),指明完成该工程所需的最短时间。如果因为其他原因,C所需时间变为4,会不会影响工期? 如果A所需时间变为4,会不会影响工期呢? 哪些工序影响工期,哪些不会影响? 不会影响的范围是多少?


4621563

电子科技.计算机学院.数据结构与算法

$4.4 图—图的应用-关键路径

AOE网(activity on edge)

若有向图中,顶点表示事件,弧表示活动,弧上的权表示完成该活动所需的时间,则称这类有向图为边表示活动的网(AOE网)

AOE网中仅有一个入度为0的事件,称为源点,它表示工程的开始;网中也仅有一个出度为0的事件,称为汇点,它表示工程的结束。

每一事件V表示以它为弧头的所有活动已经完成,同时,也表示以它为弧尾的所有活动可以开始。


4621563

电子科技.计算机学院.数据结构与算法

AOE网可解决如下问题:

估算工程的最短工期(从源点到汇点至少需要多少时间)

找出哪些活动是影响整个工程进展的关键

a1=6

a4=1

a5=1

a2=4

$4.4 图—图的应用-关键路径

有4个事件:V1, V2, V3, V5

V1为源点,V5为汇点

有4个活动:a1, a2, a4, a5

V3表示:a2已完成,a5可以开始


4621563

电子科技.计算机学院.数据结构与算法

vk

vj

$4.4 图—图的应用-关键路径

  • 2、术语

    • 路径长度:路径上各活动持续时间的总和 (即:路径上所有弧的权值之和)

    • 关键路径:从源点到汇点之间路径长度最长的路径, (不一定唯一)

    • 事件Vi的最早发生时间ev(i):从源点到Vi的最长路径长度

    • 活动 ai的最早开始时间e(i):等于该活动的弧尾事件Vj的最早发生时间

    • 即若<j, k>表示活动ai ,则有e(i)=ev(j)


4621563

电子科技.计算机学院.数据结构与算法

$4.4 图—图的应用-关键路径

  • 事件 vk 的最迟发生时间 lv(k):是在不推迟整个工期的前提下,该事件最迟必须发生的时间

  • 活动ai的最迟开始时间l(i):是该活动的弧头事件的最迟发生时间与该活动的持续时间之差,

  • 即l(i)=lv(k)- ai 的持续时间

  • 关键活动:l(i)=e(i)的活动

由此可见:在AOE网中找关键活动问题可转化为求 l(i)=e(i),而e(i)=ev(j)

l(i)=lv(k) - ai 的持续时间

因此,需先求出事件的最早、最迟发生时间


4621563

电子科技.计算机学院.数据结构与算法

a1=6

a4=1

a5=1

a2=4

$4.4 图—图的应用-关键路径

3、关键路径算法思想

1) 从ve(1)=0 开始利用下面递推公式,计算出各事件的最早发生时间

其中:p是所有以k为头的弧集合,

W<j,k>表示活动的持续时间

前例中,v(5)=Max{ev(2)+W<2,5>,

ev(3)+W<3,5>}

=Max{6+1,4+1}=7


4621563

电子科技.计算机学院.数据结构与算法

a1=6

a4=1

a5=1

a2=4

$4.4 图—图的应用-关键路径

  • 2) 从lv(n)=ev(n)开始,利用下面递推公式,计算出各事件的最迟发生时间:

    • 其中:S是所有以j为尾的弧集合

  • 前例中,Lv(5)=ev(5)=7 Lv(2)=Lv(5)-1=6

  • Lv(3)=Lv(5)-1=6

  • Lv(1)=Min{Lv(2)-W(<1,2>,Lv(3)-W<1,3>}

  • =Min{6-6,6-4}=0


4621563

电子科技.计算机学院.数据结构与算法

$4.4 图—图的应用-关键路径

  • 3) 设活动ai由弧<j, k>表示,其持续时间为w<j,k>,则利用下面公式,计算出各活动的最早、最迟开始时间:

    • e(i)=ev(j)

    • l(i)=Lv(k)-w<j,k>

  • 4) 找出e(i)=l(i)的活动,即为关键活动,诸关键活动组成的从源点到汇点的路径即为关键路径。


4621563

电子科技.计算机学院.数据结构与算法

1

2

3

4

5

6

a4=3

a1=3

a8=1

a3=2

源点

汇点

a7=2

a2=2

a5=4

a6=3

例. 求下面AOE网的关键路径

  • e(i)=ev(j)

  • l(i)=lv(k)-w<j,k>

计算结果为:

顶点 ev lv 活动 弧 持续T e l l-e 关键活动

V1 0 0 a1 <1,2> 3 0 1 1

V2 3 4 a2 <1,3> 2 0 0 0 a2

V3 2 2 a3 <2,4> 2 3 4 1

V4 6 6 a4 <2,5> 3 3 4 1

V5 6 7 a5 <3,4> 4 2 2 0 a5

V6 8 8 a6 <3,6> 3 2 5 3

a7 <4,6> 2 6 6 0 a7

Max + Min -a8 <5,6> 1 6 7 1


4621563

电子科技.计算机学院.数据结构与算法

e3=6

e0=0

e9=16

e6=7

6

6

16

16

a0=6

l0=0

a3=1

l3=6

0

0

l6=7

a6=9

a9=2

l9=16

e1=0

0

2

3

4

1

5

6

7

8

e4=4

start

7

7

a1=4

l1=2

18

18

a7=7

l7=7

finish

a10=4

l10=14

e7=7

6

4

a4=1

l4=6

e10=14

14

14

e2=0

e8=7

l2=0

a2=5

l8=10

a8=4

5

5

7

7

a5=2

l5=5

e5=5

$4.4 图—图的应用-关键路径

例. 求下面AOE网的关键路径

2

2

3

 计算 ev(i): 从v0开始

 计算 lv(i): 从v8开始

 计算 e(i): 从a0开始

 计算 l(i): 从a10开始

 关键活动: {ai | e ( i ) = l ( i ) }

关键路径: = v0v1v4v6v8


4621563

电子科技.计算机学院.数据结构与算法

a3=2

a4=3

a8=1

a1=3

a7=2

a5=4

a2=2

a6=3

$4.4 图—图的应用-关键路径

关键路径上的活动都是关键活动。

缩短非关键活动都不能缩短整个工期

如a6缩短为1,则整个工期仍为8。

又如a6推迟3天开始,或拖延3天完成

a6=6)均不影响整个工期

分析关键路径的目的是找出影响整个工期的关键活动,缩短关键活动的持续时间,常可以缩短整个工期。

如a7缩短为1,则整个工期为7。

此时,再缩短任一关键活动均不能缩短整个工期。

即在有多条关键路径时,缩短那些在所有关键路上的关键活动,才能缩短整个工期


4621563

电子科技.计算机学院.数据结构与算法

  • int criticalpath(algraph * paoe) { /*算法4.7 关键路径算法(P161) */

  • int i,j,k; int ev[vexnum],lv[vexnum],l[arcnum],e[arcnum]; arcnode * p; Topo topo;

  • if(toposort(paoe,&topo)==0) return 0; /* 求AOE网的一个拓扑序列 */

  • for(i=0;i<paoe->vexnum;i++) ev[i]=0;

  • for(k=0;k<paoe->vexnum;k++) { /*正向求事件vj的最早发生时间ev(j)*/

  • i=topo.vexsno[k]; p=paoe->vertices[i].firstarc;

  • while(p!=NULL) {

  • j=p->adjvex;

  • if(ev[i]+p->weight>ev[j]) ev[j]=ev[i]+p->weight;

  • p=p->nextarc; } }

  • for(i=0;i<paoe->vexnum;i++) lv[i]=ev[paoe->vexnum-1];

  • for(k=paoe->vexnum-2;k>=0;k--) { /*逆向求事件vi的最迟发生时间lv(j)*/

  • i=topo.vexsno[k]; p=paoe->vertices[i].firstarc;

  • while(p!=NULL) {

  • j=p->adjvex;

  • if((lv[j]- p->weight)<lv[i]) lv[i]=lv[j]- p->weight;

  • p=p->nextarc; } }

  • k=0;

  • for(i=0;i<paoe->vexnum;i++) { /*求活动ak的最早开始时间e(k)和最晚开始时间l(k) */

  • p=paoe->vertices[i].firstarc;

  • while(p!=NULL) {

  • j=p->adjvex; e[k]=ev[i]; l[k]=lv[j]- p->weight;

  • if(e[k]==l[k]) printf(“<v%2d,v%2d>,”,i,j);

  • k++; p=p->nextarc; } }

  • printf(“\n”);

  • return 1; }


4621563

电子科技.计算机学院.数据结构与算法

  • int criticalpath(algraph * paoe) { /*算法4.7 */

  • int i,j,k;

  • int ev[vexnum],lv[vexnum],l[arcnum],e[arcnum];

  • arcnode * p;

  • Topo topo;

  • if(toposort(paoe,&topo)==0) return 0; /* 求拓扑序列 */

  • for(i=0;i<paoe->vexnum;i++) ev[i]=0;

  • for(k=0;k<paoe->vexnum;k++) { /*正向求事件vj的最早发生时间ev(j)*/

  • i=topo.vexsno[k]; /*弄清楚使用的数据结构:栈和图*/

  • p=paoe->vertices[i].firstarc;

  • while(p!=NULL) {

  • j=p->adjvex;

  • if(ev[i]+p->weight>ev[j]) ev[j]=ev[i]+p->weight;

  • p=p->nextarc; } }

  • ……

  • return 1; }

求事件vj的最早发生时间ev(j)是按拓扑有序的次序


4621563

电子科技.计算机学院.数据结构与算法

  • int criticalpath(algraph * paoe) { /*算法4.7 关键路径算法(P161) */

  • ……

  • if(toposort(paoe,&topo)==0) return 0; /* 求AOE网的一个拓扑序列 */

  • for(i=0;i<paoe->vexnum;i++) ev[i]=0;

  • for(k=0;k<paoe->vexnum;k++) { /*正向求事件vj的最早发生时间ev(j)*/

  • …… }

  • for(i=0;i<paoe->vexnum;i++) lv[i]=ev[paoe->vexnum-1];

  • for(k=paoe->vexnum-2;k>=0;k--) { /*逆向求事件vi的最迟发生时间lv(i)*/

  • i=topo.vexsno[k];

  • p=paoe->vertices[i].firstarc;

  • while(p!=NULL) {

  • j=p->adjvex;

  • if((lv[j]- p->weight)<lv[i]) lv[i]=lv[j]- p->weight;

  • p=p->nextarc; } }

  • ……

  • return 1; }

  • 求事件vj的最迟发生时间lv(j)是按拓扑逆序的次序


4621563

电子科技.计算机学院.数据结构与算法

  • int criticalpath(algraph * paoe) { /*算法4.7 关键路径算法(P161) */

  • ……

  • if(toposort(paoe,&topo)==0) return 0; /* 求AOE网的一个拓扑序列 */

  • for(i=0;i<paoe->vexnum;i++) ev[i]=0;

  • for(k=0;k<paoe->vexnum;k++) { /*正向求事件vj的最早发生时间ev(j)*/

  • …… }

  • for(i=0;i<paoe->vexnum;i++) lv[i]=ev[paoe->vexnum-1];

  • for(k=paoe->vexnum-2;k>=0;k--) { /*逆向求事件vi的最迟发生时间lv(j)*/

  • …… }

  • k=0;

  • for(i=0;i<paoe->vexnum;i++) { /*求活动ak的最早开始时间e(k)和最晚开始时间l(k) */

  • p=paoe->vertices[i].firstarc;

  • while(p!=NULL) {

  • j=p->adjvex; e[k]=ev[i]; l[k]=lv[j]- p->weight;

  • if(e[k]==l[k]) printf(“<v%2d,v%2d>,”,i,j);

  • k++; p=p->nextarc; } }

  • printf(“\n”);

  • return 1; }


4 4 shortest paths

$4.4 图—图的应用-最短路径( Shortest Paths )

  • 如果从峨眉山出发,每年要从九寨沟,黄山,香港,拉斯维加斯等地选择一个旅游景点旅游, 已知各地旅游线路间的机票价格如图所示, 到各个旅游点的机票最低开销是多少?


4 4 shortest paths1

$4.4 图—图的应用-最短路径( Shortest Paths )

怎么求最低开销呢?

观察!

实质就是求图一个顶点到其他顶点的最短路径!


4 4 shortest paths2

电子科技.计算机学院.数据结构与算法

$4.4 图—图的应用-最短路径( Shortest Paths )

在有向图中,寻找从某个源点到其余各个顶点或者每一对顶点之间的最短带权路径的运算,称为最短路径问题。

1.单源点最短路径

是指给定带权有向图D和源点v,求从源点v到D中其余各顶点之间的最短路径

2.所有顶点对之间的最短路径

求D中各顶点对之间的最短路径


4 4 shortest paths3

$4.4 图—图的应用-最短路径( Shortest Paths )

【例4.4】图4-30所示带权有向图中从v0到其余各顶点之间的最短路径,如表4-4所示。从图中可见,从v0到v3有两条不同的路径:(v0,v2,v3)和(v0,v4,v3),前者长度为60,而后者长度为50。因此,后者是从v0到v3的最短路径。而从v0到v1没有路径。


4 4 shortest paths4

电子科技.计算机学院.数据结构与算法

$4.4 图—图的应用-最短路径( Shortest Paths )

  • 1. 迪杰特拉(Dijkstra) 算法:

  • 算法思想:按路径长度递增的次序产生到各顶点的最短路径

  • 使用DS:

    • 利用带权邻接矩阵

    • 表示当前找到的从源点V0到每个终点Vi的最短路径长度的辅助向量dist[i]

    • 存储最短路径的向量path[i]

    • 表示已找到从V0出发的最短路径的终点的集合S


4 4 shortest paths5

$4.4 图—图的应用-最短路径( Shortest Paths )

  • 算法步骤:

    • 1. 用邻接矩阵初始化dist;置S={V0};

    • 2. 选择Vj,使得:dist[j]=Min{dist[i]|Vi∈V-S} Vj 就是当前求得的从V0出发的最短路径的终点,并将Vj并入S;

    • 3. 对V-S上的所有顶点Vk,修改:

    • dist[k]=Min{dist[j]+cost[j, k], dist[k]}

    • 4. 重复2,3, n-1次。


4 4 shortest paths6

cost

60

0 1 2 3 4 5

100

100

30

10

0

0

30

20

5

10

10

1

2

50

5

10

50

3

4

60

20

5

10(v0,v2)

50(v0,v4,v3)

60(v0,v2,v3)

30(v0,v4)

30(v0,v4)

100(v0,v5)

90(v0,v4,v5)

60(v0,v4,v3,v5)

100(v0,v5)

v4

v3

v2

v5

$4.4 图—图的应用-最短路径( Shortest Paths )

  • 例子

终点 从v0到各终点的 dist 值和最短路径

v1

v2

v3

v4

v5

vj


4 4 shortest paths7

$4.4 图—图的应用-最短路径( Shortest Paths )

  • 算法4.8 迪杰斯特拉(Dijkstra)算法(P164)

  • void Dijkstra(Mgraph Gn, int v0,int path[],int dist[]) {

  • /* 求有向网Gn的v0顶点到其余顶点v的最短路径, */

  • int s[VEX_NUM];

  • /* s标记已找到最短路径的顶点,初值只包括v0,即s[0]=1*/

  • /* dist记录源点到其他各顶点当前的最短距离,其初值为:

  • dist[i] = G.arcs[0][i] i=1,2,…,n-1*/

  • for(int v=0; v<VEX_NUM; v++) {

  • s[v] = 0;

  • dist[v] = Gn.arcs[v0][v];

  • if( dist[v] < MAXINT ) path[v] = v0;

  • else path[v] = -1;

  • }

  • dist[v0] = 0;s[v0] = 1; /*初始时源点v0∈S集*/


4621563

  • /* 循环求v0到某个顶点v的最短路径,并将v加入S集*/

  • /*算法执行时从S以外的顶点集合(V -S)中选出一个顶点w,使dist[w]的值最小。 然后将w加入集合S中,即s[w]=1;同时调整集合(V-S)中的各个顶点的距离值: 从原来的dist[j]和dist[w]+cost[w][j]中选择较小的值作为新的dist[j]。重复上述过程, 直到S中包含图中所有顶点,或再也没有可加入到S中的顶点为止。*/

  • for(int i=1; i<VEX_NUM-1; i++) {

  • int min = MAXINT;

  • v=-1;

  • for(int w=0; w<VEX_NUM; w++)/* 找出最小的dist[w] */

  • if(!s[w] && dist[w]<min){ /*顶点w不属于S,且离v0更近*/

  • v = w;

  • min = dist[w];}

  • if(v == -1) break; /* 已无顶点可加入S中,退出外层for */

  • s[v]=1; /*顶点v并入S*/

  • /*调整集合V-S中的各个顶点的距离值 */

  • for(int j=0; j<VEX_NUM; j++) /*更新当前最短路径及距离*/

  • if(!s[j] && (min+Gn.arcs[v][j]<dist[j])){/*dist[j]是v0到顶点j当前的最短路径*/

  • dist[j] = min + Gn.arcs[v][j];/*v0经v到顶点j的距离= min + Gn.arcs[v][j];*/

  • path[j] = v; }/*if*/

  • }/*for*/

  • }


4621563

60

100

0

30

20

10

10

5

50

0

0

0

0

0


4 4 shortest paths8

$4.4 图—图的应用-最短路径( Shortest Paths )

2、每一对顶点之间的最短路径

  • 每次以一个顶点为源点,调用Dijkstra算法n次,O(n3);

  • 弗洛伊德算法(Floyed)

    弗洛伊德算法思想:

定义一个n阶方阵序列为D(-1),D(0), D(1),…, D(k-1),…, D(n-1),

可用如下的数学表达式描述弗洛伊德算法:

D(-1)[i][j]=cost[i][j];

D(k)[i][j]=Min{D(k-1)[i][j],D(k-1)[i][k]+D(k-1)[k][j]} 0≤k≤n-1

可见,D(1)[i][j]是从vi到vj的中间顶点的序号不大于1的最短路径长度;

D(k)[i][j]是从vi到vj的中间顶点的序号不大于k的最短路径的长度;

D(n-1)[i][j]就是从vi到vj的最短路径的长度


4 4 shortest paths9

$4.4 图—图的应用-最短路径( Shortest Paths )

  • 弗洛伊德(Floyd)算法(P166)

  • void Floyd(int cost[][],Mgraph Gn,int path[][]) {

  • int i,j,k;

  • for (i=0;i<n;i++)

  • for (j=0;j< n;j++) {

  • Gn.arcs[i][j]=cost[i][j];

  • if (i==j) path[i][j]=-1;

  • else if (cost[i][j]<maxint) path[i][j]=i;

  • else path[i][j]=-1;

  • }

  • for(k=0;k<n;k++)

  • for(i=0;i<n;i++)

  • for(j=0;j<n;j++)

  • if(Gn.arcs[i][j]>( Gn.arcs[i][k]+ Gn.arcs[k][j]))

  • { Gn.arcs[i][j]= Gn.arcs[i][k]+ Gn.arcs[k][j];

  • path[i][j]=path[k][j];

  • }

  • }


4621563

电子科技.计算机学院.数据结构与算法

广义表也是常用的一类数据结构,它与图一样,可以反映

数据元素之间多对多的关系。它是一种广泛应用于人工智能等

领域内的重要数据结构。广义表也称为列表,甚至就简称为表

1.广义表定义

广义表可记为:LS=(d1,d2,…,dn)

其中:LS为表名,

数据元素di(i=1,2,…,n),可以是单元素(用小写字母表示);

也可以是广义表(称为子表,用大写字母表示);

n为表的长度,当长度为0时称为空表;

非空表的第一个元素d1称为表头,

其余元素组成的表(d2,…,dn)称为表尾。


4621563

$4.5 广义表

  • 广义表的定义是递归定义的,下面给出一些广义表的例子:

  • A =() 空表;其长度为零

  • B =(a,(b,c))是一个长度为2的广义表,其中第一个数据元素是单元素a,第二个数据元素是一个子表(b,c)

  • C =(A,A,B)是长度为3的广义表,其前两个元素为表A,第三个元素为B

  • D=(a,D)是长度为2递归定义的广义表,D相当于无穷表

  • D=(a,(a,(a,(…))))


4621563

$4.5 广义表

⒉ 广义表的基本运算

⑴ 取表头 head(LS);

⑵ 取表尾 tail(LS)。

广义表B =(a,(b,c))

head(B)=a; 表B的表头是:a

tail(B)=((b,c)); 表B的表尾是((b,c))

广义表的表尾一定是一个表。

一个广义表的深度是指该广义表展开后所含括号的层数,例如:

A=(b,c)的深度为1,B=(A,d)的深度为2,C=(f,B,h)的深度为3


4621563

$4.5 广义表

广义表也可以用图形来表示,其中:图中的分支结点对应广义表,非分支结点一般是原子。下面给出的几个广义表的图形表示:


4621563

3. 广义表存储结构

广义表中的数据元素可以是单元素,或是广义表

很难用顺序存储结构表示,常采用链式存储结构。

1)表头表尾链存储结构

有两类结点:表结点和单元素结点。

$4.5 广义表

tag标志域,0表示结点为单元素结点,1表示为表结点;

hp:表头指针域; tp:表尾指针域; data: 值域。


4621563

电子科技.计算机学院.数据结构与算法

C

1

1

1

1

1

0 a

0 c

0 b

0 d

$4.5 广义表

例: C=(a, (b, c, d))

((b, c, d))

  • 这种存储结构的特点是:

  • 最上层的表结点数即为广义表的长度;

  • 层次清楚;

  • 表结点数目多,与广义表中括号对的数目不匹配

(b, c, d)

(c, d)

(d)


4621563

2) 同层结点链存储结构

有两类结点:表结点和单元素结点。

tp为链接同层下一结点的指针域,

其它域的含义同表头表尾链结构。

$4.5 广义表


4621563

C

1

1

0 b

0 a

0 c

0 d

$4.5 广义表

例: C=(a, (b, c, d))

同层结点链结构的特点是:

  • 表结点的数目与广义表的括号对数目一致;

  • 写递归算法不方便。

(b, c, d)


  • Login