目录
一、图的深度优先介绍
1.图遍历介绍
所谓图的遍历,即是对结点的访问。一个图有那么多个结点,如何遍历这些结点,需要特定策略,一般有两种
访问策略
:
(1)深度优先遍历 (2)广度优先遍历
2.深度优先遍历基本思想
图的深度优先搜索(Depth First Search) 。
1)
深度优先遍历,从初始访问结点出发,初始访问结点可能有多个邻接结点,深度优先遍历的策略就是首先访问
第一个邻接结点,然后再以这个被访问的邻接结点作为初始结点,访问它的第一个邻接结点, 可以这样理解:
每次都在访问完当前结点后首先访问当前结点的第一个邻接结点。
2)
我们可以看到,这样的访问策略是优先往纵向挖掘深入,而不是对一个结点的所有邻接结点进行横向访问。
3)
显然,深度优先搜索是一个递归的过程

3. 深度优先遍历算法步骤

package com.zengwen.graph;
import java.util.ArrayList;
import java.util.Arrays;
public class Graph {
private ArrayList<String> vertexList;//存储顶点集合
private int[][] edges;//存储图对应的邻接矩阵
private int numOfEdges;//表示边的数目
private boolean[] isVisited;//记录某个结点是否被访问
public Graph(int n){
//初始化矩阵和vertexList
edges = new int[n][n];
vertexList = new ArrayList<String>(n);
isVisited = new boolean[n];
numOfEdges = 0;
}
/**
* 根据前一个邻接结点的下标来获取下一个邻接结点
* @param v1
* @param v2
* @return
*/
public int getNextNeighbor(int v1, int v2){
for (int j = v2 + 1; j < vertexList.size(); j++) {
if (edges[v1][j] > 0){
return j;
}
}
return -1;
}
/**
* 得到第一个邻接结点的下标W
* @param index
* @return 存在W返回对应下标,否则返回-1
*/
public int getFirstNeighbor(int index){
for (int j = 0; j < vertexList.size(); j++) {
if (edges[index][j] > 0){
return j;
}
}
return -1;
}
//
/**
* 深度优先遍历算法
* @param isVisited
*/
public void dfs(boolean[] isVisited, int i){
//首先我们访问该节点,输出
System.out.println(getValueByIndex(i) + "->");
//将该节点设置为已经访问过
isVisited[i] = true;
//查找结点i的第一个邻接结点W
int w = getFirstNeighbor(i);
//判断是否存在
while (w != -1){//说明有
if (!isVisited[w]){//没有访问过
dfs(isVisited,w);
}
//如果已经被访问过
w = getNextNeighbor(i,w);
}
}
//对dfs进行一个重载,遍历所有节点,进行dfs
public void dfs(){
//遍历所有的节点,进行dfs
for (int i = 0; i < getNumOfVertex(); i++) {
if (!isVisited[i]){
dfs(isVisited,i);
}
}
}
//图中常用的方法
//显示顶点个数
public int getNumOfVertex(){
return vertexList.size();
}
//显示边的个数
public int getNumOfEdges(){
return numOfEdges;
}
//显示顶点
public String getValueByIndex(int i){
return vertexList.get(i);
}
//显示权值
public int getWeight(int v1, int v2){
return edges[v1][v2];
}
//显示图
public void showGraph(){
for (int[] link :
edges) {
System.err.println(Arrays.toString(link));
}
}
//插入结点
public void insertVertex(String vertex){
vertexList.add(vertex);
}
/**
*添加边
* @param v1 第一个顶点下标
* @param v2 第二个顶点下标
* @param weight 权值
*/
public void insertEdge(int v1, int v2, int weight){
edges[v1][v2] = weight;
edges[v2][v1] = weight;
numOfEdges++;
}
public static void main(String[] args) {
int n = 5;//顶点个数
String vertexValue[] = {"A","B","C","D","E"};
//创建图对象
Graph graph = new Graph(n);
for (String vertex : vertexValue){
graph.insertVertex(vertex);
}
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
graph.dfs();
}
}
二、图的广度优先遍历
2.1广度优先遍历基本思想
2.2 广度优先遍历算法步骤
package com.zengwen.graph;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.LinkedList;
public class Graph {
private ArrayList<String> vertexList;//存储顶点集合
private int[][] edges;//存储图对应的邻接矩阵
private int numOfEdges;//表示边的数目
private boolean[] isVisited;//记录某个结点是否被访问
public Graph(int n){
//初始化矩阵和vertexList
edges = new int[n][n];
vertexList = new ArrayList<String>(n);
isVisited = new boolean[n];
numOfEdges = 0;
}
/**
* 根据前一个邻接结点的下标来获取下一个邻接结点
* @param v1
* @param v2
* @return
*/
public int getNextNeighbor(int v1, int v2){
for (int j = v2 + 1; j < vertexList.size(); j++) {
if (edges[v1][j] > 0){
return j;
}
}
return -1;
}
/**
* 得到第一个邻接结点的下标W
* @param index
* @return 存在W返回对应下标,否则返回-1
*/
public int getFirstNeighbor(int index){
for (int j = 0; j < vertexList.size(); j++) {
if (edges[index][j] > 0){
return j;
}
}
return -1;
}
//
/**
* 深度优先遍历算法
* @param isVisited
*/
public void dfs(boolean[] isVisited, int i){
//首先我们访问该节点,输出
System.out.println(getValueByIndex(i) + "->");
//将该节点设置为已经访问过
isVisited[i] = true;
//查找结点i的第一个邻接结点W
int w = getFirstNeighbor(i);
//判断是否存在
while (w != -1){//说明有
if (!isVisited[w]){//没有访问过
dfs(isVisited,w);
}
//如果已经被访问过
w = getNextNeighbor(i,w);
}
}
//对dfs进行一个重载,遍历所有节点,进行dfs
public void dfs(){
//遍历所有的节点,进行dfs
for (int i = 0; i < getNumOfVertex(); i++) {
if (!isVisited[i]){
dfs(isVisited,i);
}
}
}
//对一个节点进行广度优先遍历的方法
private void bfs(boolean[] isVisited, int i){
int u;//表示队列的头结点对应下标
int w;//邻接结点
//队列,记录结点访问的顺序
LinkedList queue = new LinkedList();
//访问这个结点
System.out.print(getValueByIndex(i) + "=>");
//标记为已访问
isVisited[i] = true;
//将结点加入队列
queue.addLast(i);
while(!queue.isEmpty()){
//取出队列的头结点下标
u = (Integer)queue.removeFirst();
//得到第一个邻接结点的下标w
w = getFirstNeighbor(u);
while (w != -1){//找到
//是否访问过
if (!isVisited[w]){
System.out.print(getValueByIndex(w) + "=>");
//标记已经访问
isVisited[w] = true;
//入队列
queue.addLast(w);
}
//已经访问过,以u为出发点找w后面的下一个邻接点
w = getNextNeighbor(u,w);//bsf与dfs不同之处
}
}
}
//遍历所有的节点,都进行广度优先搜索
public void bfs(){
for (int i = 0; i < getNumOfVertex(); i++) {
if (!isVisited[i]){
bfs(isVisited,i);
}
}
}
//图中常用的方法
//显示顶点个数
public int getNumOfVertex(){
return vertexList.size();
}
//显示边的个数
public int getNumOfEdges(){
return numOfEdges;
}
//显示顶点
public String getValueByIndex(int i){
return vertexList.get(i);
}
//显示权值
public int getWeight(int v1, int v2){
return edges[v1][v2];
}
//显示图
public void showGraph(){
for (int[] link :
edges) {
System.err.println(Arrays.toString(link));
}
}
//插入结点
public void insertVertex(String vertex){
vertexList.add(vertex);
}
/**
*添加边
* @param v1 第一个顶点下标
* @param v2 第二个顶点下标
* @param weight 权值
*/
public void insertEdge(int v1, int v2, int weight){
edges[v1][v2] = weight;
edges[v2][v1] = weight;
numOfEdges++;
}
public static void main(String[] args) {
int n = 5;//顶点个数
String vertexValue[] = {"A","B","C","D","E"};
//创建图对象
Graph graph = new Graph(n);
for (String vertex : vertexValue){
graph.insertVertex(vertex);
}
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
// graph.dfs();
//测试bfs
graph.bfs();
}
}