您的位置:首页 > 其它

有向图的可达性

2015-11-16 11:22 363 查看
        有向图中,我们可以使用深度优先遍历方式来测试有向图的可达性。这样给出一个节点,我们就可以知道是否存在一个路径从起点(就是从该点进行深度优先遍历)到达该节点。它解决了单点连通性的问题,使用用例可以判定其他顶点和给定的起点是否连通。

        在存储图的数据结构中,我们使用邻接表来存储有向图。下图就是一个存储的示例:



源代码如下:

#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;

class Digraph
{
public:
Digraph(size_t nvertax) : arr(nvertax), vertaxs(nvertax), edges(0) {}
void addEdge(size_t a, size_t b);
void removeEdge(size_t a, size_t b);
void addVertax(size_t v);
void removeVertax(size_t v);
Digraph reverse() const;

vector<size_t> adj(size_t v) const;
void showAdj(size_t v) const;
void showDigraph() const;

size_t edge() const { return edges; }
size_t vertax() const { return vertaxs; }
size_t arrSize() const { return arr.size(); }

private:
vector<vector<size_t>> arr; // 邻接表
size_t vertaxs; // 顶点个数
size_t edges; // 边的个数
};

/// 使用深度优先遍历测试有向图的可达性
class DirectedDFS
{
public:
DirectedDFS(const Digraph &graph, size_t _start) : marked(graph.arrSize()), start(_start)
{
for (size_t i = 0; i < graph.arrSize(); i++)
marked[i] = false;
dfs(graph, start);
}

/// 节点v是可达的吗?起点start
bool isDirected(size_t v) const { return (v < marked.size()) ? marked[v] : false; }

private:
void dfs(const Digraph &graph, size_t v)
{
marked[v] = true;

vector<size_t> vec = graph.adj(v);
for (size_t i = 0; i < vec.size(); i++)
{
if (!marked[vec[i]])
dfs(graph, vec[i]);
}
}

vector<bool> marked;
size_t start; // 起点
};

int main(void)
{
Digraph graph(5);

graph.addEdge(0, 1);
graph.addEdge(0, 2);
graph.addEdge(1, 3);
graph.addEdge(2, 3);
//graph.addEdge(3, 4);
graph.addEdge(4, 2);

cout << graph.vertax() << endl;
cout << graph.edge() << endl;
graph.showDigraph();
cout << endl;

DirectedDFS dir(graph, 0);

cout << "0 -> 3: ";
if (dir.isDirected(3))
cout << "true" << endl;
else
cout << "false" << endl;

cout << "0 -> 4: ";
if (dir.isDirected(4))
cout << "true" << endl;
else
cout << "false" << endl;

system("pause");
return 0;
}

void Digraph::addEdge(size_t a, size_t b)
{
if (!(a < vertax() && b < vertax()))
return;
arr[a].push_back(b);
edges++;
}

void Digraph::removeEdge(size_t a, size_t b)
{
if (!(a < vertax() && b < vertax()))
return;

vector<size_t>::iterator iter = find(arr[a].begin(), arr[a].end(), b);
if (iter != arr[a].end())
{
arr[a].erase(iter);
edges--;
}
}

void Digraph::addVertax(size_t v)
{
if (v != arrSize())
return;
arr.push_back(vector<size_t>());
vertaxs++;
}

void Digraph::removeVertax(size_t v)
{
if (v >= arrSize())
return;
vector<size_t>::iterator iter;

for (size_t i = 0; i < arrSize(); i++)
{
if (i == v)
{
edges -= arr[i].size(); // 减去头部是v的边的个数
arr[i].clear();
vertaxs--;
}
else
{
iter = find(arr[i].begin(), arr[i].end(), v);
if (iter != arr[i].end())
{
arr[i].erase(iter);
edges--;
}
}
}
}

Digraph Digraph::reverse() const
{
Digraph graph(vertax());
vector<size_t> vec;

for (size_t i = 0; i < arrSize(); i++)
{
vec = adj(i);
for (size_t j = 0; j < vec.size(); j++)
{
graph.addEdge(vec[j], i); // 取得该图的反向图
}
}

return graph;
}

vector<size_t> Digraph::adj(size_t v) const
{
if (v < arrSize())
return arr[v];
else
vector<size_t>();
}

void Digraph::showAdj(size_t v) const
{
if (v >= arrSize())
return;

vector<size_t> vec = adj(v);
for (size_t i = 0; i < vec.size(); i++)
cout << vec[i] << " ";
cout << endl;
}

void Digraph::showDigraph() const
{
for (size_t i = 0; i < arr.size(); i++)
{
cout << i << ": ";
showAdj(i);
}
}

参考资料
        1、https://github.com/luoxn28/algorithm_data_structure (graph文件夹下有常用的关于图的各种算法)

        2、《算法 第4版》中关于图的章节
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息