一、图的基本介绍
1、为什么要有图

2、图的举例说明
图是一种数据结构,其中结点可以具有零个或多个相邻元素。两个结点之间的连接称为边。 结点也可以称为
顶点。如图:
3、图的常用概念

4、图的表现方式
邻接矩阵

邻接表

5、代码实现(邻接矩阵)

依据上图进行插入各个节点以及边。
属性有三个组成:vertexs(用来存储节点名称,集合存储)、edges(用来存储邻接矩阵,二维数组)、numOfEdge(用来存储两节点相连的实际边数,int型)
主要方法有三个:构造方法(根据输入节点个数来为三个属性进行赋初值)、插入节点名称(集合插入)、插入邻接矩阵中两点连线的权值
其他常用普遍方法:
package graph;import java.util.ArrayList;import java.util.Arrays;public class Graph {public static void main(String[] args) {Graph graph = new Graph(5);String[] vertexName = {"A","B","C","D","E"};//插入节点名称for(String vertex:vertexName) {graph.insertVertex(vertex);}//插入各自节点的权值//A-B A-C B-C B-D B-Egraph.insertEdge(0, 1, 1);graph.insertEdge(0,2,1);graph.insertEdge(1,2,1);graph.insertEdge(1,3,1);graph.insertEdge(1,4,1);graph.showGraph();}private ArrayList<String> vertexs;//用来存储节点的private int[][] edges;//存储图对应的邻接矩阵private int numOfEdge;//用来存储边的数量//构造函数,用来对属性进行初始化public Graph(int n) {edges = new int[n][n];//邻接矩阵进行初始化vertexs = new ArrayList<>(n);//开辟指定空间的集合numOfEdge = 0;//边的数目暂时不确定}//其他普遍常用的方法*************//获取边数public int getNumOfEdge(){return numOfEdge;}//获取指定下标的对应类型名称public String getValueByIndex(int i) {return vertexs.get(i);}//获取两点之间的权值public int getWeight(int v1,int v2) {return edges[v1][v2];}//显示图对应的矩阵public void showGraph() {for(int[] link:edges) {System.out.println(Arrays.toString(link));}}//其他普遍常用的方法*************//插入节点public void insertVertex(String vertex) {vertexs.add(vertex);//来进行插入到list集合中}//插入边public void insertEdge(int v1,int v2,int weight) {edges[v1][v2] = weight;edges[v2][v1] = weight;numOfEdge++;}}
运行结果:
二、图的遍历
所谓图的遍历,即是对结点的访问。一个图有那么多个结点,如何遍历这些结点,需要特定策略,一般有两种 访问策略:(1)深度优先遍历 (2)广度优先遍历
1、深度优先遍历(dfs)
源代码:Graph.java
基本思想以及算法步骤

算法步骤
代码实现以及思路

进行深搜需要有两个辅助方法:都很简单只不过就是遍历看是否大于1返回对应下标
① 获取当前节点位置行中第一个相连接的节点 —》 getFirstConnectNode
② 获取到当前节点位置中对应位置节点之后的一个节点 —》getNextConnectNode
下面dfs方法分成两部分,实际上可以直接分成一部分,只不过更加区分好理解而已。
package graph;import java.util.ArrayList;import java.util.Arrays;public class Graph {private ArrayList<String> vertexs;//用来存储节点的private int[][] edges;//存储图对应的邻接矩阵private int numOfEdge;//用来存储边的数量private boolean[] isVisible;//用来判断该点是否已经访问过了//构造函数,用来对属性进行初始化public Graph(int n) {edges = new int[n][n];//邻接矩阵进行初始化vertexs = new ArrayList<>(n);//开辟指定空间的集合numOfEdge = 0;//边的数目暂时不确定isVisible = new boolean[n];//默认都是false}//dfs算法相关******************//辅助方法1:获取对应节点中第一个连接的节点public int getFirstConnectNode(int w) {for(int i = 0;i<vertexs.size();i++) {if(edges[w][i]>0) {return i;//返回第一个连接的节点位置}}return -1;//没有的话就返回-1;}//辅助方法2:获取对应节点中的下一个节点,需要传入两个值一个是当前节点,另一个是当前节点这行中的位置public int getNextConnectNode(int w1,int w2) {for(int i = w2+1;i<vertexs.size();i++) {//找到w2节点之后的进行返回对应位置if(edges[w1][i]>0) {return i;}}return -1;}//开始写dfs算法private void dfs(int n) {//获取当前访问的节点System.out.printf(vertexs.get(n)+"->");//当前节点已经被访问isVisible[n] = true;//获取到对应节点连接的第一个节点int w = getFirstConnectNode(n);while(w != -1) {if(!isVisible[w]) {dfs(w);}w = getNextConnectNode(n, w);//当前节点为n,对应位置节点为w}}//这里写一个外部,涉及到所有可能性public void dfs() {//对每个边都进行搜查,而不是只是一个节点不断往下搜查for(int i=0;i<vertexs.size();i++) {if(!isVisible[i]) {dfs(i);}}}//dfs算法相关******************....其他方法可见上面图的代码实现}
测试方法:
package graph;import java.util.ArrayList;import java.util.Arrays;public class Graph {public static void main(String[] args) {Graph graph = new Graph(5);String[] vertexName = {"A","B","C","D","E"};//插入节点名称for(String vertex:vertexName) {graph.insertVertex(vertex);}//插入各自节点的权值//A-B A-C B-C B-D B-Egraph.insertEdge(0, 1, 1);graph.insertEdge(0,2,1);graph.insertEdge(1,2,1);graph.insertEdge(1,3,1);graph.insertEdge(1,4,1);//展示矩形图graph.showGraph();//进行深搜遍历graph.dfs();}}
运行结果:
2、广度优先遍历(BFS)
源代码:Graph.java
基本思想以及算法步骤

算法步骤

代码实现

//辅助方法1:获取对应节点中第一个连接的节点public int getFirstConnectNode(int w) {for(int i = 0;i<vertexs.size();i++) {if(edges[w][i]>0) {return i;//返回第一个连接的节点位置}}return -1;//没有的话就返回-1;}//辅助方法2:获取对应节点中的下一个节点,需要传入两个值一个是当前节点,另一个是当前节点这行中的位置public int getNextConnectNode(int w1,int w2) {for(int i = w2+1;i<vertexs.size();i++) {//找到w2节点之后的进行返回对应位置if(edges[w1][i]>0) {return i;}}return -1;}//开始写bfs算法public void bfs(int n) {int u;//设置为队列的头节点对应下标int w;//邻接节点System.out.print(vertexs.get(n)+"=>");//创建一个队列LinkedList<Integer> list = new LinkedList<>();//设置对应节点已经访问过isVisible[n] = true;list.addLast(n);//将首先这个节点放置最后//1、队列不为空为判断情况 这里相当于将每一行的放置在队列中依次取出while(!list.isEmpty()) {u = list.removeFirst();//取出队列中的第一个节点并获取下标//2、得到第一个邻接节点的下标w 这里相当于遍历头节点行进行打印以及放置队列w = getFirstConnectNode(u);while(w != -1) {if(!isVisible[w]) {System.out.print(vertexs.get(w)+"=>");isVisible[w] = true;list.addLast(w);//将该节点添加到队列中}w = getNextConnectNode(u, w);//继续获取头节点对应下一节点的位置}}}//对所有情况进行遍历public void bfs() {for(int i = 0;i<vertexs.size();i++) {if(!isVisible[i]) {bfs(i);}}}
测试代码:**
package graph;import java.util.ArrayList;import java.util.Arrays;import java.util.LinkedList;public class Graph {public static void main(String[] args) {Graph graph = new Graph(5);String[] vertexName = {"A","B","C","D","E"};//插入节点名称for(String vertex:vertexName) {graph.insertVertex(vertex);}//插入各自节点的权值//A-B A-C B-C B-D B-Egraph.insertEdge(0, 1, 1);graph.insertEdge(0,2,1);graph.insertEdge(1,2,1);graph.insertEdge(1,3,1);graph.insertEdge(1,4,1);//展示矩形图graph.showGraph();//进行深搜遍历//graph.dfs();//进行广搜遍历graph.bfs();}}
运行结果:
图的深度优先 VS 广度优先

整理者:长路 时间:2020/9/2-2020/9/4
