注意stringstream 类的使用 完成string到int的类型转化
先clear再str("")实现重复使用
typename Graph
稀疏图的邻接表实现
#pragma once
#include <iostream>
#include<cassert>
#include<vector>
using namespace std;
class SparseGraph
{
private:
int n, m;//点的个数和边的个数
bool isdirected;//是否是有向图
vector<vector<int>> g;//存储INT类型变量 点
public:
SparseGraph(int n, bool isdirected)
{
this->isdirected = isdirected;
this->n = n;
g.resize(n);//和下一句作用一样
/*for (int i=0;i<n;i++)
{
g.push_back(vector<int>());//vector的构造函数 尺寸为n 值为false
}*/
}
~SparseGraph()
{}
int V() { return n; }//返回顶点数
int E() { return m; }//返回边的数
void addEdge(int p, int q)
{
assert(p >= 0 && p < n);
assert(q >= 0 && q < n);
//if (hasEdge(p, q))return;//不考虑边重复的问题
g[p].push_back(q);
if (!isdirected&&p!=q)//无向图 p q不能相等 否则就增加了两次同一条边
g[q].push_back(p);
m++;//边数目增加
}
bool hasEdge(int p, int q)//p->q的类型
{
assert(p >= 0 && p < n);
assert(q >= 0 && q < n);
for (int i = 0;i < g[p].size();i++)
{
if (g[p][i]==q)return true;
}
return false;
}
class adjIterator
{
private:
SparseGraph& graph;
int v;
int index;
public:
adjIterator(SparseGraph& gra, int v):graph(gra)//初始化列表
{
this->v = v;
index =-1;
}
~adjIterator(){}
int begin()
{
assert(v >= 0 && v < graph.g.size());
index = 0;
if (graph.g[v].size())
{
return graph.g[v][0];
}
return -1;
}
int next()
{
assert(v >= 0 && v < graph.g.size());
index++;
if (index < graph.g[v].size())
{
return graph.g[v][index];
}
return -1;
}
bool end()
{
return (index >= graph.g[v].size());
}
};
void show()
{
for (int i = 0;i < n;i++)
{
cout << i << ":";
for (int j = 0;j < g[i].size();j++)
{
cout << g[i][j] << " ";
}
cout << endl;
}
cout << endl;
}
};
稠密图的邻接矩阵实现
#pragma once
#include <iostream>
#include<cassert>
#include<vector>
using namespace std;
class DenseGraph
{
private:
int n, m;//点的个数和边的个数
bool isdirected;
vector<vector<bool>> g;
public:
DenseGraph(int n,bool isdirected)
{
this->isdirected = isdirected;
this->n = n;
//g.resize(n);
for (int i=0;i<n;i++)
{
g.push_back(vector<bool>(n, false));//vector的构造函数 尺寸为n 值为false
}
}
~DenseGraph()
{}
int V() { return n; }//返回顶点数
int E() { return m; }//返回边的数
void addEdge(int p, int q)
{
if (hasEdge(p, q))return;//如果有就直接返回 不用进行之下的步骤了 避免重复添加count
g[p][q] = true;
if (!isdirected)//无向图
g[q][p] = true;
m++;//边数目增加
}
bool hasEdge(int p, int q)
{
assert(p >= 0 && p < n);
assert(q >= 0 && q < n);
return g[p][q];
}
class adjIterator
{
private:
DenseGraph& graph;
int v;
int index;
public:
adjIterator(DenseGraph& gra, int v) :graph(gra)
{
assert(v >= 0 && v < graph.g[v].size());
this->v = v;
this->index = 0;
}
~adjIterator(){}
int begin()
{
int i;
for ( i = 0;i < graph.g[v].size();i++)
{
if (graph.g[v][i] == true)break;
}
index = i;
return index;
}
int begin2()
{
index = -1;
return next2();//非常机智啊 可以直接调用next
}
int next()
{
int i;
for (i = index + 1;i < graph.g[v].size();i++)
{
if (graph.g[v][i] == true)break;
}
index = i;
if (i == graph.g[v].size())return -1;
return index;
}
int next2()
{
for (index++;index < graph.V();index++)//不用其他变量 直接用index
{
if (graph.g[v][index] == true)return index;//直接返回 找到了就提前返回 不用判断是否没找到了
}
//此时index=graph.V();
return -1;
}
bool end()
{
return (index >= graph.g[v].size());
}
};
void show()
{
for (int i = 0;i < n;i++)
{
cout << i << ":";
for (int j = 0;j < n;j++)
{
cout << g[i][j] << " ";
}
cout << endl;
}
cout << endl;
}
};
模板类实现各种类型图的测试
从文件中读取图
#pragma once
#include <iostream>
#include<cassert>
#include<fstream>
#include<string>
#include<vector>
#include<sstream>
using namespace std;
template <typename Graph>
class ReadGraph
{
public:
ReadGraph(const string &filename, Graph &graph)//构造函数
{
ifstream infile(filename);
string line;
int V, E;
assert(infile.is_open());//确认打开
assert(getline(infile, line));
stringstream outstring;//构造函数 stringstream的用法
outstring << line;
outstring >> V >> E;
outstring.clear();
outstring.str("");
int v, w;
assert(graph.V() == V);
for (int i = 0;i < E;i++)
{
assert(getline(infile, line));
//outstring.str(line);
//stringstream outstring(line);
outstring << line;
outstring >> v >> w;
outstring.clear();
outstring.str("");
graph.addEdge(v, w);
}
}
};
深度优先搜索遍历
#pragma once
#include <iostream>
#include<cassert>
#include<fstream>
#include<string>
#include<vector>
#include<sstream>
using namespace std;
template <typename Graph>
class Component
{
private:
Graph& graph;
bool* visited;//是否访问
int ccount;//一共多少联通分量 组
int* id;//属于第几个联通分量 用于计算
void dfs(int p)
{
visited[p] = true;
id[p] = ccount;
typename Graph::adjIterator iter(graph,p);//修改 加template
for (int w = iter.begin();!iter.end();w = iter.next())
{
if (!visited[w])
{
dfs(w);
}
}
}
public:
Component(Graph& graph) :graph(graph)
{
ccount = 0;
int n = graph.V();
visited = new bool[n];
id = new int[n];
for (int i = 0;i < n;i++)
{
visited[i] = false;//初始化
id[i] = -1;
}
for (int i = 0;i < n;i++)
{
if (!visited[i])//没有被访问过
{
dfs(i);
ccount++;//更新一个新的组
}
}
}
~Component()
{
delete[] visited;
delete[] id;
ccount = 0;
}
int count()
{
return ccount;
}
bool isConnected(int p,int q)
{
return id[p] == id[q];
}
};
深度优先搜索遍历并输出查询路径
count遍历是自己加的用来计算是否有环
#pragma once
#include <iostream>
#include<cassert>
#include<fstream>
#include<string>
#include<vector>
#include<sstream>
#include<stack>
using namespace std;
//有向图依然有效
template <typename Graph>
class Path
{
private:
Graph& graph;
bool* visited;
int* from;
int p;
int ccount;
void dfs(int num)
{
visited[num] = true;
typename Graph::adjIterator iter(graph, num);//注意语法
for (int w = iter.begin();!iter.end();w = iter.next())
{
if (visited[w] && from[num] != w)
{ ccount++; }
if (!visited[w])//如果没有访问过
{
from[w] = num;
dfs(w);
}
}
}
public:
Path(Graph& g, int p) :graph(g)
{
ccount == 0;
this->p = p;
int n = graph.V();
assert(p >= 0 && p < n);
visited = new bool[n];
from = new int[n];
for (int i = 0;i < graph.V();i++)
{
visited[i] = false;
from[i] = -1;
}
dfs(p);
}
~Path()
{
delete[] from;
delete[] visited;
}
bool hasPath(int w)
{
assert(w >= 0 && w < graph.V());
return visited[w];//被访问过说明有路径
}
void path(int w, vector<int>& vec)
{
assert(w >= 0 && w < graph.V());
stack<int> sta;
sta.push(w);
while (from[w] >= 0)
{
sta.push(from[w]);
w = from[w];
}
/*while (w != -1)
{
sta.push(w);
w = from[w];
}*/
vec.clear();
while (!sta.empty())
{
vec.push_back(sta.top());
sta.pop();
}
}
void showPath(int p)
{
vector<int> vec;
path(p, vec);
cout << "path:";
for (int i = 0;i < vec.size();i++)
{
cout << vec[i];
if (i == vec.size() - 1)
{
cout << endl;
break;
}
cout << "->";
}
}
//int circount() { return ccount/2; }
};
广度优先搜索实现图的遍历和路径表示
#pragma once
#include <iostream>
#include<cassert>
#include<fstream>
#include<string>
#include<vector>
#include<sstream>
#include<stack>
#include<queue>
using namespace std;
//有向图依然有效
template <typename Graph>
class ShortPath
{
private:
Graph& graph;
bool* visited;
int* from;
int p;
int* length;//距离根节点的距离
public:
ShortPath(Graph& g, int p) :graph(g)
{
//ccount == 0;
this->p = p;
int n = graph.V();
assert(p >= 0 && p < n);
visited = new bool[n];
from = new int[n];
length = new int[n];
for (int i = 0;i < graph.V();i++)
{
visited[i] = false;
from[i] = -1;
length[i] = -1;
}
queue<int> q;
q.push(p);
visited[p] = true;
length[p] = 0;
while (!q.empty())
{
int tmp = q.front();
q.pop();
typename Graph::adjIterator iter(graph, tmp);
for (int w = iter.begin();!iter.end();w = iter.next())
{
if (!visited[w])//记得 没有visited的才遍历
{
q.push(w);
visited[w] = true;
from[w] = tmp;
length[w] = length[tmp] + 1;
}
}
}
}
~ShortPath()
{
delete[] length;
delete[] from;
delete[] visited;
}
bool hasPath(int w)
{
assert(w >= 0 && w < graph.V());
return visited[w];//被访问过说明有路径
}
void path(int w, vector<int>& vec)
{
assert(w >= 0 && w < graph.V());
stack<int> sta;
sta.push(w);
while (from[w] >= 0)
{
sta.push(from[w]);
w = from[w];
}
/*while (w != -1)
{
sta.push(w);
w = from[w];
}*/
vec.clear();
while (!sta.empty())
{
vec.push_back(sta.top());
sta.pop();
}
}
void showPath(int p)
{
vector<int> vec;
path(p, vec);
cout << "path:";
for (int i = 0;i < vec.size();i++)
{
cout << vec[i];
if (i == vec.size() - 1)
{
cout << endl;
break;
}
cout << "->";
}
}
int rlength(int w) {
assert(w >= 0 && w < graph.V());
return length[w];
}
};
测试函数
#include <iostream>
#include<cassert>
#include<vector>
#include<ctime>
#include"ReadGraph.h"
#include"DenseGraph.h"
#include"SparseGraph.h"
#include"DFS.h"
#include"path.h"
#include"ShortPath.h"
using namespace std;
int main()
{
SparseGraph sGraph(7, false);
DenseGraph dGraph(7, false);
string filename1 = "testG2.txt";
ReadGraph<SparseGraph> read(filename1, sGraph);
sGraph.show();
ShortPath<SparseGraph> path1(sGraph, 0);
path1.showPath(3);
//cout << path1.circount() << endl;
ReadGraph<DenseGraph> read2(filename1, dGraph);
dGraph.show();
//生成随机的图/
int N, M;
N = 20;
M = 100;
srand(time(NULL));
SparseGraph sgraph(N, false);
DenseGraph dgraph(N, false);
for (int i = 0;i < M;i++)
{
int p = rand() % N;
int q = rand() % N;
sgraph.addEdge(p, q);
dgraph.addEdge(p, q);
}
for (int v = 0;v < N;v++)
{
cout << v << ":";
SparseGraph::adjIterator iter(sgraph,v);
int w=iter.begin();
bool t = iter.end();
for ( w = iter.begin();!iter.end();w = iter.next())
{
cout << w << " ";
}
cout << endl;
}
for (int v = 0;v < N;v++)
{
cout << v << ":";
DenseGraph::adjIterator iter(dgraph, v);
for (int w = iter.begin();!iter.end();w = iter.next())
{
cout << w << " ";
}
cout << endl;
}
return 0;
}