图的遍历算法(DFS和BFS)

1.    图的深度遍历DFS

可采用递归和循环两种方式实现。

方法一:采用递归的方式。

定义一个标志数组表示某个结点是否已经被访问过。以邻接矩阵的形式表示图。依次对深度遍历图中的每个未被遍历过的结点,然后针对该结点未被遍历过的邻接点再进行深度遍历,每个结点被遍历后加入到结果中,并且设定该结点已经被访问过。

方法二:不采用递归的方式而是采用栈保存已经遍历过并且还有其孩子结点可能还没有遍历过的结点。与递归方式中一样,也是定义一个标志数组表示某个结点是否已经被访问过。始化栈内存放第一个结点。判断栈顶元素的第一个还未被访问邻接点,把它压入到栈中,每个结点入栈的时候,把其对应的标志数组元素设为true同时把该结点放到结果中。如果栈顶元素没有了未被访问的邻接点,则将该元素弹栈。循环直到栈空。

/**
	 * 方法一:采用递归的方式。
	 * 定义一个标志数组表示某个结点是否已经被访问过。
	 * 以邻接矩阵的形式表示图。
	 * 依次对深度遍历图中的每个未被遍历过的结点,针对该结点未被遍历过的邻接点再进行深度遍历,每个结点被遍历后加入到结果中,并且设定该结点已经被访问过。
	 */
	public static boolean visited[];
	public static ArrayList<Integer> list = new ArrayList<Integer>();
	public static ArrayList<Integer> DFS_Graph1(int graph[][]){
		int size = graph.length;//求得结点的个数
		visited = new boolean[size];
		/*Step1:依次遍历树中还未被遍历的结点*/
		for(int i=0;i<size;i++){
			if(visited[i] == false){
				visited[i] = true;
				list.add(i);
				/*Step2:深度遍历以结点i为开始的路径上的结点*/				          DFS(graph,i);
			}
		}
		return list;		
	}
	/**
	 * 深度递归遍历以图中node结点为起点的结点。
	 * @param graph
	 * @param node
	 */
	public static void DFS(int graph[][],int i){
		int size = graph.length;
		for(int j=0;j<size;j++){
			/*这个当前结点可达且未被访问的结点j才可以*/
			if(graph[i][j] == 1 && visited[j] == false){
				visited[j] = true;
				list.add(j);
				DFS(graph,j);
			}
		}
	}
	
	/**
	 * 方法二:不采用递归的方式而是采用栈保存已经遍历过并且还有其孩子结点可能还没有遍历过的结点。
	 * 与递归方式中一样,也是定义一个标志数组表示某个结点是否已经被访问过。
	 * 初始化栈内存放第一个结点。
	 * 判断栈顶元素的第一个还未被访问邻接点,把它压入到栈中,每个结点入栈的时候,把其对应的标志数组元素设为true同时把该结点放到结果中。
	 * 如果栈顶元素没有了未被访问的邻接点,则将该元素弹栈。
	 * 一直循环直到栈空。
	 * 
	 * @param graph
	 * @return
	 */
	public static ArrayList<Integer> DFS_Graph2(int graph[][]){
		Stack<Integer> stack = new Stack<Integer>();
		int size = graph.length;
		visited = new boolean[size];
		/*Step1:把初始第一个结点放到栈内*/
		stack.push(0);
		visited[0] = true;
		list.add(0);
		/*	
		 * Step2:找栈顶元素的第一个还未被访问邻接点,把它压入到栈中,
		 * 每个结点入栈的时候,把其对应的标志数组元素设为true同时把该结点放到结果中。 
		 * 如果栈顶元素没有了未被访问的邻接点,则将该元素弹栈。
		 * 循环结束的条件是栈为空。
		 */
		while(!stack.isEmpty()){
			int i = stack.peek();//读栈顶元素
			int j = 0;
			/*找栈顶元素的第一个未被访问的邻接点*/
			for(;j<size;j++){
				if(graph[i][j] == 1 && visited[j] == false){
					break;
				}
			}
			if(j<size){//说明找到了
				visited[j] = true;
				list.add(j);
				stack.push(j);
			}else{//只有当前栈顶元素不存在未被访问的邻接点时才弹出栈顶元素
				stack.pop();
			}
		}
		return list;
	}

  

2. 图的广度优先遍历

       借助队列实现,同时设置一个包含结点个数的visited数组表示某个结点是否已经被遍历过。

       初始化时把第一个结点加入到结果list中,并且把visited[0]设置为true。

       循环开始时队列中存储的是图中的第一个结点,循环结束的条件是队列变成空。

       循环体内取出队列的第一个元素,并且把这个元素的所有未被访问过的邻接点都加入到队列中、加入到结果list中、设置其对应的状态为已访问。

      类似于树的层次遍历.

/**
	 * 图的广度优先遍历。
	 * 借助队列实现,同时设置一个包含结点个数的visited数组表示某个结点是否已经被遍历过。
	 * 初始化时把第一个结点加入到结果list中,并且把visited[0]设置为true。
	 * 循环开始时队列中存储的是图中的第一个结点,循环结束的条件是队列变成空。
	 * 循环体内取出队列的第一个元素,并且把这个元素的所有未被访问过的邻接点都加入到队列中、加入到结果list中、设置其对应的状态为已访问。
	 */
	public static boolean visited[];
	public static ArrayList<Integer> list = new ArrayList<Integer>();
	public static ArrayList<Integer> BFS_Graph(int graph[][]){
		Queue<Integer> queue = new ArrayBlockingQueue<Integer>(10);
		int size = graph.length;
		visited = new boolean[size];
		/*Step1:把初始第一个结点放到栈内。*/
		queue.add(0);
		visited[0] = true;
		list.add(0);
		int i ;
		/*Step2:循环队列中的元素直到队列为空。*/
		while(!queue.isEmpty()){
			i = queue.poll();
			for(int j =0;j<size;j++){//找刚刚被弹出队列的队头元素可达的点
				if(graph[i][j] ==1 && visited[j] == false){
					visited[j] = true;
					list.add(j);
					queue.add(j);
				}
			}
		}
		return list;
	}

    原文作者:数据结构之图
    原文地址: https://blog.csdn.net/u010339647/article/details/52263118
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞