JAVA 数据结构 12-图
--图创建、深度、广度遍历完整代码见最后
问题:为什么要有图?
线性表局限于一个直接前驱和一个直接后继的关系,当我们需要表示多对多的关系时,就需要用到图的结构。
图的基本介绍:
图是一种数据结构,其中结点可以具有零个或多个相邻元素。两个结点之间的连接称为边。结点也可以称为顶点。如图:
图的表示方式:
图的表示方式有两种:二维数组表示(邻接矩阵)和链表表示(邻接表)
- 邻接矩阵是表示图中顶点之间直接相邻关系的矩阵,对于n个顶点的图而言,矩阵的行和列表示第n个点。若矩阵中值为1,则表示当前行和列的结点之间有边。
- 邻接表的实现只关心存在的边,为每一个结点创建一条链表,将与该结点有边的结点记录在链表上。
1. 实现图结构
要求:代码实现上图中的图结构
思路分析:
- 需要一个存储结点信息的集合;
- 需要一个存储边信息的集合(顶点之间的关系);
- 顶点信息使用ArrayList保存;
- 边信息采用邻接矩阵int[][]的方式进行存储。
代码实现:
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
public class Graph {
private List<String> vertexList; //顶点集合
private int[][] edges; //边集合
private int numOfEdges; //边的数目
public static void main(String args[]){
Graph graph = new Graph(5);
//添加点
graph.addVertex("A");graph.addVertex("B");
graph.addVertex("C");graph.addVertex("D");graph.addVertex("E");
//添加边
graph.addEdge("A","B",1);graph.addEdge("A","C",1);
graph.addEdge("B","C",1);graph.addEdge("B","D",1);
graph.addEdge("B","E",1);
//展现邻接矩阵
graph.showEdges();
}
public Graph(int n){
this.vertexList = new ArrayList<>();
this.edges = new int[n][n];
this.numOfEdges = 0;
}
public void showEdges(){
for (int[] arr:this.edges){
System.out.println(Arrays.toString(arr));
}
}
public void addVertex(String value){
vertexList.add(value);
}
/**
* 添加无向边
* @param v1 顶点1
* @param v2 顶点2
* @param weight 权值
*/
public void addEdge(String v1,String v2, int weight){
int index1 = vertexList.indexOf(v1);
int index2 = vertexList.indexOf(v2);
this.edges[index1][index2] = weight;
this.edges[index2][index1] = weight;
numOfEdges++;
}
}
2. 图的深度优先遍历(DFS)使用栈递归实现
算法思想:从初始访问结点出发,初始访问结点可能有多个邻接结点,首先啊访问第一个邻接结点,然后再以这个被访问的邻接结点作为初始结点,访问它的第一个邻接结点。每次都在访问完当前结点后首先访问当前结点的第一个邻接结点。算法策略优先从纵向挖掘深度,而不是对一个结点的所有邻接结点进行横向访问。
实现思路分析:
- 访问初始结点v,并标记结点v为已访问;
- 查找结点v的i一个邻接结点w;
- 若w存在,则继续执行4,如果w不存在,则回到第一步,将从v的下一个结点继续;
- 若w未被访问,对w进行深度优先遍历递归(将w看作初始结点,重复步骤123);
- 若w已经被访问,查找v的下一个邻接点,转到步骤3.
代码实现:
前提方法:得到第一个邻接点的下标
/**
* 找第一个邻接点的下标,如果没找到返回-1
* @param index 当前点
* @return
*/
public int getFirstNeighbor(int index){
for(int i = 0;i<vertexList.size();i++){
if