package com.atguigu.graph;
import jdk.nashorn.internal.runtime.RewriteException;
import java.util.ArrayList;
import java.util.LinkedList;
/**
* @author
* @create 2022-07-05-9:40
*/
public class Graph {
private ArrayList<String> vertexList;//存储顶点的集合
private int[][] edges;//存储邻接矩阵
private int numOfEdges;//边的数目
private boolean[] isVisited;
public static void main(String[] args) {
//测试
int n = 5;//节点个数
String verTexValue[] = {"A", "B", "C", "D", "E"};
//创建图对象
Graph graph = new Graph(n);
//添加顶点
for (String value : verTexValue) {
graph.insertVertex(value);
}
//添加边
// 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();
//测试dfs
// System.out.println("dfs:");
// graph.dfs();
// System.out.println();
//测试bfs
System.out.println("bfs:");
graph.bfs();
}
//构造器
public Graph(int n) {//n为顶点个数
//初始化矩阵
edges = new int[n][n];
vertexList = new ArrayList<>(n);
numOfEdges = 0;
isVisited = new boolean[n];
}
//得到第一个临接节点的下标
/**
* @param index 传入的节点的下标
* @return 如果存在就i返回对应的下标,如果不存在就返回-1
*/
public int getFirstNeighbor(int index) {
for (int i = 0; i < vertexList.size(); i++) {
if (edges[index][i] > 0) {//这里是固定行,从列找的第一个邻接节点
return i;
}
}
return -1;
}
//根据第一个邻接节点访问下一个邻接节点
/**
* @param v1 第一个邻接节点在邻接矩阵中的row坐标,表示与这个节点相邻的另外一个节点在vertexList集合中的下标
* @param v2 第一个邻接节点在邻接矩阵中的column坐标,表示就是邻接节点在vertexList集合中的下标
* @return
*/
public int getNextNeighborByFirst(int v1, int v2) {
//由于上一个方法是按照列找的,所以这里也要按照列的那个索引在顶点数组中查找,这里的v2+1是指从当前向下查找
for (int i = v2 + 1; i < vertexList.size(); i++) {
if (edges[v1][i] > 0) {
return i;
}
}
return -1;
}
//深度优先遍历算法
/**
* @param isVisited 是否被访问的数组
* @param index 传入的下标
*/
private void dfs(boolean[] isVisited, int index) {
//首先输出当前节点
System.out.println(getValueByIndex(index));
//标记该节点已经被访问
isVisited[index] = true;
//查找此节点的第一个邻接节点
int firstNeighbor = getFirstNeighbor(index);
if (firstNeighbor != -1) {//第一个邻接节点存在
if (!isVisited[firstNeighbor]) {//第一个邻接节点未被访问
dfs(isVisited, firstNeighbor);
} else {//顺序第一个邻接节点被访问了,那么就从上一层查找第一个邻接节点
//此处是最有难度的一句!!
firstNeighbor = getNextNeighborByFirst(index, firstNeighbor);
}
} //此处如果第一个邻接节点不存在,采用重载进行下一个节点的dfs,所以没写else
}
public void dfs() {
for (int i = 0; i < getNumOfVertex(); i++) {
if (!isVisited[i]) {//如果当前节点没有被访问,那么就进行dfs
dfs(isVisited, i);
}
}
}
//广度优先遍历算法
/**
* 对一个节点进行广度优先遍历
*
* @param isVisited 是否被访问的boolean数组
* @param i 哪一个节点的下标
*/
public void bfs(boolean[] isVisited, int i) {
int headIndex;//队列头节点对应下标
int firstNeighbor;//第一个邻接节点
//1.输出当前节点
System.out.print(getValueByIndex(i)+" ");
//2.标记为已访问
isVisited[i] = true;
LinkedList<Integer> queue = new LinkedList();
//3.将当前节点加入队列
queue.addLast(i);
//4.队列非空时继续执行,否则算法结束
if (!queue.isEmpty()) {
//5.出队列取得头节点
headIndex = queue.removeFirst();
//6.查找此头节点的第一个邻接节点
firstNeighbor = getFirstNeighbor(headIndex);
//7.如果firstNeighbor存在
if (firstNeighbor != -1) {
if (!isVisited[firstNeighbor]) {//7.1 firstNeighbor尚未被访问
//访问
System.out.print(getValueByIndex(firstNeighbor)+" ");
//标记为已访问
isVisited[firstNeighbor] = true;
//入队列
queue.addLast(firstNeighbor);
}
}
//8.如果firstNeighbor不存在。则以headIndex为前驱,找下一个邻接节点
firstNeighbor = getNextNeighborByFirst(headIndex, firstNeighbor);//体现出广度优先
}
}
//遍历所有的节点,都进行广度优先搜索
public void bfs(){
for (int i = 0; i < getNumOfVertex(); i++) {
if (!isVisited[i]){
bfs(isVisited,i);
}
}
}
//
//图中常用方法
//1.返回节点的个数
public int getNumOfVertex() {
return vertexList.size();
}
//2.返回边的个数
public int getNumOfEdges() {
return numOfEdges;
}
//3.返回节点i对应的数据
public String getValueByIndex(int i) {
return vertexList.get(i);
}
//4.返回v1和v2的权值 v1 v2表示点的下标
public int getWeight(int v1, int v2) {
return edges[v1][v2];
}
//5.显示图对应的矩阵
public void showGraph() {
for (int[] arr : edges) {
for (int n : arr) {
System.out.print(n + " ");
}
System.out.println();
}
}
//插入节点
public void insertVertex(String vertex) {
vertexList.add(vertex);
}
//添加边
/**
* @param v1 表示点的下标,表示是第几个顶点 "A->"B": A: 0 B:1
* @param v2 第二个顶点的下标
* @param weight 表示关联的权值
*/
public void insertEdge(int v1, int v2, int weight) {
edges[v1][v2] = weight;
edges[v2][v1] = weight;
numOfEdges++;
}
}
数据结构和算法学习之图(深度优先/广度优先)
最新推荐文章于 2024-07-19 17:17:26 发布