7-2 实验6-2(图-邻接表)
利用邻接表存储无向图,并从0号顶点开始进行广度优先遍历。
输入格式:
输入第一行是两个整数n1 n2,其中n1表示顶点数(则顶点编号为0至n1-1),n2表示图中的边数。
之后有n2行输入,每行输入表示一条边,格式是"顶点1 顶点2",把边插入图中。在链表中插入元素时,在链表头部插入。需要注意,由于是无向图,因此同一条边需要在两条链表中都插入。
例如:
cpp
4 4
0 1
1 3
0 3
0 2
输出格式:
先按0至n1-1输出存储图的邻接表,每个链表占1行,同一行元素之间空1格,最后一个元素之后不要有空格。先输出顶点编号,之后按链表顺序输出相邻顶点编号。
之后空一行后输出从0号顶点开始的广度优先遍历序列,顶点编号之间空1格。
例如,对于上面的示例输入,输出为:
cpp
0 2 3 1
1 3 0
2 0
3 0 1
0 2 3 1
说明:输入第1个4表示有4个顶点,第2个4表示有4条边。之后的4行输入代表4条边的顶点。输出前4行为邻接表中的4个链表,之后空一行,然后输出的"0 2 3 1"是广度优先遍历序列。
输入样例:
在这里给出一组输入。例如:
cpp
5 4
0 2
1 2
0 3
0 4
输出样例:
在这里给出相应的输出。例如:
cpp
0 4 3 2
1 2
2 1 0
3 0
4 0
0 4 3 2 1
代码长度限制 16 KB
时间限制 400 ms
内存限制 64 MB
栈限制 8192 KB
代码均自学参考数据结构一书完成,总结一下有两个注意点:
- 一是BFS遍历问题
注意BFS需要遍历完图中所有点,如果是非连通图,很容易漏掉。 - 二是格式
特别要注意格式,如果说一直提示格式错误,一定要仔细检查输出函数空格问题,我就是检查了很久才找到,当图中某个点没有邻接点时,要注意打印顶点之后,不能再打印空格。
C++代码
cpp
#include <iostream>
#include <queue>
using namespace std;
#define MaxVertexNum 100 // 设置最大顶点数
typedef int DataType; // 顶点存储的数据设为整型
typedef int WeightType; // 边的权重设置为整型
typedef int Vertex; // 用定点下标设置为顶点,为整型
bool Visited[MaxVertexNum] = {false};
// 边的定义
typedef struct ENode* PtrToENode;
struct ENode {
Vertex V1, V2; // 有向边<V1, V2>
WeightType Weight; // 权重
};
typedef PtrToENode Edge;
// --------------------------组成图--------------------------
// 邻接点定义
typedef struct AdjVNode* PtrToAdjVNode;
struct AdjVNode {
Vertex AdjV; // 邻接点下标
WeightType Weight; // 边权重
PtrToAdjVNode Next; // 指向下一个邻接点的指针
};
// 顶点表头结点的定义
typedef struct VNode {
PtrToAdjVNode FirstEdge; // 边表头指针
DataType Data; // 存顶点的数据
} AdjList[MaxVertexNum]; // AdjList是邻接表类型,AdjList是结构体数组,长度为MaxVertexNum,元素为VNode
// 图结点的定义
typedef struct GNode* PtrToGNode;
struct GNode {
int Nv; // 顶点数
int Ne; // 边数
AdjList G; // 邻接表
};
typedef PtrToGNode LGraph; // 以邻接表方式存储的图类型
// ----------------------------------------------------------
// 初始化一个有VerTexNum个顶点但没有边的图
LGraph CreatGraph(int VertexNum) {
LGraph Graph = (LGraph)malloc(sizeof(struct GNode));
Graph->Nv = VertexNum;
Graph->Ne = 0;
// 初始化邻接表头指针
for (Vertex V = 0; V < Graph->Nv; V++) {
Graph->G[V].FirstEdge = NULL;
}
return Graph;
}
void InsertEdge(LGraph Graph, Edge E) {
// 插入边 E(<V1, V2>, W)
// 为V1建立邻接点V2
PtrToAdjVNode NewNode = (PtrToAdjVNode)malloc(sizeof(struct AdjVNode));
NewNode->AdjV = E->V2;
NewNode->Weight = E->Weight;
// 将V2插入图Graph
NewNode->Next = Graph->G[E->V1].FirstEdge; // 邻接点V2尾部指向顶点域V1所指的邻接点
Graph->G[E->V1].FirstEdge = NewNode; // 顶点域V1指向邻接点V2
// 对于无向图,
// 还要插入边 E(<V2, V1>, W)
NewNode = (PtrToAdjVNode)malloc(sizeof(struct AdjVNode));
NewNode->AdjV = E->V1;
NewNode->Weight = E->Weight;
// 将V1插入图Graph
NewNode->Next = Graph->G[E->V2].FirstEdge; // 邻接点V1尾部指向顶点域V2所指的邻接点
Graph->G[E->V2].FirstEdge = NewNode; // 顶点域V2指向邻接点V1
}
// 建立以邻接表方式存储的图
LGraph BuildGraph() {
int Nv;
Edge E;
LGraph Graph;
cin >> Nv; // 读入顶点个数
Graph = CreatGraph(Nv); // 初始化只有Nv个顶点的图
if (Nv == 0) {
Graph->Ne = 0;
return Graph;
}
cin >> Graph->Ne; // 读入边数
if (Graph->Ne != 0) { // 如果有边
E = (Edge)malloc(sizeof(ENode)); // 建立边结点
//读入边,输入格式为:起点 终点 权重
for (int i = 0; i < Graph->Ne; i++) {
cin >> E->V1 >> E->V2;
E->Weight = 1;
InsertEdge(Graph, E); // 插入边
}
// 若需要输入顶点数据,写在这
}
return Graph;
}
// 打印图的邻接表
void PrintGraph(LGraph Graph) {
Vertex Vi;
PtrToAdjVNode P;
for (Vi = 0; Vi < Graph->Nv; Vi++) {
cout << Vi; // 打印顶点
if (Graph->G[Vi].FirstEdge != NULL) cout << ' '; // 卡了很久才知道是这里的问题,要注意,如果没有邻接点,顶点后面不能输出空格,要区分好
for (P = Graph->G[Vi].FirstEdge; P != NULL; P = P->Next) { // 遍历Vi的邻接点
cout << P->AdjV; // 依次打印邻接点下标
if(P->Next) cout << ' ';
}
cout << '\n';
}
}
// BFS主函数
void BFSFormVertex(LGraph G, Vertex S, void(*Visit)(Vertex)) {
// 以S为出发点的以邻接表方式存储的图进行BFS搜索
Vertex V;
PtrToAdjVNode P;
queue<Vertex> Q; // 创建空队列
Visit(S); // 访问S
Visited[S] = true; // 标记已访问
Q.push(S); // S入队
while (!Q.empty()) {
V = Q.front();Q.pop(); // 弹出队首元素V
// 遍历V的每个邻接点,若没有访问过,则访问并入队
for (P = G->G[V].FirstEdge; P != NULL; P = P->Next) {
if (!Visited[P->AdjV]) { // 如果没访问过
Visit(P->AdjV); // 访问
Visited[P->AdjV] = true; // 访问后标记
Q.push(P->AdjV); // 入队
}
}
}
}
// 广度优先遍历BFS
void BFS(LGraph G, Vertex S, void(*Visit)(Vertex)) {
Vertex V;
for (V = 0; V < G->Nv; V++) {
if (!Visited[V]) {
// 用于访问非连通的顶点
BFSFormVertex(G, V, Visit);
}
}
}
// 访问方法
void Visit(Vertex V) {
cout << V << ' ';
}
int main(int argc, char *argv[]) {
LGraph Graph;
Graph = BuildGraph(); // 读入数据,建立图
PrintGraph(Graph); // 打印图的邻接表
cout << '\n'; // 注意换行
BFS(Graph, 0, Visit); // BFS遍历图
}