@CrazyHenry
2018-03-15T04:12:23.000000Z
字数 10616
阅读 1221
dddd数据结构课本
- Author:李英民 | Henry
- E-mail: li
_yingmin@outlookdotcom- Home: https://liyingmin.wixsite.com/henry
快速了解我: About Me
转载请保留上述引用内容,谢谢配合!
#include <iostream>#include <vector>#include <cassert>using namespace std;// 稠密图 - 邻接矩阵class DenseGraph{private:int n, m; // 节点数和边数bool directed; // 是否为有向图vector<vector<bool>> g; // 图的具体数据public:// 构造函数DenseGraph( int n , bool directed ): g(n, vector<bool>(n, false)),n(n),m(0),directed(directed){}~DenseGraph(){}int V(){ return n;} // 返回节点个数int E(){ return m;} // 返回边的个数// 向图中添加一个边void addEdge( int v , int w ){assert( v >= 0 && v < n );assert( w >= 0 && w < n );if(v != w)//自环边避免{if( hasEdge( v , w ) )return; //去除平行边g[v][w] = true;if( !directed )g[w][v] = true;++m;//无向图中有连接的边只算一条}}// 验证图中是否有从v到w的边bool hasEdge( int v , int w ){ //O(1)来判断是否有连接return g[v][w];}};
#include <iostream>#include <vector>#include <cassert>using namespace std;// 稀疏图 - 邻接表class SparseGraph{private:int n, m; // 节点数和边数bool directed; // 是否为有向图vector<vector<int>> g; // 图的具体数据public:// 构造函数SparseGraph( int n , bool directed ): n(n),m(0),directed(directed),g(n, vector<int>()){}~SparseGraph(){}int V(){ return n;} // 返回节点个数int E(){ return m;} // 返回边的个数// 向图中添加一个边void addEdge( int v, int w ){assert( v >= 0 && v < n );assert( w >= 0 && w < n );if(v != w){g[v].push_back(w);if(!directed )g[w].push_back(v);++m;}}// 验证图中是否有从v到w的边bool hasEdge( int v , int w ){ //O(n)的复杂度,因此一般不判断平行边assert( v >= 0 && v < n );assert( w >= 0 && w < n );for( int i = 0 ; i != g[v].size() ; ++i )if( g[v][i] == w )return true;return false;}};
#include <iostream>#include <vector>#include <cassert>using namespace std;// 稀疏图 - 邻接表class SparseGraph{private:int n, m; // 节点数和边数bool directed; // 是否为有向图vector<vector<int>> g; // 图的具体数据public:// 构造函数SparseGraph( int n , bool directed ): n(n),m(0),directed(directed),g(n, vector<int>()){}~SparseGraph(){}int V(){ return n;} // 返回节点个数int E(){ return m;} // 返回边的个数// 向图中添加一个边void addEdge( int v, int w ){assert( v >= 0 && v < n );assert( w >= 0 && w < n );if(v != w){g[v].push_back(w);if(!directed )g[w].push_back(v);++m;}}// 验证图中是否有从v到w的边bool hasEdge( int v , int w ){ //O(n)的复杂度,因此一般不判断平行边assert( v >= 0 && v < n );assert( w >= 0 && w < n );for( int i = 0 ; i != g[v].size() ; ++i )if( g[v][i] == w )return true;return false;}// 邻边迭代器, 传入一个图和一个顶点,// 迭代在这个图中和这个顶点向连的所有顶点class adjIterator{private:SparseGraph &G; // 图G的引用int v;int index;public:// 构造函数adjIterator(SparseGraph &graph, int v): G(graph),v(v),index(0){}~adjIterator(){}// 返回图G中与顶点v相连接的第一个顶点int begin(){index = 0;if( G.g[v].size() )return G.g[v][index];// 若没有顶点和v相连接, 则返回-1return -1;}// 返回图G中与顶点v相连接的下一个顶点int next(){++index;if( index < G.g[v].size() )return G.g[v][index];// 若没有顶点和v相连接, 则返回-1return -1;}// 查看是否已经迭代完了图G中与顶点v相连接的所有顶点bool end(){return index >= G.g[v].size();}};};
//main.cpp#include <iostream>#include "SparseGraph.h"#include "DenseGraph.h"using namespace std;int main() {int N = 20;int M = 100;srand( time(NULL) );// Sparse GraphSparseGraph g1(N , false);for( int i = 0 ; i < M ; i ++ ){int a = rand()%N;int b = rand()%N;g1.addEdge( a , b );}// O(E)for( int v = 0 ; v < N ; v ++ ){cout<<v<<" : ";SparseGraph::adjIterator adj( g1 , v );for( int w = adj.begin() ; !adj.end() ; w = adj.next() )cout<<w<<" ";cout<<endl;}cout<<endl;// Dense GraphDenseGraph g2(N , false);for( int i = 0 ; i < M ; i ++ ){int a = rand()%N;int b = rand()%N;g2.addEdge( a , b );}// O(V^2)for( int v = 0 ; v < N ; v ++ ){cout<<v<<" : ";DenseGraph::adjIterator adj( g2 , v );for( int w = adj.begin() ; !adj.end() ; w = adj.next() )cout<<w<<" ";cout<<endl;}return 0;}
// 邻边迭代器, 传入一个图和一个顶点,// 迭代在这个图中和这个顶点向连的所有顶点class adjIterator{private:DenseGraph &G; // 图G的引用int v;int index;public:// 构造函数adjIterator(DenseGraph &graph, int v): G(graph),v(v),index(-1){}// 索引从-1开始, 因为每次遍历都需要调用一次next()~adjIterator(){}// 返回图G中与顶点v相连接的第一个顶点int begin(){// 索引从-1开始, 因为每次遍历都需要调用一次next()index = -1;return next();}// 返回图G中与顶点v相连接的下一个顶点int next(){// 从当前index开始向后搜索, 直到找到一个g[v][index]为truefor( index += 1 ; index < G.V() ; ++index )if( G.g[v][index] )return index;// 若没有顶点和v相连接, 则返回-1return -1;}// 查看是否已经迭代完了图G中与顶点v相连接的所有顶点bool end(){return index >= G.V();}};
//main.cpp#include <iostream>#include "SparseGraph.h"#include "DenseGraph.h"using namespace std;int main() {int N = 20;int M = 100;srand( time(NULL) );// Sparse GraphSparseGraph g1(N , false);for( int i = 0 ; i < M ; i ++ ){int a = rand()%N;int b = rand()%N;g1.addEdge( a , b );}// O(E)for( int v = 0 ; v < N ; v ++ ){cout<<v<<" : ";SparseGraph::adjIterator adj( g1 , v );for( int w = adj.begin() ; !adj.end() ; w = adj.next() )cout<<w<<" ";cout<<endl;}cout<<endl;// Dense GraphDenseGraph g2(N , false);for( int i = 0 ; i < M ; i ++ ){int a = rand()%N;int b = rand()%N;g2.addEdge( a , b );}// O(V^2)for( int v = 0 ; v < N ; v ++ ){cout<<v<<" : ";DenseGraph::adjIterator adj( g2 , v );for( int w = adj.begin() ; !adj.end() ; w = adj.next() )cout<<w<<" ";cout<<endl;}return 0;}
#include <iostream>#include <string>#include <fstream>#include <sstream>#include <cassert>using namespace std;// 读取图算法template <typename Graph> //表示SparseGraph或者DenseGraphclass ReadGraph{public:// 从文件filename中读取图的信息, 存储进图graph中ReadGraph(Graph &graph, const string &filename){ifstream file(filename);string line;int V, E;assert( file.is_open() );// 第一行读取图中的节点个数和边的个数assert( getline(file, line) );stringstream ss(line);ss>>V>>E;assert( V == graph.V() ); //建立Graph对象时给定了V,判断是否一致// 读取每一条边的信息for( int i = 0 ; i < E ; i ++ ){assert( getline(file, line) );stringstream ss(line);int a,b;ss>>a>>b;assert( a >= 0 && a < V );assert( b >= 0 && b < V );graph.addEdge( a , b );}}};
//打印DenseGraphvoid show(){for( int i = 0 ; i < n ; i ++ ){for( int j = 0 ; j < n ; j ++ )cout<<g[i][j]<<"\t";cout<<endl;}}
//打印SparseGraph// 显示图的信息void show(){for( int i = 0 ; i < n ; i ++ ){cout<<"vertex "<<i<<":\t";for( int j = 0 ; j < g[i].size() ; j ++ )cout<<g[i][j]<<"\t";cout<<endl;}}
//main.cpp#include <iostream>#include "SparseGraph.h"#include "DenseGraph.h"#include "ReadGraph.h"using namespace std;// 测试通过文件读取图的信息int main() {// 使用两种图的存储方式读取testG1.txt文件string filename = "testG1.txt";SparseGraph g1( 13 , false );ReadGraph<SparseGraph> readGraph1( g1 , filename );cout<<"test G1 in Sparse Graph:" << endl;g1.show();cout<<endl;DenseGraph g2( 13 , false );ReadGraph<DenseGraph> readGraph2( g2 , filename );cout<<"test G1 in Dense Graph:" << endl;g2.show();cout<<endl;// 使用两种图的存储方式读取testG2.txt文件filename = "testG2.txt";SparseGraph g3( 6 , false );ReadGraph<SparseGraph> readGraph3( g3 , filename );cout<<"test G2 in Sparse Graph:" << endl;g3.show();cout<<endl;DenseGraph g4( 6 , false );ReadGraph<DenseGraph> readGraph4( g4 , filename );cout<<"test G2 in Dense Graph:" << endl;g4.show();return 0;}
#include <iostream>#include <cassert>using namespace std;// 求无权图的联通分量template <typename Graph>class Component{private:Graph &G; // 图的引用bool *visited; // 记录dfs的过程中节点是否被访问int ccount; // 记录联通分量个数int *id; // 每个节点所对应的联通分量标记// 图的深度优先遍历void dfs( int v ){visited[v] = true;id[v] = ccount;typename Graph::adjIterator adj(G, v);for( int i = adj.begin() ; !adj.end() ; i = adj.next() ){if( !visited[i] )dfs(i);//i为顶点的下标}}public:// 构造函数, 求出无权图的联通分量Component(Graph &graph): G(graph){// 算法初始化visited = new bool[G.V()]{};id = new int[G.V()]{};ccount = 0;for( int i = 0 ; i < G.V() ; ++i ){visited[i] = false;id[i] = -1;}// 求图的联通分量for( int i = 0 ; i < G.V() ; ++i )if( !visited[i] ){dfs(i);++ccount;}}// 析构函数~Component(){delete[] visited;delete[] id;}// 返回图的联通分量个数int count(){return ccount;}// 查询点v和点w是否联通bool isConnected( int v , int w ){assert( v >= 0 && v < G.V() );assert( w >= 0 && w < G.V() );return id[v] == id[w];}};#include <iostream>#include "SparseGraph.h"#include "DenseGraph.h"#include "ReadGraph.h"#include "Components.h"using namespace std;// 测试图的联通分量算法int main() {// TestG1.txtstring filename1 = "testG1.txt";SparseGraph g1 = SparseGraph(13, false);ReadGraph<SparseGraph> readGraph1(g1, filename1);Component<SparseGraph> component1(g1);cout<<"TestG1.txt, Component Count: "<<component1.count()<<endl;cout<<endl;// TestG2.txtstring filename2 = "testG2.txt";SparseGraph g2 = SparseGraph(7, false);ReadGraph<SparseGraph> readGraph2(g2, filename2);Component<SparseGraph> component2(g2);cout<<"TestG2.txt, Component Count: "<<component2.count()<<endl;return 0;}
#include <vector>#include <stack>#include <iostream>#include <cassert>using namespace std;// 路径查询template <typename Graph>class Path{private:Graph &G; // 图的引用int s; // 起始点bool* visited; // 记录dfs的过程中节点是否被访问int * from; // 记录路径, from[i]表示查找的路径上i的上一个节点// 图的深度优先遍历void dfs( int v ){visited[v] = true;typename Graph::adjIterator adj(G, v);for( int i = adj.begin() ; !adj.end() ; i = adj.next() ){if( !visited[i] ){from[i] = v;dfs(i);}}}public:// 构造函数, 寻路算法, 寻找图graph从s点到其他点的路径Path(Graph &graph, int s):G(graph){// 算法初始化assert( s >= 0 && s < G.V() );visited = new bool[G.V()];from = new int[G.V()];for( int i = 0 ; i < G.V() ; i ++ ){visited[i] = false;from[i] = -1;}this->s = s;// 寻路算法dfs(s);}// 析构函数~Path(){delete [] visited;delete [] from;}// 查询从s点到w点是否有路径bool hasPath(int w){assert( w >= 0 && w < G.V() );return visited[w];}// 查询从s点到w点的路径, 存放在vec中void path(int w, vector<int> &vec){assert( hasPath(w) );stack<int> s;// 通过from数组逆向查找到从s到w的路径, 存放到栈中int p = w;while( p != -1 ){s.push(p);p = from[p];}// 从栈中依次取出元素, 获得顺序的从s到w的路径vec.clear();while( !s.empty() ){vec.push_back( s.top() );s.pop();}}// 打印出从s点到w点的路径void showPath(int w){assert( hasPath(w) );vector<int> vec;path( w , vec );for( int i = 0 ; i < vec.size() ; i ++ ){cout<<vec[i];if( i == vec.size() - 1 )cout<<endl;elsecout<<" -> ";}}};//main#include <iostream>#include "SparseGraph.h"#include "DenseGraph.h"#include "ReadGraph.h"#include "Path.h"using namespace std;// 测试寻路算法int main() {string filename = "testG.txt";SparseGraph g = SparseGraph(7, false);ReadGraph<SparseGraph> readGraph(g, filename);g.show();cout<<endl;Path<SparseGraph> path(g,0);cout<<"Path from 0 to 6 : " << endl;path.showPath(6);return 0;}
// 寻找无权图的最短路径template <typename Graph>class ShortestPath{private:Graph &G; // 图的引用int s; // 起始点bool *visited; // 记录dfs的过程中节点是否被访问int *from; // 记录路径, from[i]表示查找的路径上i的上一个节点int *ord; // 记录路径中节点的次序。ord[i]表示i节点在路径中的次序。public:// 构造函数, 寻找无权图graph从s点到其他点的最短路径ShortestPath(Graph &graph, int s):G(graph){// 算法初始化assert( s >= 0 && s < graph.V() );visited = new bool[graph.V()];from = new int[graph.V()];ord = new int[graph.V()];for( int i = 0 ; i < graph.V() ; i ++ ){visited[i] = false;from[i] = -1;ord[i] = -1;}this->s = s;// 无向图最短路径算法, 从s开始广度优先遍历整张图queue<int> q;q.push( s );visited[s] = true;ord[s] = 0;while( !q.empty() ){int v = q.front();q.pop();typename Graph::adjIterator adj(G, v);for( int i = adj.begin() ; !adj.end() ; i = adj.next() )if( !visited[i] ){q.push(i);visited[i] = true;from[i] = v;ord[i] = ord[v] + 1;}}}// 析构函数~ShortestPath(){delete [] visited;delete [] from;delete [] ord;}// 查询从s点到w点是否有路径bool hasPath(int w){assert( w >= 0 && w < G.V() );return visited[w];}// 查询从s点到w点的路径, 存放在vec中void path(int w, vector<int> &vec){assert( w >= 0 && w < G.V() );stack<int> s;// 通过from数组逆向查找到从s到w的路径, 存放到栈中int p = w;while( p != -1 ){s.push(p);p = from[p];}// 从栈中依次取出元素, 获得顺序的从s到w的路径vec.clear();while( !s.empty() ){vec.push_back( s.top() );s.pop();}}// 打印出从s点到w点的路径void showPath(int w){assert( w >= 0 && w < G.V() );vector<int> vec;path(w, vec);for( int i = 0 ; i < vec.size() ; i ++ ){cout<<vec[i];if( i == vec.size()-1 )cout<<endl;elsecout<<" -> ";}}// 查看从s点到w点的最短路径长度int length(int w){assert( w >= 0 && w < G.V() );return ord[w];}};//main#include <iostream>#include "SparseGraph.h"#include "DenseGraph.h"#include "ReadGraph.h"#include "Path.h"#include "ShortestPath.h"using namespace std;// 测试无权图最短路径算法int main() {string filename = "testG.txt";SparseGraph g = SparseGraph(7, false);ReadGraph<SparseGraph> readGraph(g, filename);g.show();cout<<endl;// 比较使用深度优先遍历和广度优先遍历获得路径的不同// 广度优先遍历获得的是无权图的最短路径Path<SparseGraph> dfs(g,0);cout<<"DFS : ";dfs.showPath(6);ShortestPath<SparseGraph> bfs(g,0);cout<<"BFS : ";bfs.showPath(6);return 0;}