2021-1 拓扑排序的准备,深度优先搜索的三个顺序

DFS的特性

  • 每个顶点只会被访问一次
  • dfs()的参数保存在一个数据结构中就能访问到图中的所有顶点

有用的三个顺序

  • 前序:递归之前,顶点加入队列 pre()
  • 后序:递归之后,顶点加入队列 post()
  • 逆后序:递归之后,顶点入栈 reversePost()
//伪代码
dfs(G ,v):
	pre.enqueue(v)//函数栈调用的先后次序
	for each w in v.adj():
		dfs(G,w)
	post.enqueue(v)//完成dfs的节点次序,先完成的在队头
	reversePost.enstack(v)//完成dfs的节点次序,但,先完成的在栈底

一幅有向无环图的拓扑顺序即为所有顶点的逆后序排列

证明:对于任意边 v->w,再调用dfs(v)下面三种情况必有其一成立:

  • dfs(w) 已经调用且已经返回(w已经被标记,比如,w只是v的第一个儿子且为叶子,现在访问第二个儿子)
  • dfs(w)还没被调用(w未被标记),因此,v->w会直接或间接的调用并返回dfs(w),且dfs(w)会在dfs(v)返回前返回。(dfs中儿子会在父亲前被返回)
  • dfs(w)已经被调用但是还未返回。证明的关键是,这种情况说明w已经在函数栈中,即存在一条w到v的路径,加上当前的v->w,已经构成环。即这种情况不可能存在于有向无环图中。

综上,在有向无环图中前两种情况,儿子总能比父亲先完成dfs,因此在后序排列中儿子在前父亲在后,逆后序中保证父亲v在前(栈顶)儿子w在后(栈底)。因此任意一条边v->w都能如愿的从排名较前的顶点指向排名靠后的顶点。

注解:dfs()先完成的节点有什么特征?儿子少,或者说是个光棍。称为这类节点排名靠后联想最经典的选课次序图,排名靠后的大概像《嵌入式系统概论》,《图像识别与深度学习》,排名较前的像《计算机基础》,它的儿子就很多。

图示

在这里插入图片描述
注意到,三号栈,依次弹出<0 1 3 2>刚好就是拓扑序列。

有向图基于DFS的顶点排序

对下图记录三种排序
在这里插入图片描述
pre: 0 5 4 3 2 1 6 9 11 12 10 8 7
rePost:7 6 8 9 10 11 12 0 1 5 4 3 2

头文件和测试文件,点这里 Digraph.h

#pragma once

#include"Digraph.h"
#include<queue>
#include<stack>


class DepthFirstOrder
{
    
    
public:
	DepthFirstOrder(Digraph& G);
	
	
	queue<int>* getPre() {
    
    
		return m_pre;
	}

	queue<int>* getPost() {
    
    
		return m_post;
	}

	stack<int>* getRePost() {
    
    
		return m_rePost;
	}

private:
	vector<bool>* m_marked = nullptr;
	queue<int>* m_pre = nullptr;
	queue<int>* m_post = nullptr;
	stack<int>* m_rePost = nullptr;

	void dfs(Digraph& G, int v);
};


void testDFOrder();
#include"DepthFirstOrder.h"

DepthFirstOrder::DepthFirstOrder(Digraph& G)
{
    
    
	m_pre = new queue<int>();
	m_post = new queue<int>();
	m_rePost = new stack<int>();

	m_marked = new vector<bool>(G.V(), false);
	for (int i = 0; i < G.V(); ++i) {
    
    
		if (!m_marked->at(i)) dfs(G, i);
	}
}

inline
void DepthFirstOrder::dfs(Digraph& G, int v)
{
    
    
	m_pre->push(v);
	m_marked->at(v) = true;
	forIt(G.adj(v)) {
    
    
		int w = *it;
		if (!m_marked->at(w)) {
    
    
			dfs(G, w);
		}
	}
	m_post->push(v);
	m_rePost->push(v);
}

void testDFOrder()
{
    
    
	Digraph G("tinyDG.txt");
	DepthFirstOrder dfO(G);

	queue<int>* q = dfO.getPre();

	while (!q->empty()) {
    
    
		int x = q->front(); q->pop();
		out(x);
	}
	hh;

	stack<int>* stk = dfO.getRePost();
	while (!stk->empty()) {
    
    
		int x = stk->top(); stk->pop();
		out(x);
	}
	hh;
}

猜你喜欢

转载自blog.csdn.net/qq_34890856/article/details/113038776