课程笔记 17:数据结构(清华) 图-遍历

来源:互联网 发布:图像识别算法 知乎 编辑:程序博客网 时间:2024/05/29 14:39

我们之前研究的树结构是一种半线性结构,为了利用之前研究相对成熟的线性结构如向量、列表,我们会采用遍历手法来将树转化为线性结构来研究。同样的,在研究图这一非线性结构时,我们同样可以通过遍历手法将其转化为非线性结构——树来研究。

在进行树的遍历算法时,关键的地方是选定当前顶点的下一个对象。通常,我们有两种选定方法。其一是对于越早被访问到的顶点,其邻居就会越优先被选用。这种方法被称为广度优先搜索。其二是直接将当前顶点的最近邻居作为当前顶点,直到某一个顶点没有邻接顶点,再返回上一顶点,继续访问其邻居顶点 。这种方法被称为深度优先搜索。

现在,我们先探讨广度优先搜索的实现。假定我们选定某一个顶点作为初始顶点,那么该顶点的所有邻接顶点都将在第一轮遍历中被访问到,我们可以把初始顶点视为树根,而把这些邻接顶点视为树的第一层子节点。继而,在第二轮遍历中,我们将依次访问第一层每个节点的所有邻接顶点,并把它们视为树的第二层子节点。以此类推,我们将得到一颗完整的树。

仔细观察上述遍历过程,不难发现我们对遍历树的访问次序就是对树进行层次遍历的次序。这就提示我们可以采用在树的层次遍历中所采用的策略一样,利用队列来实现图的广度优先搜索。根据一思路,我们可以写出如下的代码 :

template<typename Tv, typename Te>

voidGraph::BFS(int u, int& clock)

{

queue<int>Q;

Q.enqueue(u);

while ( !Q.empty())

{

u = Q.dequeue();

for ( int s =firstNbr(u); s > -1; s = nextNbr(u, s) )

{

if ( V[s].status== UNDISCOVRED )

{

Q.enqueue(s);

E[u][s].status =TREE;

V[s].parent =V[u];

V[s].dTime = ++clock;

V[s],status =DISCOVERED;

}

else

E[u][s] = CROSS;

}

V[u].status =VISITED;

}

}

为了保证整个图的每一个顶点和边能无一遗漏的被访问到,我们需要对所有的顶点进行一遍扫描来确认每一个顶点的状态都是VISITED。

template<typename Tv, typename Te>

void Graph::bfs()

{

int clock = 0;

for ( int u = 0; u< n; u ++ )

if ( V[u].status!= VISITED ) BFS(u, clock);

}

深度优先算法比广度优先算法更容易理解,但是在实现方面却更为复杂。因为深度优先搜索需要标记的边的状态较多,讨论也较为复杂。一般来说,我们把在遍历形成的支撑树中由祖先节点指向后代节点的非树边记为FORWARD,而由后代节点指向祖先节点的非树边记为BACKWARD,另外,无直系血缘关系的节点间的非树边记为CROSS。现在我们就可以着手进行深度优先搜索的设计了。

template<typename Tv, typename Te>

void  Graph::DFS(int u, int& clock)

{

V[u].status =DISCOVERED;

V[u].dTime = ++clock;

for ( int s =firstNbr(u); s > -1; s = nextNbr(u, s) )

{

switch (V[s].status )

{

case UNDISCOVERED:

E[u][s].status =TREE;

V[s].parent = u;

DFS(s, clock);

break;

case DISCOVERED:

E[u][s].status =BACKWARD;

break;

default :

E[u][s].status = (V[s].dTime > V[u].dTime ) ? FORWARD: CROSS;

break;

}

}

V[u].status =VISITED;

V[u].fTime = ++clock;

}

和BFS一样,我们同样需要对所有顶点进行一遍扫描来确保每一个顶点的状态都是VISITED。

template<typename Tv, typename Te>

void Graph::dfs()

{

int clock = 0;

for ( int u = 0; u< n; u ++ )

if ( V[u].status!= VISITED ) BFS(u, clock);

}

0 0
原创粉丝点击