API
和无向图Graph.h比较,只改动了几个地方,一个翻转图,添加边时只是单向添加。
一个改动
返回整个list<int>
可能导致Stack Overflow
,索性只返回一个指向堆的指针。另外,用一个宏定义简化书写。
//原来是
list<int> adj(int v){
return *((*m_adj)[v]);
}
//可以这样调用邻接点
for(auto &next : G.adj(v)){
.....next; }
//现在改为返回指针
ListPtr Digraph::adj(int v)
{
return (m_adj->at(v));
}
//这样调用
for(auto &next: *G.adj(v)){
next.....;
}
//或者调用
ListPtr p=G.adj(v);
for(auto it=p->begin();it!=p->end();++it){
.......(*it);
}
//如果设计一个宏定义
#define forIt(ListPtr) for(auto it=ListPtr->begin();it!=ListPtr->end();++it)
//最后这样写
forIt(G.adj(v)){
........(*it)....;
}
代码
//Digraph.h
#pragma once
#include<iostream>
#include<list>
#include<vector>
#include<fstream>
using namespace std;
#define out(x) cout<<x<<" "
#define hh printf_s("\n")
#define forIt(ListPtr) for(auto it=ListPtr->begin();it!=ListPtr->end();++it)
/*******************如无必要,勿增实体************************/
typedef list<int>* ListPtr;
class Digraph
{
public:
Digraph(int V);
Digraph(string file);
void addEdge(int v, int w);
ListPtr adj(int v);
int V() {
return m_V; }
int E() {
return m_E; }
Digraph& reverse();//在堆上开辟,返回引用避免复制
string toString();
private:
int m_V=0;
int m_E=0;
vector<ListPtr>* m_adj=nullptr;
void initGraph(int V);
bool isParallel_edges_self_loop(int v, int w);
string intToStr(int n);
};
void testDigraph();
#include "Digraph.h"
Digraph::Digraph(int V)
{
m_V = V;
m_E = 0;
m_adj = new vector<ListPtr>(V, nullptr);
for (int i = 0; i < V; i++)
{
m_adj->at(i) = new list<int>(0);
}
}
Digraph::Digraph(string file)
{
ifstream in(file, ios::in);
if (!in) {
printf_s("file open error.");
return;
}
int V, E;
in >> V;
initGraph(V);
in >> E;//不一定等于最后的边数,因为可能不包含自环和平行边
int w, v;
for (int i = 0; i < E; i++)
{
in >> w >> v;
addEdge(w, v);
}
in.close();
}
void Digraph::addEdge(int v, int w)
{
//if (isParallel_edges_self_loop(v, w)) return;
(*m_adj)[v]->push_front(w);
m_E++;
}
ListPtr Digraph::adj(int v)
{
return (m_adj->at(v));
}
Digraph& Digraph::reverse()
{
Digraph* rG = new Digraph(m_V);
for (int i = 0; i < m_V; ++i) {
forIt(m_adj->at(i)) {
rG->addEdge(*it, i);
}
}
return *rG;
}
string Digraph::toString()
{
string s = intToStr(m_V) + " vertices, " + intToStr(m_E) + " edges\n";
for (int i = 0; i < m_V; i++)
{
s += intToStr(i) + ": ";
for (auto adj : *(m_adj->at(i)))
{
s += intToStr(adj) + " ";
}
s += "\n";
}
return s;
}
string
inline Digraph::intToStr(int n)
{
char int_s[20] = {
0 };//末尾加上'\0'
_itoa_s(n, int_s, 10);// 10 表示十进制
return string(int_s);
}
void
inline Digraph::initGraph(int V)
{
m_V = V;
m_E = 0;
m_adj = new vector<ListPtr>(V, nullptr);
for (int i = 0; i < V; i++)
{
m_adj->at(i) = new list<int>(0);
}
}
inline
bool Digraph::isParallel_edges_self_loop(int v, int w)
{
if (v == w) return true;
for (auto& n : *(m_adj->at(v))) {
if (n == w) {
return true;
}
}
return false;
}
void testDigraph()
{
Digraph dG("tinyDG.txt");
out(dG.toString()), hh;
Digraph rG=dG.reverse();
out(rG.toString()),hh;
}
tinyDG.txt
13
22
4 2
2 3
3 2
6 0
0 1
2 0
11 12
12 9
9 10
9 11
7 9
10 12
11 4
4 3
3 5
6 8
8 6
5 4
0 5
6 4
6 9
7 6
DFS搜索可达性
#pragma once
#include"Digraph.h"
class DirectedDFS
{
public:
DirectedDFS(Digraph& G,int s);//搜索单点可达
DirectedDFS(Digraph& G, list<int> sources);//标记多点可达的点
bool marked(int v);
private:
vector<bool>* m_marked = nullptr;
void dfs(Digraph& G, int s);
};
void testDFS();
#include "DirectedDFS.h"
DirectedDFS::DirectedDFS(Digraph& G, int s)
{
m_marked = new vector<bool>(G.V(), false);
dfs(G, s);
}
DirectedDFS::DirectedDFS(Digraph& G, list<int> sources)
{
m_marked = new vector<bool>(G.V(), false);
for (auto& s : sources) {
if (!m_marked->at(s)) {
dfs(G, s);
}
}
}
bool DirectedDFS::marked(int v)
{
return m_marked->at(v);
}
void DirectedDFS::dfs(Digraph& G, int s)
{
m_marked->at(s) = true;
forIt (G.adj(s)) {
if (!m_marked->at(*it)) {
dfs(G, *it);
}
}
}
void testDFS()
{
Digraph G("tinyDG.txt");
list<int> sources = {
2,6,8 };
DirectedDFS dfs(G, sources);
out("can reach :");
for (int i = 0; i < G.V(); ++i) {
if (dfs.marked(i)) {
out(i);
}
}
hh;
}