数据结构遍历的意义
树的遍历
图的遍历
树的前序遍历
图遍历和树遍历区别
知识回顾
树的深度优先遍历
普通函数和递归函数调用的区别
图的深度优先遍历的过程
初始visited数组都是fasle,当从顶点0开始调用时, 如果没有被遍历,那么遍历结果列表中添加这个顶点,然后开始for循环,执行dfs(1)
DFS的改进
如果是如下的图结构
对应的txt
7 6
0 1
0 2
1 3
1 4
2 3
2 6
执行dfs之后我们发现 顶点5并没有被遍历,这是因为我们dfs是从0开始的
只调用一次, 5和其他顶点并没有联通, 所以应该执行dfs(5)
图的DFS的典型应用, 求联通分量的个数
#include <iostream>
#include <cassert>
#include "ReadGraph.h"
#include "SparseGraph.h"
#include "DenseGraph.h"
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);
}
}
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;
}
// 求图的联通分量
// dfs(0);
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];
}
};
// 测试图的联通分量算法
int main (){
string filename = "/Users/ericli/CLionProjects/lijunshi/day14/testG1.txt";
SparseGraph g1(13, false);
ReadGraph<SparseGraph> readGraph1(g1, filename);
Component<SparseGraph> component1(g1);
cout<< "------" <<endl;
cout<< "testG1 component1 count = "<<component1.count()<<endl;
cout<< "------" <<endl;
DenseGraph g2(13, false);
ReadGraph<DenseGraph> readGraph2(g2, filename);
Component<DenseGraph> component2(g2);
cout<< "------" <<endl;
cout<< "testG2 component2 count = "<<component2.count()<<endl;
cout<< "------" <<endl;
// 使用两种图的存储方式读取testG2.txt文件
filename = "/Users/ericli/CLionProjects/lijunshi/day13/testG2.txt";
SparseGraph g3(6, false);
ReadGraph<SparseGraph> readGraph3(g3, filename);
Component<SparseGraph> component3(g3);
cout<< "------" <<endl;
cout<< "testG2 component3 count = "<<component3.count()<<endl;
cout<< "------" <<endl;
DenseGraph g4(6, false);
ReadGraph<DenseGraph> readGraph4(g4, filename);
Component<DenseGraph> component4(g4);
cout<< "------" <<endl;
cout<< "testG2 component4 count="<<component4.count()<<endl;
cout<< "------" <<endl;
return 0;
}
路径查询
新建Path.cpp
#include <iostream>
#include <vector>
#include <stack>
#include "ReadGraph.h"
#include "SparseGraph.h"
#include "DenseGraph.h"
using namespace std;
// 路径查询
template<typename Graph>
class Path {
private:
Graph &G; // 图的引用
bool *visited; // 记录dfs的过程中节点是否被访问
int s; // 起始点
int *from; // 记录路径, from[i]表示查找的路径上i的上一个节点
// [1, 2, 5] from[2] 代表 5 是从2点过来的
// 图的深度优先遍历
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;
else
cout << " ->";
}
}
};
int main() {
string filename = "/Users/ericli/CLionProjects/lijunshi/day14/testG2.txt";
SparseGraph g(6, false);
ReadGraph <SparseGraph> readGraph(g, filename);
g.show();
Path<SparseGraph> path(g, 0);
path.showPath(5);
//
return 0;
}