一、图的基本介绍
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-E
graph.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-E
graph.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-E
graph.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