• 图的邻接矩阵和邻接表及深度优先搜索


    图的邻接矩阵和邻接表

    许多人到这一块会比较混乱,特别是邻接表,定义的东西很多,同时也为自己做一个总结。
    打算以图的深度优先搜索为例,分别表示邻接矩阵和邻接表。
    开始前,为了方便大家对命名的记忆,列出了以下常用单词:

    1. vertex/vertices:顶点
    2. arc:弧
    3. matrix:矩阵
    4. adjacency matrix:邻接矩阵
    5. graph:图
    6. depth-first search:深度优先搜索

    邻接矩阵

    输出固定为:

    5 6		//顶点数,边数
    A B C D E	//五个顶点的名字
    A C 12	//顶点A到顶点E的权值
    A E 8
    B C 6
    C D 5
    D E 8
    E B 6
    

    先上定义

    //邻接矩阵存储
    typedef struct {
    	char vex[10];	//顶点表
    	int arcs[10][10];	//邻接矩阵
    	int vexnum, arcnum;	//图的信息,顶点总数和边总数
    };
    

    邻接矩阵较为简单,将一个二维数组和其他信息打包即可
    因为输入数据的时候不一定按顺序来,所以需要一个顶点表记录顶点编号。
    C

    /*
    输入格式:
    5 6		//顶点数,边数
    A B C D E	//五个顶点的名字
    A C 12	//顶点A到顶点E的权值
    A E 8
    B C 6
    C D 5
    D E 8
    E B 6
    */
    
    #include <iostream>
    
    using namespace std;
    
    //邻接矩阵存储
    typedef struct {
    	char vex[10];	//顶点表
    	int arcs[10][10];	//邻接矩阵
    	int vexnum, arcnum;	//图的信息,顶点总数和边总数
    }AMGraph;
    
    //函数声明
    void Create(AMGraph &G);
    int Locate(AMGraph G, char v);
    void DFS(AMGraph G, int v);
    
    bool visited[10] = { false };
    
    int main() {
    	AMGraph graph;
    	Create(graph);
    	DFS(graph, 0);
    	
    	//输出邻接矩阵
    	//cout << endl;
    	//for (int i = 0; i < graph.vexnum; i++) {
    	//	for (int j = 0; j < graph.vexnum; j++) {
    	//		cout << graph.arcs[i][j] << " ";
    	//	}
    	//	cout << endl;
    	//}
    
    	return 0;
    }
    //创建无向图
    void Create(AMGraph &G) {
    	char v1, v2;	//接收输入的顶点
    	int x = 0, y = 0, w = 0;	//输入的边的权w,对应行标x,列表y
    
    	cin >> G.vexnum >> G.arcnum;	//总顶点、边数
    	for (int i = 0; i < G.vexnum; i++) {	//依次输入节点信息
    		cin >> G.vex[i];
    	}
    	//初始化邻接矩阵,边均为0
    	for (int i = 0; i < G.vexnum; i++) {
    		for (int j = 0; j < G.vexnum; j++) {
    			G.arcs[i][j] = 0;
    		}
    	}
    	//根据输入的图的边构造矩阵
    	for (int i = 0; i < G.arcnum; i++) {
    		cin >> v1 >> v2 >> w;
    		x = Locate(G, v1);
    		y = Locate(G, v2);
    		G.arcs[x][y] = w;
    		G.arcs[y][x] = w;
    	}
    	cout << "创建成功" << endl;
    }
    
    //根据顶点名获得其编号下标
    int Locate(AMGraph G, char v) {
    	int result = -1;
    	for (int i = 0; i < G.vexnum; i++) {
    		if (G.vex[i] == v) {
    			result = i;
    			break;
    		}
    	}
    	return result;
    }
    
    //从编号为v的节点开始深度优先搜索并输出节点名
    void DFS(AMGraph G, int v) {
    	cout << G.vex[v] << endl;
    	visited[v] = true;
    	for (int i = 0; i < G.vexnum; i++) {
    		if ((G.arcs[v][i] != 0) && (visited[i] == false)) {
    			DFS(G, i);
    		}
    	}
    }
    
    

    邻接表

    输出固定为:

    5 6    //顶点数,边数
    A B C D E	//五个顶点的名字
    A C
    A E
    B C
    C D
    D E
    E B
    

    这里的三个定义比较复杂,相互嵌套绕的有点晕...

    //定义边
    typedef struct ArcNode{
    	int adjvex;		//边另一头的节点
    	struct ArcNode *nextarc;		//边
    }ArcNode;
    //定义顶点
    typedef struct VexNode {
    	char data;	//顶点信息
    	ArcNode *firstarc;	//边
    }VexNode, AdjList[10];
    //定义邻接表
    typedef struct {
    	AdjList vertices;	//表本体
    	int vexnum, arcnum;		//额外信息,顶点、边总数
    }ALGraph;
    

    三个定义的关系如下

    /*
    输入格式:
    5 6		//顶点数,边数
    A B C D E	//五个顶点的名字
    A C 
    A E 
    B C 
    C D 
    D E 
    E B 
    */
    
    #include <iostream>
    
    using namespace std;
    
    //定义边
    typedef struct ArcNode{
    	int adjvex;		//边另一头的节点
    	struct ArcNode *nextarc;		//边
    }ArcNode;
    //定义顶点
    typedef struct VexNode {
    	char data;	//顶点信息
    	struct ArcNode *firstarc;	//边
    }VexNode, AdjList[10];
    //定义邻接表
    typedef struct {
    	AdjList vertices;	//表本体
    	int vexnum, arcnum;		//额外信息,顶点、边总数
    }ALGraph;
    
    //函数声明
    void Create(ALGraph &G);
    int Locate(ALGraph G, char v);
    void DFS(ALGraph G, int v);
    
    bool visited[10] = { false };	//已经被搜索到的顶点变为true,避免重复搜索
    
    int main() {
    	ALGraph graph;
    	Create(graph);
    	DFS(graph, 0);
    	return 0;
    }
    
    //创建
    void Create(ALGraph &G) {
    	char v1, v2;	//存输入的两个边
    	int x = 0, y = 0;	//存输入的两个边的编号下标
    	ArcNode *p1, *p2;
    	cin >> G.vexnum >> G.arcnum;
    	for (int i = 0; i < G.vexnum; i++) {
    		cin >> G.vertices[i].data;
    		G.vertices[i].firstarc = NULL;	//初始化为空,避免野指针
    	}
    	//读入两点构建边
    	for (int i = 0; i < G.arcnum; i++) {
    		p1 = new ArcNode;
    		p1->nextarc = NULL;
    		p2 = new ArcNode;
    		p2->nextarc = NULL;
    		cin >> v1 >> v2;
    		x = Locate(G, v1);
    		y = Locate(G, v2);
    		p1->adjvex = y;
    		p2->adjvex = x;
    		p1->nextarc = G.vertices[x].firstarc;
    		G.vertices[x].firstarc = p1;
    		p2->nextarc = G.vertices[y].firstarc;
    		G.vertices[y].firstarc = p2;
    	}
    	cout << "创建完成" << endl;
    }
    
    //根据顶点名得到其对应的编号下标
    int Locate(ALGraph G, char v) {
    	int result = -1;
    	for (int i = 0; i < G.vexnum; i++) {
    		if (G.vertices[i].data == v) {
    			result = i;
    			break;
    		}
    	}
    	return result;
    }
    
    
    //从编号为v的顶点开始深度优先搜索并输出顶点名
    void DFS(ALGraph G, int v) {
    	ArcNode *p = new ArcNode;	//编号为v的顶点的指针
    	int w = 0;	//后一个指针的编号
    	cout << G.vertices[v].data << endl;
    	visited[v] = true;
    	p = G.vertices[v].firstarc;
    	while (p != NULL) {
    		w = p->adjvex;
    		if (visited[w] == false) {
    			DFS(G, w);
    		}
    		p = p->nextarc;
    	}
    }
    
    
  • 相关阅读:
    片段
    告诉长夜
    明天
    开源一个WEB版本GEF,基于SVG的网页流程图框架
    RCP:ISourceLocator翻译
    SVG:textPath深入理解
    SVG:linearGradient渐变在直线上失效的问题解决方案
    【半平面交】BZOJ2618[Cqoi2006]凸多边形
    【旋转卡壳+凸包】BZOJ1185:[HNOI2007]最小矩形覆盖
    【凸包+旋转卡壳】平面最远点对
  • 原文地址:https://www.cnblogs.com/luoyang0515/p/10843932.html
Copyright © 2020-2023  润新知