# 算法系列笔记6(有关图的算法一―搜索，拓扑排序和强连通分支)

// 广度遍历图
void Graph::bfs(int s){
queue<int> q;
q.push(s);
visited[s] = 1;
while(!q.empty()){
int u = q.front();
q.pop();
cout << u <<" ";
GNode *p = edges[u].next;
while(p != NULL){
if(!visited[p->val]){ // 未被访问，则将其加入队列中并标志为访问过
q.push(p->val);
visited[p->val] = 1;
}
p = p->next;
}
}

}

void Graph::bfsTravel(){
memset(visited, 0, sizeof(int)*vertexNum);
for(int i = 0; i < vertexNum; i++){
if(!visited[i]){
bfs(i);
cout << endl;
}
}
}

// 深度优先遍历
void Graph::dfs(int s){
visited[s] = 1;
time += 1;
beginTime[s] = time;
cout << s << "(" << beginTime[s] << " "; // shen
GNode *p = edges[s].next;
while(p != NULL){
if(!visited[p->val])
dfs(p->val);
p = p->next;
}
time += 1;
endTime[s] = time;
topSort.push_back(s);
cout << endTime[s] << ")" <<" ";
}

void Graph::dfsTravel(){
memset(visited, 0, sizeof(int)*vertexNum);
memset(beginTime, 0, sizeof(int)*vertexNum); // 结点开始访问的时间
memset(endTime, 0, sizeof(int)*vertexNum); // 结点结束访问的时间
for(int i = 0; i < vertexNum; i++){
if(!visited[i]){
dfs(i);
cout << endl;
}
}
}

(1)树边，深度遍历森林中的每条边就是树边。

(2)前向边，u到其后裔的非树边(u,v)。

(3)反向边，u到其先人的边(u,v)。

(4)横向边，1个顶点就不是另外1个顶点的先人或后裔。

(2)对1个无向图G进行深度优先搜索的进程中，G的每条边要末是树边，要末是反向边。

// 创建图g的转置
void Graph::buildTransGraph(Graph &g){
this->vertexNum = g.vertexNum;
this->edgesNum = g.edgesNum;
for(int i = 0; i < vertexNum; i++){
this->vertex[i] = g.vertex[i];
this->edges[i].val = g.edges[i].val;
this->edges[i].weight = g.edges[i].weight;
this->edges[i].next = NULL;
}

for(int i = 0; i < vertexNum; i++){
GNode *p = g.edges[i].next;
while(p != NULL){
GNode *newNode = new GNode();
newNode->val = i;
newNode->next = NULL;
newNode->weight = p->weight;
GNode *q = &edges[p->val];
while(q->next != NULL) q = q->next;
q->next = newNode;
p = p->next;
}
}
}

//强连通份量
void Graph::componentSC(){
//time = 0;
//dfsTravel(); // 对图g进行深度搜索得到完成x访问所需要的时间 并由此得到其拓扑排序
Graph g2;
g2.buildTransGraph(*this); // 得到图G的转置
time = 0;
memset(g2.visited, 0, sizeof(int)*vertexNum);
cout << "强连通份量: " << endl;
for(vector<int>::reverse_iterator iter = topSort.rbegin(); iter != topSort.rend(); iter++){ // 对转置图g2进行深度搜索得到强连通份量
if(!g2.visited[*iter])
g2.dfs(*iter);
}
cout << endl;
}

graph.h

#ifndef GRAPH_H
#define GRAPH_H
#include <iostream>
#include <vector>
using namespace std;
#define maxSize 10
#define maxInt 0x80000000 // 将此值设为权值的最大值

struct GNode{
int val;
int weight;
GNode *next;
};
class Graph{
public:
void createGraph(int n, int e);
void destroyGraph(GNode *p);
~Graph(){
for(int i = 0; i < vertexNum; i++){
destroyGraph(edges[i].next);
//cout << "析构:" << i << endl;
}
}
void showGraph();
void bfsTravel(); // 广度遍历
void dfsTravel(); // 深度遍历
void showTopSort(); // 输出拓扑序列
void componentSC(); // 建立图g的强连通份量

void prim();

private:
int vertex[maxSize]; // 寄存顶点
GNode edges[maxSize]; // 寄存邻接表
int vertexNum; //顶点个数
int edgesNum; //边条数

//bfs and dfs 遍历
int visited[maxSize];
void bfs(int s);
void dfs(int s);
int beginTime[maxSize]; // 深度开始访问x的时间
int endTime[maxSize]; // 结束访问x的时间
static int time;
vector<int> topSort; // topSort的逆序为有向无回路的拓扑排序
void buildTransGraph(Graph &g); // 建立图g的转置

// prim
int lowcost[maxSize];
};

#endif

graph.cpp

#include <iostream>
#include "graph.h"
#include <queue>
using namespace std;

int Graph::time = 0;
void Graph::createGraph(int n, int e){
vertexNum = n;
edgesNum = e;
for(int i = 0; i < n; i++){
vertex[i] = i;
edges[i].val = i;
edges[i].weight = 0;
edges[i].next = NULL;
}

for(int i = 0; i < e; i++){
int source, dest, wei;
cin >> source >> dest >> wei;
GNode *newNode = new GNode();
newNode->val = dest;
newNode->weight = wei;
newNode ->next = NULL;
GNode *p = &edges[source];
while(p->next != NULL) p = p->next;
p->next = newNode;

// 无向图 有向图就将这段删除掉
/*GNode *newNode2 = new GNode();
newNode2->val = source;
newNode2->weight = wei;
newNode2 ->next = NULL;
GNode *p2 = &edges[dest];
while(p2->next != NULL) p2 = p2->next;
p2->next = newNode2;*/

}
}

void Graph::destroyGraph(GNode *p){
if(p == NULL) return;
else{
destroyGraph(p->next);
delete p;
}
}

void Graph::showGraph(){
for(int i = 0; i < vertexNum; i++){
int j = i;
cout << i << "->";
GNode *p = edges[j].next;
while( p != NULL) {
cout << "(" << p->val <<"," << p->weight << ")" ;
p = p->next;
}
cout << endl;
}
}

// 广度遍历图
void Graph::bfs(int s){
queue<int> q;
q.push(s);
visited[s] = 1;
while(!q.empty()){
int u = q.front();
q.pop();
cout << u <<" ";
GNode *p = edges[u].next;
while(p != NULL){
if(!visited[p->val]){ // 未被访问，则将其加入队列中并标志为访问过
q.push(p->val);
visited[p->val] = 1;
}
p = p->next;
}
}

}

void Graph::bfsTravel(){
memset(visited, 0, sizeof(int)*vertexNum);
for(int i = 0; i < vertexNum; i++){
if(!visited[i]){
bfs(i);
cout << endl;
}
}
}

// 深度优先遍历
void Graph::dfs(int s){
visited[s] = 1;
time += 1;
beginTime[s] = time;
cout << s << "(" << beginTime[s] << " "; // shen
GNode *p = edges[s].next;
while(p != NULL){
if(!visited[p->val])
dfs(p->val);
p = p->next;
}
time += 1;
endTime[s] = time;
topSort.push_back(s);
cout << endTime[s] << ")" <<" ";
}

void Graph::dfsTravel(){
memset(visited, 0, sizeof(int)*vertexNum);
memset(beginTime, 0, sizeof(int)*vertexNum); // 结点开始访问的时间
memset(endTime, 0, sizeof(int)*vertexNum); // 结点结束访问的时间
for(int i = 0; i < vertexNum; i++){
if(!visited[i]){
dfs(i);
cout << endl;
}
}
}

// 输出拓扑排序
void Graph::showTopSort(){
for(vector<int>::reverse_iterator iter = topSort.rbegin(); iter != topSort.rend(); iter ++)
cout << *iter << " ";
cout << endl;
}

// 创建图g的转置
void Graph::buildTransGraph(Graph &g){
this->vertexNum = g.vertexNum;
this->edgesNum = g.edgesNum;
for(int i = 0; i < vertexNum; i++){
this->vertex[i] = g.vertex[i];
this->edges[i].val = g.edges[i].val;
this->edges[i].weight = g.edges[i].weight;
this->edges[i].next = NULL;
}

for(int i = 0; i < vertexNum; i++){
GNode *p = g.edges[i].next;
while(p != NULL){
GNode *newNode = new GNode();
newNode->val = i;
newNode->next = NULL;
newNode->weight = p->weight;
GNode *q = &edges[p->val];
while(q->next != NULL) q = q->next;
q->next = newNode;
p = p->next;
}
}
}

//强连通份量
void Graph::componentSC(){
//time = 0;
//dfsTravel(); // 对图g进行深度搜索得到完成x访问所需要的时间 并由此得到其拓扑排序
Graph g2;
g2.buildTransGraph(*this); // 得到图G的转置
time = 0;
memset(g2.visited, 0, sizeof(int)*vertexNum);
cout << "强连通份量: " << endl;
for(vector<int>::reverse_iterator iter = topSort.rbegin(); iter != topSort.rend(); iter++){ // 对转置图g2进行深度搜索得到强连通份量
if(!g2.visited[*iter])
g2.dfs(*iter);
}
cout << endl;
}

main.cpp

#include <iostream>
#include "graph.h"
using namespace std;

int main(){
Graph g;
g.createGraph(8, 13);

cout << "邻接表: " << endl;
g.showGraph();

cout << "广度遍历的结果: " << endl;
g.bfsTravel();

cout << "深度遍历的结果: " << endl; // 具有括号结果 其中x(a b) x代表结点 a代表开始访问x的时间 b代表完成访问x的时间
g.dfsTravel(); // 深度遍历完成访问x的时间的逆序就是有向无回路的拓扑排序

cout << "拓扑排序: " << endl;
g.showTopSort();

g.componentSC();

return 0;
}

0 1 1
1 2 1
2 0 1
1 3 1
3 4 1
4 3 1
2 5 1
5 6 1
6 5 1
3 6 1
6 7 1
7 7 1
4 7 1

1. 本站所有资源来源于用户上传和网络，如有侵权请邮件联系站长！
2. 分享目的仅供大家学习和交流，您必须在下载后24小时内删除！
3. 不得使用于非法商业用途，不得违反国家法律。否则后果自负！
4. 本站提供的源码、模板、插件等等其他资源，都不包含技术服务请大家谅解！
5. 如有链接无法下载、失效或广告，请联系管理员处理！
6. 本站资源售价只是赞助，收取费用仅维持本站的日常运营所需！
7. 本站源码并不保证全部能正常使用，仅供有技术基础的人学习研究，请谨慎下载
8. 如遇到加密压缩包，请使用WINRAR解压,如遇到无法解压的请联系管理员！