如何检测节点网络中是否存在闭环之java实现

原创 2015年07月10日 22:32:24

所谓节点网络指的是任一节点与其他若干节点之间存在直接的联系,从而形成一种网络结果,在数学和计算机科学领域中也被称为图。其中闭环又称为回路,指的的是某一节点顺着关系链既是关系链的起点又是关系链的终点。即A->B->C->D->A 如图所示


为了判断节点网络中是否存在闭环,本文采用的基本思想是逐步遍历整个网络,每次访问某个节点都将改节点相关信息存储在一个哈希结构的集合里(这里使用HashMap),并最终检测该集合中是否有重复的来达到检查网络中是否含有闭环的情况。


本次实现的网络节点数据结构如下表所示:

node
nodeName: String
relList: List
curRelIndex: int
beforeNode: String


代码实现如下,本人测试了节点为4的情况,由于本人时间有限,不能测试更多的情况,如果以下程序有bug,欢迎各位在评论里提出,谢谢。

import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;

public class GraphAnalysis {
/**
	 * 
	 * 功能:判断网络中是否存在闭环
	 * 作者:EugeneJao
	 * @param nodeCollections
	 * @return
	 * @throws Exception
	 */
	public boolean isContainLoop(Map<String,Map<String,Object>> nodeCollections) throws Exception{
		//用map的hash码计算,速度更快
		Map<String,String> visitedList = new HashMap<String, String>();
		/**
		 * 初始化"起点
		 */
		String startNode = getOrigin(nodeCollections);
		
		boolean containLoop = false ;
		/**
		 * 初始化"视野"
		 */
		Map<String,String> nodeName = new HashMap<String, String>() ;
		nodeName.put("nextNode", startNode);
		nodeName.put("curNode", startNode);
		nodeName.put("beforeNode", startNode);
		
		int count = 0 ;
		
		/**
		 * 如果当前不含有闭环,并且没有遍历完起点节点的所有分支则进入循环
		 */
		while(!containLoop 
				&& !(nodeName.get("beforeNode").equals(nodeName.get("curNode")) 
				&& nodeName.get("nextNode") == null )){
			
			nodeName = traverse(nodeCollections, nodeName, visitedList);
			
			if(count > 1){
				containLoop = containSameNode(visitedList,nodeName.get("nextNode"));
			}
						
			count ++ ;
			
		}
		
		return containLoop;
		
	}
	
	/**
	 * 
	 * 功能:随机获取起始节点
	 * 作者:EugeneJao
	 * @param nodeCollections
	 * @return
	 */
	@SuppressWarnings("rawtypes")
	private String getOrigin(Map<String,Map<String,Object>> nodeCollections){
		
		Set keySet = nodeCollections.entrySet();
		 
		Iterator it = keySet.iterator() ;
		
		 List<String> keyArr = new ArrayList<String>(); 
		
		while(it.hasNext()){
			Entry tmpSet = (Entry) it.next() ;		
			keyArr.add((String) tmpSet.getKey()) ;
		}
		
		int randomInteger = (int) (Math.random() * keyArr.size()) ;
		
		return  keyArr.get(randomInteger) ;
		
		
	}
	
	/**
	 * 
	 * 功能:访问某个网络节点
	 * 作者:EugeneJao
	 * @param nodeCollections
	 * @param nodeName
	 * @param visitedList
	 * @return
	 * @throws Exception
	 */
	private Map<String,String> traverse(Map<String,Map<String,Object>> nodeCollections , Map<String,String> nodeName ,
			Map<String, String> visitedList) throws Exception{
		/**
		 * 判断前进节点在网络中存不存在
		 */
		if(nodeName.get("nextNode") != null){
			if(!(nodeCollections.containsKey(nodeName.get("nextNode")))){
				throw new Exception("节点网络构建异常,网络中不存在节点:" + nodeName);
			}
		}
		
		if(nodeName.get("curNode") == null || nodeName.get("beforeNode") == null){
			throw new Exception("traverse()方法入参异常:curNode和beforeNode不能为空" + nodeName);
		}
		
		String nextNodeName =  nodeName.get("nextNode") ;
		 
		if( nextNodeName  == null){
			
			nodeName = back(nodeCollections, nodeName);
			
		}else{
			
			nodeName = head(nodeCollections, nodeName, visitedList);
			
		}
		
		return nodeName ;
		
	}
	
	/**
	 * 
	 * 功能:前进至下一个节点
	 * 作者:EugeneJao
	 * @param nodeCollections
	 * @param nodeName
	 * @param visitedList
	 * @return
	 */
	@SuppressWarnings("unchecked")
	private Map<String,String> head(Map<String,Map<String,Object>> nodeCollections , Map<String,String> nodeName ,
			 Map<String, String> visitedList){
		String  curNodeName = nodeName.get("nextNode") ; //传入参数的nextNode在本方法中即是当前节点
		String beforeNodeName = nodeName.get("curNode") ;//传入参数的curNode在本方法中即是前一节点
		Map<String,Object> curNode = nodeCollections.get(curNodeName);
		List<String> relList = (List<String>) curNode.get("relList") ;
		curNode.put("beforeNode",beforeNodeName) ;//传入参数的beforeNode在本方法中即是当前节点
		int curRelIndex = getNextNodeIndex(curNode);
		/**
		 * 获取下一个前进的目标节点名称,当curRelIndex等于relList的长度时,
		 * 说明当前节点的所有关系节点都遍历完了,已无节点可以前进,只能后退
		 */
		String nextNodeName = null ;
		if(curRelIndex < relList.size()){
			nextNodeName = relList.get(curRelIndex) ; 
		}
		
		
		
		/**
		 * 更新当前节点信息
		 */
		curNode.put("curRelIndex", curRelIndex);//不能调整顺序值调用getNextNodeIndex()方法后面
		nodeCollections.put(curNodeName, curNode);
		/**
		 * 更新nodeName信息
		 */
		nodeName.put("nextNode", nextNodeName);
		nodeName.put("curNode", curNodeName);
		nodeName.put("beforeNode", beforeNodeName);
		/**
		 * 更新visitedList信息
		 */
		visitedList.put(curNodeName,null) ;
		return nodeName;
		
		
	}
	
	/**
	 * 
	 * 功能:后退至之前的节点
	 * 作者:EugeneJao
	 * @param nodeCollections
	 * @param nodeName
	 * @return
	 */
	@SuppressWarnings("unchecked")
	private Map<String,String> back(Map<String,Map<String,Object>> nodeCollections , Map<String, String> nodeName){
		String  curNodeName = nodeName.get("beforeNode") ; //传入参数的beforeNode在本方法中即是当前节点
		
		Map<String,Object> curNode = nodeCollections.get(curNodeName);
		List<String> relList = (List<String>) curNode.get("relList") ;
		String beforeNodeName = (String) curNode.get("beforeNode");
		/**
		 * 先更新当前节点beforeNode信息,因为后面要用
		 */
		curNode.put("beforeNode", beforeNodeName);//不能调整顺序值调用getNextNodeIndex()方法后面
		
		int curRelIndex = getNextNodeIndex(curNode);
		/**
		 * 获取下一个前进的目标节点名称,当curRelIndex等于relList的长度时,
		 * 说明当前节点的所有关系节点都遍历完了,已无节点可以前进,只能后退
		 */
		String nextNodeName = null ;
		if(curRelIndex < relList.size()){
			nextNodeName = relList.get(curRelIndex) ; 
		}
		
		/**
		 * 更新当前节点信息
		 */
		curNode.put("curRelIndex", curRelIndex);//不能调整顺序值调用getNextNodeIndex()方法前面
		
		nodeCollections.put(curNodeName, curNode);
		/**
		 * 更新nodeName信息
		 */
		nodeName.put("nextNode", nextNodeName);
		nodeName.put("curNode", curNodeName);
		nodeName.put("beforeNode",beforeNodeName) ;
		
		
		return nodeName;
		
	}
	
	
	
<span style="white-space:pre">	</span>/**
  <span style="white-space:pre">	</span>* 
 <span style="white-space:pre">	</span>* 功能:检测是否存在环路
 <span style="white-space:pre">	</span>* 作者:EugeneJao
<span style="white-space:pre">	</span>* @param visitedList
	* @param curNodeName
	* @return
	*/
	private boolean containSameNode(Map<String, String> visitedList,String curNodeName){
		
		if(visitedList.containsKey(curNodeName)){
			return true ;
		}
		
		return false;
		
	}
	
	/**
	 * 
	 * 功能:获取下一节点名称在relList里的索引值
	 * 作者:EugeneJao
	 * @param curNode
	 * @return
	 */
	@SuppressWarnings("unchecked")
	private int getNextNodeIndex(Map<String,Object> curNode){
		List<String> relList = (List<String>) curNode.get("relList") ;
		int curRelIndex = (Integer) curNode.get("curRelIndex") ;
		String beforeNodeName = (String) curNode.get("beforeNode");
		String nextNodeName = beforeNodeName ;
		//判断是否可以进入while循环,条件一:上一节点名称是否可下一节点名称相同,条件二:数组是否越界
		boolean canAdd = beforeNodeName.equals(nextNodeName) && curRelIndex < relList.size()-1 ;
		while(canAdd){
			curRelIndex ++ ;
			nextNodeName = relList.get(curRelIndex) ;
						
			canAdd = beforeNodeName.equals(nextNodeName) && curRelIndex < relList.size()-1;
		}
		/**
		 * 若果经过前面运算后,前一节点名称和下一节点名称依然相同,
		 * 则说明当前节点的关系节点全都遍历过了,curRelIndex赋值为relList的大小,
		 * 即说明当前节点的关系节点全都遍历过了,不能前进了,只能后退
		 */
		if(beforeNodeName.equals(nextNodeName) || relList.size() == 0){
			curRelIndex = relList.size() ;
		}
		return curRelIndex ;
	}
	
}




版权声明:本文为博主原创文章,未经博主允许不得转载。

三维重建:闭环检测

还是不要看了,高翔的科普读物已经出版了,读他的《slam十四讲》就可以了。 三维重建过程中,滤波方法可以看做是一种追踪方法。EM方法的长期使用造成在相对整个世界坐标系中累计误差的指数级增长。若是检测到...
  • wishchin
  • wishchin
  • 2017年03月30日 17:48
  • 1117

Java判断单链表是否有环的两种实现方法

package demo6;import java.util.HashMap;import demo6.LinkReverse2.Node; /** * 判断链表是否有环的方法 * @author...
  • JQ_AK47
  • JQ_AK47
  • 2016年10月05日 17:18
  • 6615

如何确定一个链表中有闭环,如果有怎么确定起始点?

这个问题很有趣,首先我第一个直觉是用图论的知识来解决,但是这是不可行的.因为我们没有办法将每一个节点的信息保存起来(这样的代价过于巨大,每一个节点标志唯一的就是它本身的地址,但是地址这个信息不能直接映...
  • pp634077956
  • pp634077956
  • 2015年12月26日 22:42
  • 3642

【Java】给定一个有环链表,实现算法返回环路的开头结点

假设链表有一部分是环路,一部分不是,环路起始处距离链表表头有K个结点 1. 创建两个指针:FastRunner 和 SlowRunnerpublic class FindLoopBegining {...
  • michellechouu
  • michellechouu
  • 2015年07月09日 15:34
  • 1043

有向图闭环检测值java代码实现

本文有向图闭环检测算法和实现由文章《如何检测节点网络中是否存在闭环之java实现》中的无向图闭环检测算法的基础上修改得到,其中修改点如下: 1.修改了数据结构,在原来无向图闭环检测算法的数据结构的基础...
  • seveneagleline
  • seveneagleline
  • 2015年08月12日 21:53
  • 1884

检测有向图中的环

题目 http://www.geeksforgeeks.org/detect-cycle-in-a-graph/ Java实现 import java.util.ArrayList; import ...
  • u010157717
  • u010157717
  • 2015年03月17日 02:38
  • 680

基于深度优先算法的有向图环路检测

1、digraph.h  #ifndef _DIGRAPH_H_H #define _DIGRAPH_H_H #define ENABLE_DIGRAPH_TEST 0 #define CHECK...
  • liujianfeng1984
  • liujianfeng1984
  • 2015年08月19日 08:00
  • 2160

闭环Java应用

你曾经因为部署/上线而痛苦吗?你曾经因为要去运维那改配置而烦恼吗?在我接触过的一些部署/上线方式中,曾碰到过以下一些问题: 1、程序代码和依赖都是人工上传到服务器,不是通过工具进行部署和发布; ...
  • u010942020
  • u010942020
  • 2016年08月16日 09:25
  • 690

链表的底层实现方式

链表在我们日常的开发过程中应该说是非常常见,做移动开发的更可以说是每天都在接触。比如MessageQueue,底层就是单链链表,各种网络框架用到的队列,底层用到的都是链表。而说到链表,就不得不提到另外...
  • xu404741377
  • xu404741377
  • 2017年06月21日 09:38
  • 1056

(8) Java源码分析 ---- LinkedList (对应数据结构中线性表中的双向循环链表,JDK1.6)

一、源码解析 1、 LinkedList类定义 2、LinkedList数据结构原理 3、私有属性 4、构造方法 5、元素添加add()及原理 6、删除数据remove() 7、数据获取get() 8...
  • pandajava
  • pandajava
  • 2015年01月04日 09:32
  • 1521
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:如何检测节点网络中是否存在闭环之java实现
举报原因:
原因补充:

(最多只允许输入30个字)