学习 严蔚敏讲数据结构笔记16

来源:互联网 发布:做淘宝仓库打包员累吗 编辑:程序博客网 时间:2024/05/19 14:17

7.6 两点之间的最短路径问题

从原点到其余各点的最短路径。

算法的基本思想是:依路径长度递增的次序求得各条路径

假设图中所示为从原点到其余各点之间的最短路径,则在这些路径中,必然存在一条长度最短者。

在这条路径上,必定只含有一条(权值最小)弧,由此,只要在所有从原点出发的弧中查找权值最小者;

长度次短的路径可能有两种情况:它可能是从原点直接到改点的路径;也可能是,从原点a再到该点

其余依次类推。

假设Disk[k]表示当前所求得的从原点到顶点k的最短路径。则一般情况下,Disk[k]=<源点到顶点k的弧上的权值>或者=<源点到其它顶点路径的长度>+<其它顶点到顶点k弧上的权值>

 

 

 

 

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

算法的基本思想:从vivj的所有存在的路径中,选出一条最短的路径

<vi,vj>存在,则存在路径{vi,vj}路径中不含其它顶点

<vi,vl><vl,vj>存在,则存在路径{vi,vl,vj}路径中所含顶点序号不大于1

{vi,…,v2},{v2,…,vj}存在,则存在一条路径{vi,…,v2,…vj}路径中所含顶点序号不大于2

依次类推,则vivj的最短路径应是上述着这些路径中,路径长度最小者

 

7.7拓扑排序

问题:假设以有向图表示一个工程的施工图或程序的数据流图,则图中不允许出现回路。

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

何谓“拓扑排序”?

对有向图进行如下操作:

按照有向图给出的次序关系,就爱那个图中顶点排成一个线性序列,对于有向图中没有限定次序关系的顶点,则可以人为加上任意的次序关系。

由此所得顶点的线性序列称之为拓扑有序序列

例如:对于下列有向图

可求得拓扑有序序列:ABCDACBD

反之,对于下列有向图

不能求得它的拓扑有序序列。因为图中存在一个回路{B,C,D}

如何进行拓扑排序?

一、从有向图中选取一个没有前驱的顶点,并输出之

二、从有向图中删去此顶点以及所有以它为尾的弧

重复上述两步,直至图空,或者图不空但找不到前驱的顶点为止。

没有前驱的顶点===入度为零的顶点

删除顶点及以它为尾的弧===弧头顶点的入度减1

算法取入度为零的顶点v

29_001

while(v <> 0)

{

         printf(v);

         ++  m;

w: = FirstAdj(v);

    while(w <> 0)

    {

                   inDegree[w]  --;

w: = newAdj(v, w);

    }

    //取下一个入度为零的顶点v;

}

if(m < n)

{

         printf("图中有回路");

}

为避免每次都要搜索入度为零的顶点,在算法中设置一个“栈”,以保存“入度为零”的顶点。

29_002

CountInDegree(G, indegree); //对各顶点求入度

InitStack(S);

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

{

         if(!  indegree[i])

         {

                   Push(S,  i); //入度为零的顶点入栈

         }

}

count = 0; //对输出顶点计数

while(! EmptyStack(S))

{

         Pop(S,  v);

         ++  count;

         printf(v);

         for(w  = FirstAdj(v); w; w = NextAdj(G, v, w))

         {

                   --  indegree(w);

         }

         if(!  indegree[w])

         {

                   Push(S,  w); //新产生的入度为零的顶点入栈

         }

}

if(count < G.vexnum)

{

         printf("图中有回路");

}

7.8关键路径

假设以有向网表示一个施工流图,弧上的权值表示完成该项子工程所需时间

问:哪些子工程项是“关键工程?”?

即:将影响整个工程完成前的子工程项。

整个工程完成的时间为:从有向图的源点到汇点的最长路径

“关键活动”指的是:该弧上的权值增加静使有向图上的最长路径的长度增加。

如何求关键活动

“事件(顶点)”的最早发生时间ve(j)ve(j)=从原点到顶点j的最长路径长度;

“事件(顶点)”的最迟发生时间vl(k), vl(k)=从顶点k到汇点的最短路径长度;

假设第i条弧为<j,k>则第i项活动“活动(弧)”的最早开始时间ee(i),ee(i)=ve(j);

“活动(弧)”的最迟开始时间el(i),el(i)=vl(k)-dut(<j,k>);

事件发生时间的计算公式

Ve(原点)=0

Ve(k)=Max{ve(j)+dut(<j,k>)}

Vl(汇点)=ve(汇点);

Vl(j)=Min{vl(k)-dut(<j,k>)}

算法的实现要点:

显然,求ve的顺序应该是按拓扑有序的次序;而求vl的顺序应该是按拓扑逆序的次序。因为,脱兔逆序序列即为拓扑有序序列的逆序列,因此,应该在拓扑排序的过程中,另设一个“栈”记下拓扑有序序列。

 

1.      熟悉图的各种存储结构及其构造算法,了解实际问题的求解效率与采用何种存储结构和算法有密切联系。

2.      熟练掌握图的两种搜索路径的遍历;遍历的逻辑定义,深度优先搜索的来年各种形式(递归和非i递归)和广度优先搜索的算法,在学习中应注意图的遍历算法域树的遍历算法之间的类似和差异。

3.      应用图的遍历算法求解各种简单路径问题

4.      理解教科书中讨论的各种图的算法。

 

5.4 广义表的类型定义

ADT Glist{

         数据对象:D={ei|I= 1,2,…,n; n>=0; eAtomSeteiGList,AtomSet为某个数据对象}

         数据关系:LR={<ei-1,ei>|ei-1,eiD,2<=i<=n}

}

广义表是递归定义的线性结构。

一般情况下,广义表写成LS=(a1,a2,…,an)其中:ai或为原子或为广义表

广义表是一个多层次的线性结构

例如:D=(E,F) E=(a,(b,c)) F=(d,(e))

其它如:

A=()

B=(a,B)=(a,(a,(a,…,)))

C=(A,D,F)

广义表LS=(a1,a2,…an)的结构特点:

1)  广义表中的数据元素有相对次序

2)  广义表的长度定义为最外层包含元素个数

3)  广义表的深度定义为所含括弧的重数;

注意“原子”的深度为“0”。“空表”的深度为1

4)  广义表可以共享

5)  广义表可以是一个递归的表;递归表的深度是无穷值,长度是有限值。

6)  任何一个非空广义表LS(a1,a2,…,an)均可分解为表头Head(L,S)=a1和表尾Tail(LS)=(a2,…,an)两部分

例如:LS=(A,D)=((),(E,F))=((),((a,(b,c)),F)

Head(LS)=A Tail(LS)=(D)

Head(D)=E Tail(D)=(F)

Head(E)=a Tail(E)=((b,c))

Head(((b,c)))=(b,c) Tail(((b,c))=()

Head((b,c))=b Tail(b,c))=(c)

Head((c))=c Tail((c))=()

基本操作:

结构的创建和销毁

InitGList(&L);

DestroGList(&L);

CreateGList(&L, S);

CopyGList(&T, L)

状态函数

GListLength(L);

GListDepth(L);

GListEmpty(L);

GetHead(L);

GetTail(L);

插入和删除操作

InsertFirst(&L, e);

DeleteFirst(&L, &e);

遍历

Traverse_GL(L, Visit());

原创粉丝点击