之前笔者实现过由邻接表和邻接矩阵表示的图的深搜和广搜,但是图的构造都是自己手动赋值的,现在我们加上邻接表的构建函数,对于整个流程都自动化。
首先是邻接表的结构声明:
/*
结构声明
*/
struct EdgeNode{ //边结点结构声明
int val;
struct EdgeNode* next; //链接下一条边
};
struct VertexNode{ //顶点结点结构声明
int val;
struct EdgeNode* first;//边链表头指针
};
struct ALGraph{ //邻接表结构声明
VertexNode VerticesList[maxVertices]; //邻接表的顶点数组
int numVertices; //顶点数
int numEdges; //边数
};
接着就是构造邻接表的函数:
/*
创建邻接表
*/
void createGraph(ALGraph& G) {
cin >> G.numVertices >> G.numEdges; //输入顶点数和边数
for(int i = 0; i < G.numVertices; i ++){
cin >> G.VerticesList[i].val; //顶点名称
G.VerticesList[i].first = NULL; //边链表置空
}
for(int i = 0; i < G.numEdges; i ++){
int tail,head; //定义边
cin >> tail >> head; //输入边
EdgeNode* p = new EdgeNode;
p->val = head;
//寻找tail对应顶点
int temp;
for(int i = 0;i < G.numVertices; i ++)
if(G.VerticesList[i].val == tail) temp = i;
//头插法插入边结点
p->next = G.VerticesList[temp].first;
G.VerticesList[temp].first = p;
}
}
我们这种构造方式对应的打印函数:
/*
打印邻接表
*/
void printGraph(ALGraph& G) {
for(int i = 0; i < G.numVertices; i ++) {
cout << G.VerticesList[i].val << "->";
EdgeNode* p = G.VerticesList[i].first;
while(p != NULL){
cout << p->val << "->";
p = p->next;
}
cout << "null"<<endl;
}
}
两个辅助函数,寻找与订单相邻第一个结点下标和下一个相邻结点的下标。这两个函数可以让我们的深搜和广搜函数都可以忽略掉图是由那种方式存储的。
/*
两个辅助函数
*/
//与顶点v相邻的第一个结点的下标
int firstNeighbor(ALGraph& G,int v){
if(G.VerticesList[v].first != NULL)
return G.VerticesList[v].first->val;
else return -1;
}
//顶点v除w顶点外的下一个相邻结点的下标
int nextNeighbor(ALGraph& G,int v,int w){
EdgeNode* p = G.VerticesList[v].first;
while(p != NULL && p->val != w) p = p->next;
if(p != NULL && p->next != NULL)
return p->next->val;
else return -1;
}
深度遍历一个连通分量:
/*
深度优先遍历一个连通分量
*/
void dfs(ALGraph& G,int v,int visited[]){
visited[v] = 1;
int w = firstNeighbor(G, v);
while(w != -1){
if(!visited[w])
dfs(G, w, visited);
w= nextNeighbor(G, v, w);
}
}
我们这里来判断一下两个结点之间是否联通:
/*
深度优先遍历
*/
bool graphTraverse_dfs(ALGraph& G, int visited[], int U, int V){
//区别就体现在这里,我们只需要遍历由U开始的的连通分量
dfs(G, U, visited);
return visited[V];
}
广搜也是一样的,可以参考我之前写的博客。
完整代码:
#include<iostream>
#include<queue>
using namespace std;
#define maxVertices 10
/*
结构声明
*/
struct EdgeNode{ //边结点结构声明
int val;
struct EdgeNode* next; //链接下一条边
};
struct VertexNode{ //顶点结点结构声明
int val;
struct EdgeNode* first;//边链表头指针
};
struct ALGraph{ //邻接表结构声明
VertexNode VerticesList[maxVertices]; //邻接表的顶点数组
int numVertices; //顶点数
int numEdges; //边数
};
/*
创建邻接表
*/
void createGraph(ALGraph& G) {
cin >> G.numVertices >> G.numEdges; //输入顶点数和边数
for(int i = 0; i < G.numVertices; i ++){
cin >> G.VerticesList[i].val; //顶点名称
G.VerticesList[i].first = NULL; //边链表置空
}
for(int i = 0; i < G.numEdges; i ++){
int tail,head; //定义边
cin >> tail >> head; //输入边
EdgeNode* p = new EdgeNode;
p->val = head;
//寻找tail对应顶点
int temp;
for(int i = 0;i < G.numVertices; i ++)
if(G.VerticesList[i].val == tail) temp = i;
//头插法插入边结点
p->next = G.VerticesList[temp].first;
G.VerticesList[temp].first = p;
}
}
/*
打印邻接表
*/
void printGraph(ALGraph& G) {
for(int i = 0; i < G.numVertices; i ++) {
cout << G.VerticesList[i].val << "->";
EdgeNode* p = G.VerticesList[i].first;
while(p != NULL){
cout << p->val << "->";
p = p->next;
}
cout << "null"<<endl;
}
}
/*
两个辅助函数
*/
//与顶点v相邻的第一个结点的下标
int firstNeighbor(ALGraph& G,int v){
if(G.VerticesList[v].first != NULL)
return G.VerticesList[v].first->val;
else return -1;
}
//顶点v除w顶点外的下一个相邻结点的下标
int nextNeighbor(ALGraph& G,int v,int w){
EdgeNode* p = G.VerticesList[v].first;
while(p != NULL && p->val != w) p = p->next;
if(p != NULL && p->next != NULL)
return p->next->val;
else return -1;
}
/*
深度优先遍历一个连通分量
*/
void dfs(ALGraph& G,int v,int visited[]){
visited[v] = 1;
int w = firstNeighbor(G, v);
while(w != -1){
if(!visited[w])
dfs(G, w, visited);
w= nextNeighbor(G, v, w);
}
}
/*
深度优先遍历
*/
bool graphTraverse_dfs(ALGraph& G, int visited[], int U, int V){
//区别就体现在这里,我们只需要遍历由U开始的的连通分量
dfs(G, U, visited);
return visited[V];
}
int main(){
ALGraph G;
/*
5
5
0 1 2 3 4
0 1
1 2
2 3
4 3
0 4
*/
int U = 0;
int V = 3;
cout << "构造邻接表:" << endl;
createGraph(G);
cout << "构造结果:" << endl;
printGraph(G);
int visit[5] = {0};
int res = graphTraverse_dfs(G, visit, U, V);
cout<<"运行结果:"<<endl;
res == true ? cout<<U<<"与"<<V<<"之间有通路"<<endl : cout<<U<<"与"<<V<<"之间没有通路"<<endl;
}
运行结果:
更多代码请参考:手撕考研数据结构(代码汇总)