0. 概览
1. DFS
先从A->B->E->C
,再返回C->E->B->A->D
,但是要跳过搜索过的顶点,最后输出A->B->E->C->D
。
#include <iostream>
#include <stack>
using namespace std;
// 深度优先搜索算法
// 沿着顶点一直找,找到最后一个顶点,然后返回横向找, 不包括已经搜索过的点
// 使用堆栈更合适, 往回找时 先进后出FILO 后进先出LIFO
// 用邻接矩阵和stack
#define MAXVERTEX_NUMS 20
class Graph;
class Vertex
{
friend class Graph;
public:
Vertex(const char dt): data(dt) { }
private:
char data;
};
class Graph
{
public:
Graph()
: nVertex(0), vertexTable(new Vertex*[MAXVERTEX_NUMS]) // 初始化当前顶点个数 和 存放顶点的数组
{
for(int i=0; i<MAXVERTEX_NUMS; i++) // 初始化顶点状态
visitedV[i] = 0;
for(int i=0; i<MAXVERTEX_NUMS; i++) // 初始化adjacency matrix
for(int j=0; j<MAXVERTEX_NUMS; j++)
adjMat[i][j] = 0;
}
~Graph() { delete[] vertexTable; } // vertexTable中存放的不是new出来的Vertex, 所以只需delete数组即可
void addVertex(Vertex& v);
void addEdge(const Vertex& v1, const Vertex& v2);
void printVertex() const;
void printAdjMat() const;
void printDFS(); // ***********8重点是printDFS()****************
private:
Vertex** vertexTable; // 存放顶点
bool visitedV[MAXVERTEX_NUMS]; // 存放顶点是否被遍历的状态
bool adjMat[MAXVERTEX_NUMS][MAXVERTEX_NUMS]; // adjacency matrix
int nVertex; // 当前顶点个数
};
void Graph::addVertex(Vertex& v)
{
vertexTable[nVertex++] = &v;
}
void Graph::addEdge(const Vertex& v1, const Vertex& v2)
{
adjMat[v1.data-65][v2.data-65] = 1;
adjMat[v2.data-65][v1.data-65] = 1;
}
void Graph::printVertex() const
{
for(int i=0; i<nVertex; i++)
cout << vertexTable[i]->data << " ";
cout << endl;
}
void Graph::printAdjMat() const
{
for(int i=0; i<nVertex; i++)
{
for(int j=0; j<nVertex; j++)
cout << adjMat[i][j] << " ";
cout << endl;
}
}
// ----------------------------DFS---------------------------------------
void Graph::printDFS()
{
auto vnextUnvisited = [&](const Vertex* v)->int // 返回顶点在vertexTable中的位置
{
for(int i=0; i<nVertex; i++) // 搜索adjacency matrix的每一行
if(adjMat[v->data-65][i] && !visitedV[i]) // 如果给定顶点,在邻接表找到1 且 没被访问过
return vertexTable[i]->data - 65; // 返回该顶点对应表中的位置
return -1; // 如果没找到返回-1
};
stack<Vertex*> gStack; // 用stack存放 遍历过的 顶点
int i = 0; // 记录顶点在vertexTable中的索引
visitedV[i] = true; // 标记第一个顶点已被访问
cout << vertexTable[i]->data << " "; // 输出
gStack.push(vertexTable[i]); // 压入起点
while(!gStack.empty())
{
i = vnextUnvisited(gStack.top()); // 访问第下个顶点
if(i >= 0) // 存在
{
visitedV[i] = true; // 标记被访问
cout << vertexTable[i]->data << " "; // 输出
gStack.push(vertexTable[i]); // 压入
}
else // 没有下个顶点了
{
gStack.pop();
}
}
cout << endl;
for(int j=0; j<nVertex; j++) // 状态表置零 可以多次搜索
visitedV[j] = false;
}
// -----------------------------------------------------------------------
int main()
{
Vertex vA('A'); // 创建顶点
Vertex vB('B');
Vertex vC('C');
Vertex vD('D');
Vertex vE('E');
Graph G; // 创建图
G.addVertex(vA); // 添加顶点
G.addVertex(vB);
G.addVertex(vC);
G.addVertex(vD);
G.addVertex(vE);
G.addEdge(vA, vB); // 添加边
G.addEdge(vA, vD);
G.addEdge(vB, vE);
G.addEdge(vD, vE);
G.addEdge(vC, vE);
G.printVertex(); // 打印顶点
G.printAdjMat(); // 打印邻接矩阵
cout << "=============\n";
G.printDFS(); // 打印深度优先搜索结果
// output:
// A B C D E
// 0 1 0 1 0
// 1 0 0 0 1
// 0 0 0 0 1
// 1 0 0 0 1
// 0 1 1 1 0
// =============
// A B E C D
return 0;
}
2.BFS
先从A
开始,一层一层的搜索,A->B->D->E->C
。
#include <iostream>
#include <stack>
#include <queue>
using namespace std;
// 广(宽)度优先搜索算法 Breadth First Search
// 顶点周围找,找完继续找下一个顶点的周围
// 先把第一个顶点周围的 顶点放入队列, 然后依次取出顶点,继续放入周围的队列 (一层一层的搜索)
// 使用队列,, 先放入的顶点先搜索周围其他顶点, 先进先出FIFO
#define MAXVERTEX_NUMS 20
class Graph;
class Vertex
{
friend class Graph;
public:
Vertex(const char dt): data(dt) { }
private:
char data;
};
class Graph
{
public:
Graph()
: nVertex(0), vertexTable(new Vertex*[MAXVERTEX_NUMS]) // 初始化当前顶点个数 和 存放顶点的数组
{
for(int i=0; i<MAXVERTEX_NUMS; i++) // 初始化顶点状态
visitedVtable[i] = 0;
for(int i=0; i<MAXVERTEX_NUMS; i++) // 初始化adjacency matrix
for(int j=0; j<MAXVERTEX_NUMS; j++)
adjMat[i][j] = 0;
}
~Graph() { delete[] vertexTable; } // vertexTable中存放的不是new出来的Vertex, 所以只需delete数组即可
void addVertex(Vertex& v);
void addEdge(const Vertex& v1, const Vertex& v2);
void printVertex() const;
void printAdjMat() const;
void printDFS(); // ***********重点是printDFS()****************
void printBFS(); // ***********重点是printBFS()****************
private:
Vertex** vertexTable; // 存放顶点
bool visitedVtable[MAXVERTEX_NUMS]; // 存放顶点是否被遍历的状态
bool adjMat[MAXVERTEX_NUMS][MAXVERTEX_NUMS]; // adjacency matrix
int nVertex; // 当前顶点个数
};
void Graph::addVertex(Vertex& v)
{
vertexTable[nVertex++] = &v;
}
void Graph::addEdge(const Vertex& v1, const Vertex& v2)
{
adjMat[v1.data-65][v2.data-65] = 1;
adjMat[v2.data-65][v1.data-65] = 1;
}
void Graph::printVertex() const
{
for(int i=0; i<nVertex; i++)
cout << vertexTable[i]->data << " ";
cout << endl;
}
void Graph::printAdjMat() const
{
for(int i=0; i<nVertex; i++)
{
for(int j=0; j<nVertex; j++)
cout << adjMat[i][j] << " ";
cout << endl;
}
}
// ----------------------------DFS---------------------------------------
void Graph::printDFS()
{
auto vnextUnvisited = [&](const Vertex* v)->int // 返回顶点在vertexTable中的位置
{
for(int i=0; i<nVertex; i++) // 搜索adjacency matrix的每一行
if(adjMat[v->data-65][i] && !visitedVtable[i]) // 如果给定顶点,在邻接表找到1 且 没被访问过
return i; // 返回该顶点对应表中的位置
return -1; // 如果没找到返回-1
};
stack<Vertex*> gStack; // 用stack存放 遍历过的 顶点
int i = 0; // 记录顶点在vertexTable中的索引
visitedVtable[i] = true; // 标记第一个顶点已被访问
cout << vertexTable[i]->data << " "; // 输出
gStack.push(vertexTable[i]); // 压入起点
while(!gStack.empty())
{
i = vnextUnvisited(gStack.top()); // 访问第下个顶点
if(i >= 0) // 存在
{
visitedVtable[i] = true; // 标记被访问
cout << vertexTable[i]->data << " "; // 输出
gStack.push(vertexTable[i]); // 访问过的顶点 都要压入stack
}
else // 没有下个顶点了
{
gStack.pop();
}
}
cout << endl;
for(int j=0; j<nVertex; j++) // 状态表置零 可以多次搜索
visitedVtable[j] = false;
}
// -----------------------------------------------------------------------
// ----------------------------BFS----------------------------------------
void Graph::printBFS()
{
auto vnextUnvisited = [&](Vertex* v) -> int
{
for(int i=0; i<nVertex; i++)
{
if(adjMat[v->data - 65][i] && !visitedVtable[i])
return i;
return -1;
}
};
queue<Vertex*> gQueue; // 用于保存顶点
int i = 0; // 用于保存当前顶点的索引
visitedVtable[i] = true; // 标记该顶点已被遍历
gQueue.push(vertexTable[i]); // 存入queue
while(!gQueue.empty()) // 遍历 queue里保存的 顶点
{
i = gQueue.front()->data - 65; // 从queue中取出一个顶点,获取索引号
int j = vnextUnvisited(gQueue.front()); // 记录 当前顶点下一个连接顶点 的起始位置, 记录adjMat的一行索引, 从第一个连接顶点开始 //
while(j < nVertex) // 遍历完周围没有被 遍历过的 顶点
{
if(adjMat[i][j] && !visitedVtable[j]) // j对应的这个周围顶点 没有被遍历过的
{
visitedVtable[j] = true; // 标记该顶点已被遍历
gQueue.push(vertexTable[j]); // 存入queue
}
j++; // 寻找下一个 周围的顶点
}
cout << gQueue.front()->data << " "; // 当前顶点周围顶点都存进queue时, 输出当前节点
gQueue.pop(); // 并删除这个顶点,指向下一个
}
cout << endl;
for(int ii=0; ii<nVertex; ii++) // 为方便多次搜索, 需要清零 是否被搜索过的记录
visitedVtable[ii] = false;
}
// -----------------------------------------------------------------------
int main()
{
Vertex vA('A'); // 创建顶点
Vertex vB('B');
Vertex vC('C');
Vertex vD('D');
Vertex vE('E');
Graph G; // 创建图
G.addVertex(vA); // 添加顶点
G.addVertex(vB);
G.addVertex(vC);
G.addVertex(vD);
G.addVertex(vE);
G.addEdge(vA, vB); // 添加边
G.addEdge(vA, vD);
G.addEdge(vB, vE);
G.addEdge(vD, vE);
G.addEdge(vC, vE);
G.printVertex(); // 打印顶点
G.printAdjMat(); // 打印邻接矩阵
cout << "=============\n";
G.printDFS(); // 打印深度优先搜索结果 DFS
G.printBFS(); // 打印广度优先搜索结果 BFS
// output:
// A B C D E
// 0 1 0 1 0
// 1 0 0 0 1
// 0 0 0 0 1
// 1 0 0 0 1
// 0 1 1 1 0
// =============
// A B E C D
// A B D E C
return 0;
}
测试二,plus代码
// 邻接矩阵如下
// 0 0 1 1 0 1 0
// 0 0 1 0 0 0 0
// 1 1 0 1 0 0 0
// 1 0 1 0 0 0 0
// 0 0 0 0 0 0 1
// 1 0 0 0 0 0 1
// DFS: A C B D F G E
// BFS: A C D F B G E
#include<iostream>
#include <cstring>
#include<stack>
#include<queue>
using namespace std;
#define MAX_SIZE (10)
template<typename T>
class Vertex
{
public:
Vertex(const char n, const T& d=T())
: name(n), data(d) { }
char name;
T data;
};
template<typename T>
class Graph
{
public:
Graph()
{
theSize = 0;
for (int i=0; i<MAX_SIZE; ++i)
for (int j=0; j<MAX_SIZE; ++j)
adjMat[i][j] = 0;
}
// 递归 或者 stack
void DFS()
{
if (theSize == 0) return;
bool visited[theSize]; // 记录被访问过的顶点
memset(visited, 0, theSize);// 初始置0
stack<Vertex<T>*> vStack; // DFS栈
int index = 0; // 记录没有访问过的顶点的索引
Vertex<T>* first = vertexTable[index];
cout << first->name << " "; // visited
visited[index] = true; // 标记被访问
vStack.push(vertexTable[index]);// 第一个入栈
while (!vStack.empty()) {
auto p = vStack.top(); // 获取栈顶
// 查找p点周围没有被访问过的点
for (int i=0; i<theSize; ++i) {
if (!visited[i] && adjMat[p->name - 'A'][i]) {
index = i;
break;
} else index = -1;
}
// 该顶点周围的点都被访问过了
if (index == -1) {
vStack.pop();
}
// p周围还存在没被访问过的顶点,访问,入栈
else {
cout << vertexTable[index]->name << " ";
visited[index] = true; // 标记被访问
vStack.push(vertexTable[index]);
}
}
cout << endl;
}
// queue 入q就标记被访问, pop只打印
void BFS()
{
bool visited[theSize];
memset(visited, 0, sizeof(visited));
queue<Vertex<T>*> vQueue;
vQueue.push(vertexTable[0]); // 从第一个顶点开始
visited[0] = true; // 标记
while (!vQueue.empty()) {
Vertex<T>* p = vQueue.front(); // 取出队头
vQueue.pop();
cout << p->name << " "; // 打印
// 周围的点都入queue, 没有被访问过且有连接关系
for (int i=0; i<theSize; ++i) {
if (!visited[i] && adjMat[p->name - 'A'][i]) {
vQueue.push(vertexTable[i]); // 入queue
visited[vertexTable[i]->name - 'A'] = true; // 标记
}
}
}
}
void add_vertex(Vertex<T>& v) { vertexTable[theSize++] = &v; }
void add_edge(const Vertex<T>& v1, const Vertex<T>& v2)
{
adjMat[v1.name - 'A'][v2.name - 'A'] = 1; // 对称阵
adjMat[v2.name - 'A'][v1.name - 'A'] = 1; // 对称阵
}
void print_adjmat() const
{
for (int i=0; i<theSize; ++i) {
for (int j=0; j<theSize; ++j)
cout << adjMat[i][j] << " ";
cout << endl;
}
}
private:
Vertex<T>* vertexTable[MAX_SIZE];
bool adjMat[MAX_SIZE][MAX_SIZE];
int theSize;
};
int main()
{
Graph<string> gh;
Vertex<string> vA('A');
Vertex<string> vB('B');
Vertex<string> vC('C');
Vertex<string> vD('D');
Vertex<string> vE('E');
Vertex<string> vF('F');
Vertex<string> vG('G');
gh.add_vertex(vA);
gh.add_vertex(vB);
gh.add_vertex(vC);
gh.add_vertex(vD);
gh.add_vertex(vE);
gh.add_vertex(vF);
gh.add_vertex(vG);
gh.print_adjmat(); cout << endl;
gh.add_edge(vA, vC);
gh.add_edge(vA, vD);
gh.add_edge(vA, vF);
gh.add_edge(vB, vC);
gh.add_edge(vC, vD);
gh.add_edge(vE, vG);
gh.add_edge(vF, vG);
gh.print_adjmat();
gh.DFS();
gh.BFS();
// stdout
// 0 0 1 1 0 1 0
// 0 0 1 0 0 0 0
// 1 1 0 1 0 0 0
// 1 0 1 0 0 0 0
// 0 0 0 0 0 0 1
// 1 0 0 0 0 0 1
// DFS: A C B D F G E
// BFS: A C D F B G E
return 0;
}