`
若是人间
  • 浏览: 76286 次
  • 性别: Icon_minigender_1
  • 来自: 上海
社区版块
存档分类
最新评论

java 图的深度优先与广度优先排序

阅读更多

一个图包括两部分信息:顶点的信息以及描述顶点之间关系的信息。


图的邻接矩阵存储也称数组表示法,其方法是用一个一维数组存储图中顶点的信息,用一个二维数组存储图中边的信息,存储顶点之间邻接关系的二维数组称为邻接矩阵。


用邻接矩阵存储图


1. 确定图的顶点个数和边的个数

2. 输入顶点信息存储在一维数组 vertex

3. 初始化邻接矩阵;

4. 依次输入每条边存储在邻接矩阵 arc

  1.  
    1. 输入边依附的两个顶点的序号 i,j;

    2. 将邻接矩阵的第 i 行第 j 列的元素值置为 1

    3. 将邻接矩阵的第 j 行第 i 列的元素值置为 1



由于大部分图都是稀疏图利用邻接矩阵存储开销会很大。 n 条边的用二维数组来表示的话,开销就是 n*n, 对于这种情况,对邻接矩阵做一下变化,用一个一维数组 vertex[] 来存储顶点的集合 , 再用一个一维数组来存储边的信息,数组的每一个元素都记录边的起始点,终点的相关信息,这样就能将边的存储开销降为 n


利用上述方法来构造,在查找的时候每次都得查找一次,则最坏的效率为 e (边数)的 n 次方,查找比较快捷的方式可以采用链表来实现。对于图的每个顶点 v ,将所有邻接于 v 的顶点链成一个单链表,所有边表的头指针和存储顶点信息的一维数组构成了顶点表,所以,在邻接表中存在两种结点结构:顶点表结构和边表结构。


利用一个一维数组来保存来保存顶点信息。给每一个顶点分配一个 vector Vector 的每一个元素都保存着与顶点有关的一条边信息,这样,对于无向图来说,得到的存储效率为 n+2e, 而对于有向图来说,得到的存储效率为 n+e; 再可以分配一个规则,对于无向图来说,每次记录边的时候都可以采用从顶点位置低的向顶点位置高的记录,这样能使无向图的存储效率达到 n+e

 

<!-- @page { margin: 2cm } P { margin-bottom: 0.21cm } -->

图的遍历是指从图中某一顶点出发,对图中所有顶点访问一次且仅访问一次。

图的遍历通常有深度优先遍历与广度优先遍历两种方式,这两种遍历次序对无向图和有向图都适用。

 

深度优先递归方法实现:

 

1. 访问顶点 v; visited[v]=1;

2.w= 顶点 v 的第一个邻接点

3.while(w 存在 )

  1.  
    1. if(w 未被访问 ) 从顶点 w 出发递归执行该算法

    2. w= 顶点 v 的下一个邻接点

 

广度优先遍历实现:

 

1. 初始化队列 Q

2. 访问顶点 v visited[v]=1; 顶点 v 入队 Q;

3.while( 队列 Q 非空 )

  1.  
    1. v= 队列 Q 的队头元素出队;

    2. w= 顶点 v 的第一个邻接点

    3. while(w 存在 )

        3.3.1 如果 w 未被访问,则访问顶点 w;visited[w]=1; 顶点 w 入队列 Q

        3.3.2 w= 顶点 v 的下一个邻接点


以下是利用vector来存储图的遍历实现:

 

Stack类:

package com.javaeye.rsrt;

/**
 * 栈,遵循先进后出的原则,用来保存元素
 * 
 * @author nishiting
 * 
 */
public class Stack {

	private int[] st;
	private int top;
	private int count;

	/**
	 * 构造一个栈
	 * 
	 * @param size
	 *            栈的大小
	 */
	public Stack(int size) {
		st = new int[size];
		top = -1;
		count = 0;
	}

	/**
	 * 元素进栈
	 * 
	 * @param j
	 *            要进栈的元素
	 */

	public void push(int j) {
		count++;
		st[++top] = j;
	}

	/**
	 * 元素出栈
	 * 
	 * @return 出栈的元素
	 */

	public int pop() {

		return st[top--];
	}

	/**
	 * 查询栈顶元素
	 * 
	 * @return 栈顶元素
	 */

	public int peek() {
		return st[top];
	}

	/**
	 * 查询栈是否为空
	 * 
	 * @return 栈是否为空
	 */

	public boolean isEmpty() {
		count--;
		return (top == -1);
	}

	/**
	 * 查看栈里的所有元素
	 */

	public void list() {

		for (int i = 0; i < count; i++) {

			System.out.print(st[i] + "   ");

		}
		System.out.println();
	}

	/**
	 * 得到栈里一共有多少元素
	 * 
	 * @return 栈里的元素个数
	 */
	public int getCount() {
		return count;
	}

	/**
	 * 查看栈里是否包含某个元素
	 * 
	 * @param i
	 *            要查询的元素
	 * @return 是否包含了要查询的元素
	 */

	public boolean isContains(int i) {
		for (int k = 0; k < st.length; k++) {

			System.out.print("开始比较" + i + "此时的result:");
			list();
			System.out.println();
			if (st[k] == i) {
				return true;
			}
		}
		return false;
	}
	
	/**
	 * 得到栈里的元素集
	 * @return 栈里的元素集合
	 */
	public int[] getSt(){
		return st;
	}

}
 

 

Queue类:

package com.javaeye.rsrt;

public class Queue {

	private int[] values;
	private int begin = -1;
	private int end = -1;
	
	Queue(int size){
		values = new int[size];
	}
	
	void push(int value){
		values[++begin] = value;
	}
	
	int pop(){
		return values[++end];
	}
	
	boolean isEmpty(){
		return begin == end;
	}
}

 Graph类:

package com.javaeye.rsrt;

import java.util.Vector;

/**
 * 
 * @author nishiting
 * 
 */

public class Graph {

	int vertexNum;
	Vector[] vector;
	int[] visited;
	Stack stack;
	Stack result;
	Queue queue;

	/**
	 * 
	 * 构造一个图
	 * 
	 * @param num
	 *            图的顶点数
	 * 
	 */
	public Graph(int num) {

		vertexNum = num;
		vector = new Vector[vertexNum];

		visited = new int[vertexNum];
		for (int i = 0; i < num; i++) {
			visited[i] = 0;
		}
		stack = new Stack(num);
		result = new Stack(num);
		queue = new Queue(num);

	}

	/**
	 * 向图中添加无向边
	 * 
	 * @param I
	 *            边的一个顶点
	 * @param J
	 *            边的另一个顶点
	 * @return 是否添加成功
	 */
	public boolean addEdge(int I, int J) {

		/**
		 * 判断用户输入的是否是一个顶点,如果是,则返回flase,添加不成功
		 */
		if (J == I) {
			return false;
		}

		/**
		 * 判断所输入的顶点值是否在图所顶点范围值内,如果不在,则提示顶点不存在
		 * 
		 */
		if (I < vertexNum && J < vertexNum && I >= 0 && J >= 0) {

			int k;
			
			/**
			 * 如果i比j大,则将i与j交换
			 */

			if (I > J) {
				k = I;
				I = J;
				J = k;
			}

			/**
			 * 
			 * 判断边是否存在
			 */

			if (isEdgeExists(I, J)) {

				return false;
			}
			
			/**
			 * 添加边
			 */

			vector[I].add(J);
			return true;
		}
		return false;
	}

	/**
	 * 判断无向边是否存在
	 * 
	 * @param i
	 *            要查询的无向边的一个顶点
	 * @param j
	 *            要查询的无向边的另一个顶点
	 * @return 边是否存在,false:不存在,true:存在
	 */

	public boolean isEdgeExists(int i, int j) {

		/**
		 * 判断所输入的顶点值是否在图所顶点范围值内,如果不在,则提示顶点不存在
		 * 
		 */
		if (i < vertexNum && j < vertexNum && i >= 0 && j >= 0) {

			if (i == j) {
				return false;
			}

			int k;

			/**
			 * 如果i比j大的话,i与j进行交换
			 */

			if (i > j) {
				k = i;
				i = j;
				j = k;
			}

			/**
			 * 判断i的邻接结点集是否为空
			 */

			if (vector[i] == null) {
				vector[i] = new Vector(8);
			}

			/**
			 * 判断这条边是否存在,如果存在,则提示边已经存在
			 */
			for (int q = 0; q < vector[i].size(); q++) {

				if (((Integer) vector[i].get(q)).intValue() == j) {
					System.out.println("顶点" + i + "和" + "顶点" + j + "这两点之间存在边");
					return true;

				}
			}
		}
		return false;
	}

	/**
	 * 进行深度优先遍历
	 */
	public void dfs() {
		
		/**
		 * 从顶点0开始遍历
		 */

		visited[0] = 1;
		stack.push(0);
		
		/**
		 * 如果栈不为空的话,进行循环查询
		 */

		while (!stack.isEmpty()) {

			int v = getAdjUnvisitedVertex(stack.peek());
			
			/**
			 * 没找到未被访问的邻接点,元素出栈,如果找到的话,将这个结点标记为访问过,将其未被访问的邻接点入栈
			 */

			if (v == -1) {
				result.push(stack.peek());
				stack.pop();

			} else {
				visited[v] = 1;
				stack.push(v);

			}
		}

		System.out.println("进行深度优先的遍历顺序为:");
		result.list();

	}
	
	/**
	 * 进行广度优先遍历
	 */
	
	public void bsf(){
		
		/**
		 * 从顶点0开始遍历
		 */
		visited[0] = 1;
		queue.push(0);
		
		while(!queue.isEmpty()){
			int v = queue.pop();
			result.push(v);
			int i;
			while((i = getAdjUnvisitedVertex(v))!=-1){
				visited[i]=1;
				queue.push(i);
			}
			
		}
		System.out.println("广度优先的遍历顺序为:");
		result.list();
		
	}

	/**
	 * 得到指定结点的一个未被访问的邻接点位置
	 * 
	 * @param v
	 *            要查询的顶点
	 * @return 顶点的下一个未被访问的邻接结点
	 */

	public int getAdjUnvisitedVertex(int v) {
		int temp;

		/**
		 * 判断邻接结点是否为空
		 */

		if (vector[v] != null) {

			/**
			 * 遍历所有的邻接结点
			 */
			for (int j = 0; j < vector[v].size(); j++) {
				temp = ((Integer) vector[v].get(j )).intValue();
				/**
				 * 判断邻接结点是否被访问过
				 */
				if (visited[temp] == 0)
					return ((Integer) vector[v].get(j)).intValue();

			}

		}

		return -1;
	}
	
	

	/**
	 * 得到图的遍历顺序
	 * 
	 * @return 图的遍历顺序
	 */

	public Stack getResult() {
		return result;
	}

}

 测试类:

package com.javaeye.rsrt;

import junit.framework.TestCase;

public class GraphTest extends TestCase {

	public void testAddEdge(){
		
//		Graph graph = new Graph(10);
//		
//		/**
//		 * 测试向两个相同的顶点添加边
//		 */
//		assertEquals(false,graph.addEdge(1, 1));
//		assertEquals(false,graph.isEdgeExists(1, 1));
//		
//		/**
//		 * 测试向不存在的点添加边
//		 */
//		assertEquals(false,graph.addEdge(-1, 1));
//		assertEquals(false,graph.isEdgeExists(-1, 1));
//		assertEquals(false,graph.addEdge(1, 15));
//		assertEquals(false,graph.isEdgeExists(1, 15));
//		assertEquals(false,graph.addEdge(-1, 15));
//		assertEquals(false,graph.isEdgeExists(-1, 15));
//		
//		/**
//		 * 测试向两个合理的点添加边
//		 */
//		assertEquals(true,graph.addEdge(1,6));
//		assertEquals(true,graph.isEdgeExists(1, 6));
//		
//		/**
//		 * 测试向已有班的顶点添加
//		 */
//		assertEquals(true,graph.isEdgeExists(1, 6));
//		assertEquals(false,graph.addEdge(1,6));
//		/**
//		 * 测试向边缘的点添加边
//		 * 
//		 */
//		assertEquals(true,graph.addEdge(0, 9));
//		assertEquals(true,graph.isEdgeExists(0, 9));
//		
//		/**
//		 * 测试无向图由位置大的点向位置小的点添加
//		 */
//		assertEquals(true,graph.addEdge(8, 4));
//		assertEquals(true,graph.isEdgeExists(8, 4));
		
		
		/**
		 * 测试一个简单的连通图
		 */
		
		Graph graph = new Graph(6);
		graph.addEdge(0, 1);
		graph.addEdge(0, 5);
		graph.addEdge(0, 2);
		graph.addEdge(1, 2);
		graph.addEdge(2, 3);
		graph.addEdge(1, 4);
		graph.addEdge(2, 4);
		
		graph.bsf();
		
//		graph.dfs();
//		int[] values = {3,4,2,1,5,0};
//		int[] result = graph.getResult().getSt();
//		for(int i = 0;i < values.length;i++){
//			assertEquals(values[i],result[i]);
//		}
		
		/**
		 * 测试一个非连通图
		 * 
		 */
//		graph = new Graph(6);
//
//		graph.addEdge(0, 1);
//		graph.addEdge(0, 5);
//		graph.addEdge(0, 2);
//		graph.addEdge(1, 2);
//		graph.addEdge(1, 4);
//		graph.addEdge(2, 4);
//		
//		graph.dfs();
//		
//		values = new int[] {4,2,1,5,0};
//		result = graph.getResult().getSt();
//		for(int i = 0;i < values.length;i++){
//			assertEquals(values[i],result[i]);
//		}
	}
}
 

 

 

 

5
0
分享到:
评论
2 楼 mywjch 2012-03-24  
很棒[size=x-large][/size]
1 楼 chenwq 2011-11-10  
顶!并收藏着!

相关推荐

    java 深度优先遍历、广度优先遍历、最短路径、最小生成树

    本文将深入探讨Java中实现的四个核心图算法:深度优先遍历(DFS)、广度优先遍历(BFS)、最短路径算法以及最小生成树算法。 首先,**深度优先遍历(DFS)**是一种用于遍历或搜索树或图的算法。它从根节点开始,尽...

    用Java实现二叉树的深度优先、广度优先遍历

    本篇文章将深入探讨如何使用Java来实现二叉树的深度优先遍历(DFS, Depth First Search)和广度优先遍历(BFS, Breadth First Search)。 **深度优先遍历** 是一种在图或树中搜索的方法,它尽可能深地探索树的分支...

    Java实现图的深度优先遍历和广度优先遍历

    根据遍历方式的不同,图的遍历可以分为深度优先遍历(DFS)和广度优先遍历(BFS)。本文将深入探讨这两种遍历方法,并提供其在Java中的实现。 ### 图的深度优先遍历(DFS) 深度优先遍历是一种递归地访问图中的...

    java 图 邻接表 深度优先遍历 广度优先遍历 最短路径

    用Java描述的图,以邻接表存储,包含常用算法

    图的几种常用算法(广度/深度优先搜索,最小生成树,弗洛伊德,拓扑排序....)java实现,简单易懂。

    本资源包含了一些图算法的Java实现,包括但不限于广度优先搜索(BFS)、深度优先搜索(DFS)、最小生成树(Minimum Spanning Tree, MST)、弗洛伊德算法(Floyd-Warshall)以及拓扑排序。下面将详细介绍这些算法及其...

    图的广度优先搜索和深度优先搜索

    本文将详细探讨两种主要的图遍历算法:广度优先搜索(Breadth-First Search, BFS)和深度优先搜索(Depth-First Search, DFS),以及它们在Java编程语言中的实现。 **广度优先搜索(BFS)** 1. **概念**: 广度...

    20180729数据结构与算法基础班深度优先搜索

    深度优先搜索(DFS,Depth-First Search)是图论与数据结构中的一种经典搜索算法,广泛应用于解决实际问题,如网络爬虫、迷宫求解、拓扑排序等。本课程“20180729数据结构与算法基础班深度优先搜索”将深入探讨这一...

    广度优先搜索学习五例之二(JAVA)

    【标题】:“广度优先搜索学习五例之二(JAVA)” 在计算机科学中,图算法是解决问题的关键工具之一,而广度优先搜索(Breadth-First Search, BFS)是一种用于遍历或搜索树或图的算法。本篇文章将重点讲解如何在...

    图的深度和广度遍历(Java实现)

    本篇将详细讲解如何使用Java实现图的深度优先遍历(DFS, Depth-First Search)和广度优先遍历(BFS, Breadth-First Search)。 1. **深度优先遍历(DFS)**: - DFS 是一种递归策略,它沿着某条路径深入到图的深处...

    泛型应用--图的深度(广度)优先遍历.成语接龙例

    总结起来,这个案例展示了如何利用Java泛型构建一个图数据结构,以及如何使用深度优先和广度优先遍历进行图的探索。泛型使我们的代码更具通用性,能够处理不同类型的数据,而图遍历算法则帮助我们解决实际问题,如...

    2015北大ACM-ICPC暑期课(广度优先搜索)

    在ACM-ICPC的训练中,BFS通常与图论和树的其他算法结合使用,例如深度优先搜索(DFS)、Dijkstra算法、Floyd-Warshall算法等,来解决更复杂的问题。对于树的遍历,BFS可以保证找到最接近根的路径。在图中,BFS能找出两...

    Java经典算法教程:深度优先搜索(DFS)算法

    这种策略倾向于先访问深度较大的节点,而不是广度较大的节点,与之相对的是广度优先搜索(BFS)。 在Java中实现DFS,通常使用递归或栈数据结构。递归方法是直接对每个未访问的邻接节点进行递归调用,而栈方法则将待...

    Graph-DFS_WFS.zip_java无向图_wfs遍历_深度优先遍历

    本文将详细讲解"Graph-DFS_WFS.zip"压缩包中涉及的知识点,包括Java实现的无向图、深度优先遍历(DFS)以及宽度优先遍历(WFS)。 首先,我们来理解什么是无向图。无向图是一种图结构,其中的边没有方向性,即任意...

    深度学习java及其算法详解

    在这个资源中,你可能会遇到排序算法(如冒泡排序、快速排序、归并排序)、查找算法(如线性查找、二分查找)以及图算法(如深度优先搜索、广度优先搜索)。理解这些基础算法可以帮助你编写更高效、更优化的代码。 ...

    深度优先搜索学习五例之一(JAVA)

    深度优先搜索(DFS, Depth-First Search)是一种用于遍历或搜索树或图的算法,其基本思想是从起点开始,沿着某一条路径一直探索到尽可能深的层次,如果在当前路径上找不到目标,则回溯到上一个节点,换另一条路径继续...

    list集合树状排序-java

    实现这个功能的一种方法是遍历List,将所有节点构建成一棵树,然后采用深度优先搜索(DFS)或广度优先搜索(BFS)来获取排序后的节点列表。遍历过程中,可以使用HashMap或其他数据结构暂存节点及其子节点,以便于...

    拓扑排序应用系统java.zip

    在`src`目录下,我们可能找到具体的拓扑排序算法实现,如`Graph.java`(表示图的类)、`Node.java`(表示图节点的类)和`TopologicalSort.java`(拓扑排序算法类)。这些类可能包含了构建图、计算入度、遍历和排序的...

    java九宫排序算法

    4. **深度优先搜索(DFS)**:DFS是一种遍历或搜索树或图的算法,沿着树的深度优先遍历树的节点。在九宫格问题中,可以将每个宫格看作一个节点,从左上角开始,尝试填入下一个节点,若满足条件则继续,否则回溯。 5...

    本周算法图的拓扑排序Java开发Java经验技巧共6页.p

    通常有两种主要的拓扑排序算法:深度优先搜索(DFS)和广度优先搜索(BFS)。 1. 深度优先搜索(DFS)拓扑排序: - 从任意一个没有前驱(入度为0)的顶点开始,进行DFS遍历。 - 访问过的顶点标记为已处理,并从其...

    GUI的Java课表排序

    接着,拓扑排序的核心算法有两种常见方法:深度优先搜索(DFS)和广度优先搜索(BFS)。DFS会首先访问所有没有前驱(入度为0)的节点,然后递归地访问其后继节点;BFS则使用队列,同样从没有前驱的节点开始,逐层...

Global site tag (gtag.js) - Google Analytics