图的深度优先遍历和广度优先遍历(java实现)

  • Post author:
  • Post category:java




一.图的深度优先遍历


1.基本思想


从初始访问节点出发,首先访问第一个节点,然后再以这个被访问的节点的邻接节点作为初始节点,访问它的第一个邻接节点,依次进行,显然这是一个递归的过程


2.算法步骤


1)访问初始节点v,并标记节点v以访问

2)查找节点v的第一个邻接节点w

3)若w存在,执行4,若w不存在,回到第一步,从v的下一个节点继续

4)若w未被访问,对w进行深度优先遍历递归

5)若w被访问,以下一个邻接节点作为初始节点进行递归


3.代码实现

//得到第一个结点的下标
	public int getfirstNeighbor(int index){
		for(int j=0;j<vertexList.size();j++){
			if(edges[index][j]>0){
				return j;
			}
		}
		return -1;
	}
	
	//根据前一个邻接节点的下标来获取下一个邻接节点
	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;
	}
	
	//深度优先遍历
	/* isVisited[] 记录节点是否访问的数组
	 * i 第一次是0
	 */
	public void dfs(boolean[] isVisited,int i){
		//首先访问该节点,输出
		System.out.print(getValueByIndex(i)+"->");
		isVisited[i]=true;
		int w=getfirstNeighbor(i);
		while(w!=-1){
			//说明有邻接节点
			if(!isVisited[w]){
				dfs(isVisited,w);
			}
			
			//如果该节点被访问
			w=getNextNeighbor(i,w);
		}
	}
	
	//重载dfs方法
	public void dfs(){
		isVisited=new boolean[vertexList.size()];
		//遍历所有的节点进行dfs回溯
		for(int i=0;i<vertexList.size();i++){
			if(!isVisited[i]){
				dfs(isVisited,i);
			}
		}
	}
	



二.图的广度优先遍历


1.基本思想


与深度优先遍历不同的是,广度优先在选出初始节点后,依次访问与初始节点邻接的节点,直到没有节点与之邻接,同时,广度优先遍历需要使用一个队列来保持访问过节点的顺序。


2.算法步骤


1)访问初始节点v并标记v为已访问

2)节点v入队列

3)当队列非空时,继续执行,否则算法结束

4)出队列,取得队头节点u

5)查找节点u的第一个邻接节点w

6)若节点u的邻接节点w不存在,进行步骤3,否则循环执行以下三个步骤

6.1若w未被访问,则访问节点w并记为已访问

6.2节点w入队列

6.3查找节点u的继ww邻接节点的下一个邻接节点w,转到步骤6


3.代码

//广度优先遍历
	public void bfs(boolean isVisited[],int i){
		int u; //表示队列的头节点对应下标
		int w; //邻接节点
		//队列,记录访问节点的顺序
		LinkedList queue=new LinkedList();
		//输出访问节点信息
		System.out.println(getValueByIndex(i)+"->");
		//标记为已访问
		isVisited[i]=true;
		//将一访问的节点加入队列
		queue.addLast(i);
		while(!queue.isEmpty()){
			//取出队列的头节点下标
			u=(Integer)queue.removeFirst();
			//得到第一个邻接节点的下标
			w=getfirstNeighbor(u);
			while(w!=-1){
				//是否访问过
				if(!isVisited[w]){
					System.out.println(getValueByIndex(w)+"->");
					//标记为已访问
					isVisited[w]=true;
					//入队
					queue.addLast(w);
				}
				//以u为前驱点,找w后面的下一个节点
				w=getNextNeighbor(u,w);
			}
		}
	}
	
	//遍历所有的节点,都进行广度优先搜索
	public void bfs(){
		isVisited=new boolean[vertexList.size()];
		for(int i=0;i<vertexList.size();i++){
			if(!isVisited[i]){
				bfs(isVisited,i);
			}
		}
	}



3.全部代码

package text_six_tu;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.LinkedList;

public class one {
	private ArrayList<String> vertexList;//存储节点集合
	private int[][] edges;//存储邻接矩阵
	private int numOfEdges;//表示边的数目
	//判断节点是否已经访问
	private boolean[] isVisited;

	public static void main(String[] args) {
		int n=6;
		String vertexs[]={"A","B","C","D"};
		one graph=new one(6);
		for(String vertex : vertexs){
			graph.insertVertex(vertex);
		}
		
		graph.insertEdge(0, 1, 2);
		graph.insertEdge(0, 2, 5);
		graph.insertEdge(2, 3, 5);
		graph.insertEdge(1, 3, 8);
		
		graph.showGreph();
		graph.bfs();

	}
	//构造器
	public one(int n){
		vertexList = new ArrayList<String>(n);
		edges=new int[n][n];
		numOfEdges=0;
		
	}
	
	//得到第一个结点的下标
	public int getfirstNeighbor(int index){
		for(int j=0;j<vertexList.size();j++){
			if(edges[index][j]>0){
				return j;
			}
		}
		return -1;
	}
	
	//根据前一个邻接节点的下标来获取下一个邻接节点
	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;
	}
	
	//深度优先遍历
	/* isVisited[] 记录节点是否访问的数组
	 * i 第一次是0
	 */
	public void dfs(boolean[] isVisited,int i){
		//首先访问该节点,输出
		System.out.print(getValueByIndex(i)+"->");
		isVisited[i]=true;
		int w=getfirstNeighbor(i);
		while(w!=-1){
			//说明有邻接节点
			if(!isVisited[w]){
				dfs(isVisited,w);
			}
			
			//如果该节点被访问
			w=getNextNeighbor(i,w);
		}
	}
	
	//重载dfs方法
	public void dfs(){
		isVisited=new boolean[vertexList.size()];
		//遍历所有的节点进行dfs回溯
		for(int i=0;i<vertexList.size();i++){
			if(!isVisited[i]){
				dfs(isVisited,i);
			}
		}
	}
	
	//广度优先遍历
	public void bfs(boolean isVisited[],int i){
		int u; //表示队列的头节点对应下标
		int w; //邻接节点
		//队列,记录访问节点的顺序
		LinkedList queue=new LinkedList();
		//输出访问节点信息
		System.out.println(getValueByIndex(i)+"->");
		//标记为已访问
		isVisited[i]=true;
		//将一访问的节点加入队列
		queue.addLast(i);
		while(!queue.isEmpty()){
			//取出队列的头节点下标
			u=(Integer)queue.removeFirst();
			//得到第一个邻接节点的下标
			w=getfirstNeighbor(u);
			while(w!=-1){
				//是否访问过
				if(!isVisited[w]){
					System.out.println(getValueByIndex(w)+"->");
					//标记为已访问
					isVisited[w]=true;
					//入队
					queue.addLast(w);
				}
				//以u为前驱点,找w后面的下一个节点
				w=getNextNeighbor(u,w);
			}
		}
	}
	
	//遍历所有的节点,都进行广度优先搜索
	public void bfs(){
		isVisited=new boolean[vertexList.size()];
		for(int i=0;i<vertexList.size();i++){
			if(!isVisited[i]){
				bfs(isVisited,i);
			}
		}
	}
	//返回节点个数
	public int getnumOfVertsx(){
		return vertexList.size();
	}
	//显示图对应的矩阵
	public void showGreph(){
		for(int[] link : edges){
			System.out.println(Arrays.toString(link));
		}
	}
	//得到边的数目
	public int getOfEdges(){
		return numOfEdges;
	}
	//返回节点i
	public String getValueByIndex(int i){
		return vertexList.get(i);
	}
	//返回v1和v2的权值
	public int getWeight(int v1,int v2){
		return edges[v1][v2];
	}
	//插入结点
	public void insertVertex(String vertex){
		vertexList.add(vertex);
	}
	//添加边
	public void insertEdge(int v1,int v2,int weight){
		edges[v1][v2]=weight;
		edges[v2][v1]=weight;
		numOfEdges++;
	}

}



版权声明:本文为weixin_44015485原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。