
图是一个基本的数据结构
- 在于理解图和java代码实现
1、为什么要图
复习一下我们之前学习的东西
- 线性表和树
- 线性表局限于只能连接一个前驱节点和一个后继节点
- 树也只能连接一个直接前驱也就是父节点
- 当我们需要表示多对多的情况时,这时候就表示两种结构都不能满足的情况(图产生的原因)
2、图的基本概念
图是一种数据结构,其中节点可以具有零个或多个相邻元素。两个节点之间的连接称为边,节点也可以称为顶点。(指不定我们的地图就是用这个来实现的)
3、图的表示方式
- 1表示它们之间能直接连通
- 0表示不能直接连通
- 左边一排表示我们的顶点
- 右边一排表示和对应节点的连接情况
1、题目
2、思路分析
- 首先得要有一个节点来存放顶点
- 其次是实现矩阵来进行图的表示
- 先看Graph
- 最后看主类
package cn;
import java.util.ArrayList;
import java.util.Arrays;
public class Main {
public static void main(String[] args) {
//测试
int n = 5;//节点的个数
String[] vertexs = {"A","B","C","D","E"};
Graph graph = new Graph(n);
//循环的添加顶点
for (String value : vertexs) {
graph.addVertex(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();
}
}
class Graph {
private ArrayList vertexList ;//存储我们顶点的集合
private int[][] edges;//存储图对应的邻结矩阵
private int numOfEdges;//表示边的个数
//构造器
public Graph() {
}
//构造器
public Graph(int n) {
edges = new int[n][n];
vertexList = new ArrayList<>(n);
numOfEdges = 0;//边不知道是多少,所以默认为0
}
public void addVertex(String n) {
vertexList.add(n);
}
public void insertEdge(int v1,int v2,int weight) {
edges[v1][v2] = weight;
edges[v2][v1] = weight;
numOfEdges++;
}
public int getNumOfVertex() {
return vertexList.size();
}
public int getNumOfEdges() {
return numOfEdges;
}
public String getValueByIndex(int x) {
return vertexList.get(x);
}
public int getWeight(int v1, int v2) {
return edges[v1][v2];
}
public void showGraph() {
for(int[] link: edges) {
System.out.println(Arrays.toString(link));
}
}
}
三、图的遍历
1、图的深度优先遍历
(1)概念
- 先看红色
- 看橙色
- 看蓝色
代码阅读建议:
- 首先去看Graph 类的方法八,九,十,十一,其他的不用管
- 最后看一下测试
package cn;
import java.util.ArrayList;
import java.util.Arrays;
public class Main {
public static void main(String[] args) {
//测试
int n = 5;//节点的个数
String[] vertexs = {"A","B","C","D","E"};
Graph graph = new Graph(n);
//循环的添加顶点
for (String value : vertexs) {
graph.addVertex(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();
System.out.println("深度遍历为" );
graph.dfs();
}
}
class Graph {
private ArrayList vertexList ;//存储我们顶点的集合
private int[][] edges;//存储图对应的邻结矩阵
private int numOfEdges;//表示边的个数
private boolean [] isVisited;//用于记录某个节点是否被访问
//构造器
public Graph() {
}
//构造器
public Graph(int n) {
edges = new int[n][n];
vertexList = new ArrayList<>(n);
numOfEdges = 0;//边不知道是多少,所以默认为0
isVisited = new boolean[n];
}
public void addVertex(String n) {
vertexList.add(n);
}
public void insertEdge(int v1,int v2,int weight) {
edges[v1][v2] = weight;
edges[v2][v1] = weight;
numOfEdges++;
}
public int getNumOfVertex() {
return vertexList.size();
}
public int getNumOfEdges() {
return numOfEdges;
}
public String getValueByIndex(int x) {
return vertexList.get(x);
}
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 int getFirstNeighbor(int index) {
//进行遍历
for (int i = 0; i < vertexList.size(); i++) {
if (edges[index][i] > 0) {
return i;
}
}
return -1;
}
public int getNextNeighbor(int v1,int v2) {
for (int i = v2 + 1; i < vertexList.size(); i++) {
if (edges[v1][i] > 0) {
return i;
}
}
return -1;
}
public void dfs(boolean[] isVisited,int i) {
//1、调用这个方法,说明进入了步骤中的第一步
System.out.print(getValueByIndex(i) + "->" );
//将该节点设置为已经访问
isVisited[i] = true;
//2、查找节点i的第一个相邻节点w
int w = getFirstNeighbor(i);
while (w != -1) {//说明有邻接节点
//4、要判断是否被访问过,如果没有被访问过
if (!isVisited[w]) {
//递归进行访问
dfs(isVisited,w);
}
//5、如果没有被访问过,则去找w的下一个节点
w = getNextNeighbor(i,w);
}
}
public void dfs() {
//遍历所有的节点,进行dfs[回溯]
for (int i = 0; i < getNumOfVertex(); i++) {
if (!isVisited[i]) {
dfs(isVisited,i);
}
}
}
}
2、图的广度优先遍历
(1)概念
1、基本思想
图的广度优先(Broad First Search),类似于一个分层搜索的过程,广度有点遍历需要使用一个队列以保持访问过的节点的顺序,以便这个节点的顺序来访问这个节点的相邻节点
2、基本步骤
- 访问初始节点v并标记节点v为已访问。
- 节点v入队列
- 当队列非空时,继续执行,否则算法结束【就是对v的第一次算法结束】
- 出队列,取得队头节点u
- 查找节点u的第一个相邻节点w
- 若节点u的相邻节点w不存在,则转到步骤3,否则循环执行以下三个步骤
- 若节点w尚未被访问,则访问节点w并标记为已访问。
- 节点w入队列
- 查找节点u的继w相邻节点后的下一个邻接节点w,转到步骤6
3、是这样的一个过程
public class Main {
public static void main(String[] args) {
//测试
int n = 5;//节点的个数
String[] vertexs = {"A","B","C","D","E"};
Graph graph = new Graph(n);
//循环的添加顶点
for (String value : vertexs) {
graph.addVertex(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();
System.out.println("广度优先");
graph.bfs();
}
}
class Graph {
private ArrayList vertexList ;//存储我们顶点的集合
private int[][] edges;//存储图对应的邻结矩阵
private int numOfEdges;//表示边的个数
private boolean [] isVisited;//用于记录某个节点是否被访问
//构造器
public Graph() {
}
//构造器
public Graph(int n) {
edges = new int[n][n];
vertexList = new ArrayList<>(n);
numOfEdges = 0;//边不知道是多少,所以默认为0
isVisited = new boolean[n];
}
public void addVertex(String n) {
vertexList.add(n);
}
public void insertEdge(int v1,int v2,int weight) {
edges[v1][v2] = weight;
edges[v2][v1] = weight;
numOfEdges++;
}
public int getNumOfVertex() {
return vertexList.size();
}
public int getNumOfEdges() {
return numOfEdges;
}
public String getValueByIndex(int x) {
return vertexList.get(x);
}
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 int getFirstNeighbor(int index) {
//进行遍历
for (int i = 0; i < vertexList.size(); i++) {
if (edges[index][i] > 0) {
return i;
}
}
return -1;
}
public int getNextNeighbor(int v1,int v2) {
for (int i = v2 + 1; i < vertexList.size(); i++) {
if (edges[v1][i] > 0) {
return i;
}
}
return -1;
}
public void dfs(boolean[] isVisited,int i) {
//1、调用这个方法,说明进入了步骤中的第一步
System.out.print(getValueByIndex(i) + "->" );
//将该节点设置为已经访问
isVisited[i] = true;
//2、查找节点i的第一个相邻节点w
int w = getFirstNeighbor(i);
while (w != -1) {//说明有邻接节点
//4、要判断是否被访问过,如果没有被访问过
if (!isVisited[w]) {
//递归进行访问
dfs(isVisited,w);
}
//5、如果没有被访问过,则去找w的下一个节点
w = getNextNeighbor(i,w);
}
}
public void dfs() {
//遍历所有的节点,进行dfs[回溯]
for (int i = 0; i < getNumOfVertex(); i++) {
if (!isVisited[i]) {
dfs(isVisited,i);
}
}
}
public void bfs(boolean[] isVisited,int i) {
int u;//表示队列的头节点对应的下标
int w;//整个过程会去找的,邻接的节点w
//队列,节点访问的顺序
linkedList
(3)留点问题
1、在测试的时候我们是不能同时测试的
原因是当我们深度遍历后,会把用于判断的数组全部置为true,所以全部不会输出。
2、解决办法是从新设计
在我们的构造方法不能直接赋值我们的用于判断的boolean数组。
欢迎分享,转载请注明来源:内存溢出
微信扫一扫
支付宝扫一扫
评论列表(0条)