1. 程式人生 > 其它 >2021-1 從檔案構建有向圖API 測試單點和多點可達 c++實現

2021-1 從檔案構建有向圖API 測試單點和多點可達 c++實現

技術標籤:日常練習有向圖c++

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;
}