matlab 无向拓扑图,无向图绘画树状拓扑图算法

基于目前Network项目需要,研究相关树形算法

该需求难点如下:

1、目前拓扑图是无向图,而树大多数都是基于有向图来画的,无法确定根节点

2、网络拓扑中存在回环问题,导致链路可能会存在重叠问题

针对问题1,目前根据所有节点的连通度来计算得出连通度最大的点作为根节点。

问题2目前没有完美的解决方案。

目前这边demo的算法分为2种

1、根据每层叶子节点个数切割X轴坐标,然后平均分布在一条直线上。

效果图如下:

0bc6b890a961?utm_campaign=maleskine&utm_content=note&utm_medium=seo_notes&utm_source=recommendation

代码比较简单,暂时就不公布了。

2、类似于一种递归的方式,从第一层叶子节点开始切割X轴,第二层叶子节点的范围不能超过上层节点之间的节点间距。

直接看图:

0bc6b890a961?utm_campaign=maleskine&utm_content=note&utm_medium=seo_notes&utm_source=recommendation

这种方式的弊端显而易见,如果后面存在大量叶子节点的枝节点,那么这里的叶子会非常密集

改变一下根节点样子或许会好一些,但是这边会出现回路重合链路问题:

0bc6b890a961?utm_campaign=maleskine&utm_content=note&utm_medium=seo_notes&utm_source=recommendation

下面贴上部分代码:

public ResponseEntity getTreeTopo() {

NodeList nodeList = new NodeList();

HashMap nodeCountMap = new HashMap<>();

//统计所有节点的连通度

for (int i = 0; i < lineTempList.size(); i++) {

if (nodeCountMap.containsKey(lineTempList.get(i).getUplinkNodeId().toString())) {

nodeCountMap.get(lineTempList.get(i).getUplinkNodeId().toString())

.setCount(nodeCountMap.get(lineTempList.get(i).getUplinkNodeId().toString()).getCount() + 1);

} else {

Connectivity connectivity = new Connectivity();

connectivity.setCount(1);

nodeCountMap.put(lineTempList.get(i).getUplinkNodeId().toString(), connectivity);

}

if (nodeCountMap.containsKey(lineTempList.get(i).getNodeId().toString())) {

nodeCountMap.get(lineTempList.get(i).getNodeId().toString())

.setCount(nodeCountMap.get(lineTempList.get(i).getNodeId().toString()).getCount() + 1);

} else {

Connectivity connectivity = new Connectivity();

connectivity.setCount(1);

nodeCountMap.put(lineTempList.get(i).getNodeId().toString(), connectivity);

}

}

//找到最大连通度的节点

int maxConnectivity = 0;

String rootNodeId = "";

for(String nodeId : nodeCountMap.keySet()) {

if(nodeCountMap.get(nodeId).getCount()>maxConnectivity) {

maxConnectivity = nodeCountMap.get(nodeId).getCount();

rootNodeId = nodeId;

}

}

int treeLevel = 1; //树高度

Set nodeSet = new HashSet<>();//记录所有已经分配过坐标的节点,用于查重

Map nodePositionMap = new HashMap<>();//记录所有节点坐标

Map subNodesCountMap = new HashMap<>();

rootNodeId="35";//手工设置根节点

nodeSet.add(rootNodeId);

NodeListInner rootNode = new NodeListInner();

rootNode.setNodeId(rootNodeId);

rootNode.setX("2000");

rootNode.setY("400");//假设画布为4000*4000

nodeList.add(rootNode);

nodePositionMap.put(rootNodeId, rootNode);

//根节点放在(2000,400)位置

List subPoint = getSubPoint(rootNodeId, nodeSet, subNodesCountMap);

subNodesCountMap.get(rootNodeId).setSpace(3800);//两边各留100空间

List parentPoint = new ArrayList<>();//需要保留父节点的信息

Point rootPoint = new Point();

rootPoint.setNodeId(rootNodeId);

rootPoint.setParentId(null);

parentPoint.add(rootPoint);

while (subPoint.size() != 0) {// 如果遍历到树的最高一层,则结束循环

//根据父节点的位置来分配叶子节点的位置

for(int j=0;j

if(subNodesCountMap.get(parentPoint.get(j).getNodeId()).getCount()==0) {

continue;

}

int gap = subNodesCountMap.get(parentPoint.get(j).getNodeId()).getSpace() / subNodesCountMap.get(parentPoint.get(j).getNodeId()).getCount();//子节点得到点与点之间的间距距离

int rightDeviation = 0;//单数往右偏移

int leftDeviation = - gap;//双数往左偏移

//获得子节点数据

List point = new ArrayList<>();

point = getSubPoint(parentPoint.get(j).getNodeId(), nodeSet, subNodesCountMap);

//遍历节点然后赋予坐标值

for(int i=0;i

if(!subNodesCountMap.containsKey(point.get(i).getNodeId())) {

NodeCount nodeCount = new NodeCount();

nodeCount.setSpace(gap);

subNodesCountMap.put(point.get(i).getNodeId(), nodeCount);

} else {

subNodesCountMap.get(point.get(i).getNodeId()).setSpace(gap);//这一个迭代的子节点是下一个迭代的父节点

}

NodeListInner node = new NodeListInner();

node.setNodeId(point.get(i).getNodeId());

if((i+1)%2==1) {//单数往右偏移

node.setX((rightDeviation+Integer.parseInt(nodePositionMap.get(parentPoint.get(j).getNodeId()).getX()))+"");

node.setY(400+treeLevel*400+"");

rightDeviation += gap;

} else {//双数往左偏移

node.setX((leftDeviation+Integer.parseInt(nodePositionMap.get(parentPoint.get(j).getNodeId()).getX()))+"");

node.setY(400+treeLevel*400+"");

leftDeviation -= gap;

}

nodePositionMap.put(point.get(i).getNodeId(),node);

nodeList.add(node);

nodeSet.add(node.getNodeId());

}

}

parentPoint = new ArrayList<>(subPoint);

subPoint.clear();

for (int i = 0; i < parentPoint.size(); i++) {//统计还有没有下一层叶子节点

subPoint.addAll(getSubPoint(parentPoint.get(i).getNodeId(), nodeSet, subNodesCountMap));

}

treeLevel+=1;

}

for (int j = 0; j < nodeList.size(); j++) {//补上节点之间的线

List lines = new ArrayList<>();

for (int i = 0; i < lineTempList.size(); i++) {

if (nodeList.get(j).getNodeId().equals(lineTempList.get(i).getUplinkNodeId().toString())) {

Line line = new Line();

line.setDest(lineTempList.get(i).getNodeId().toString());

line.setDestX(nodePositionMap.get(lineTempList.get(i).getNodeId().toString()).getX());

line.setDestY(nodePositionMap.get(lineTempList.get(i).getNodeId().toString()).getY());

lines.add(line);

}

}

nodeList.get(j).setLine(lines);

}

HttpHeaders headers = new HttpHeaders();

headers.setContentType(MediaType.APPLICATION_JSON_UTF8);

headers.add("Access-Control-Allow-Methods", "POST, GET, OPTIONS, DELETE, PUT");

headers.add("Access-Control-Allow-Origin", "*");

headers.add("Access-Control-Allow-Headers", "x-requested-with,content-type");

return new ResponseEntity(nodeList, headers, HttpStatus.OK);

}

private List getSubPoint(String nodeId, Set nodeSet, Map subNodesCountMap) {

int count = 0;

List result = new ArrayList<>();

for (int i = 0; i < lineTempList.size(); i++) {

if (lineTempList.get(i).getUplinkNodeId().toString().equals(nodeId)) {

if (!nodeSet.contains(lineTempList.get(i).getNodeId().toString())) {

// 存储对端节点

Point point = new Point();

point.setNodeId(lineTempList.get(i).getNodeId().toString());

point.setParentId(nodeId);

result.add(point);

count++;

}

}

if (lineTempList.get(i).getNodeId().toString().equals(nodeId)) {

if (!nodeSet.contains(lineTempList.get(i).getUplinkNodeId().toString())) {

// 存储对端节点

Point point = new Point();

point.setNodeId(lineTempList.get(i).getUplinkNodeId().toString());

point.setParentId(nodeId);

result.add(point);

count++;

}

}

}

if(!subNodesCountMap.containsKey(nodeId)) {

NodeCount nodeCount = new NodeCount();

nodeCount.setCount(count);

subNodesCountMap.put(nodeId, nodeCount);

} else {

subNodesCountMap.get(nodeId).setCount(count);

}

return result;

}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/357602.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Java Mail+MYSQL+Tomcate+jsp实现企业快信系统

导读:首先对企业快信的开发进行了较深入的研究,然后对短信发送与邮件发送原理进行了介绍,接下来对系统的概要设计、功能模块、数据库设计,以及名片夹管理功能与邮件发送功能的具体实现作了细致阐述,最后是系统效果的展示。企业快信系统是一个集短信与邮件为一体的移动商务…

odbc连接oracle失败,大神解答win7系统ODBC无法连接ORACLE的处理方案

随着电脑的使用率越来越高&#xff0c;我们有时候可能会遇到win7系统ODBC无法连接ORACLE问题&#xff0c;如果我们遇到了win7系统ODBC无法连接ORACLE的问题&#xff0c;要怎么处理win7系统ODBC无法连接ORACLE呢&#xff1f;我们只用1)操作系统是Win7 x64&#xff0c;客户端是Or…

spring-mvc教程_使用MVC模式制作游戏-教程和简介

spring-mvc教程游戏开发中一种有用的体系结构模式是MVC&#xff08;模型视图控制器&#xff09;模式。 它有助于分离输入逻辑&#xff0c;游戏逻辑和UI&#xff08;渲染&#xff09;。 在任何游戏开发项目的早期阶段&#xff0c;它的用途很快就会被注意到&#xff0c;因为它可以…

web前端开发需要学什么(包含前端学习路线)

前端开发&#xff0c;做到后面&#xff0c;是可以走很多方向的&#xff1b;但是要保证后期的平滑过度&#xff0c;前期还是要把一些必须的知识搞扎实的&#xff1b;web前端开发需要学什么环境搭建前端环境很好搭建&#xff0c;编辑器浏览器即可。浏览器推荐使用 Chrome行业内主…

2015年必火的五个Html5移动开发工具推荐

NO.1 DCloudHBuilder:基于HTML5开发工具 中文官网&#xff1a;http://www.dcloud.io/ DCloudHBuilder:基于HTML5开发工具是当前最快的HTML开发工具&#xff0c;强大的代码助手帮你快速完成开发&#xff0c;最全的语法库和浏览器兼容 性数据让浏览器碎片化不再头痛&#xff0c…

想当程序员,如何判断自己是否适合当前端程序员?

说在前面&#xff1a;有粉丝提问说自己并不确定学前端&#xff0c;因为自己还没有工作&#xff0c;想做程序员&#xff0c;想问问做哪个方向比较有前途&#xff1b; 有两三个小伙伴这么问的&#xff0c;感觉很有意义&#xff0c;拿出来单独说说比较好。 目录 程序员有哪些选择&…

个税社保

资料来源&#xff1a;http://finance.qq.com/cross/20160218/H9cM96A8.html?pgv_refaio2015&ptlang2052转载于:https://www.cnblogs.com/weikang/p/5200832.html

前端程序员如何选择适合自己的培训机构

web前端开发培训哪家好这个主要是根据自己的情况来选择&#xff0c;本篇文章主要分享怎么选择适合自己的培训机构市场上有哪些培训机构以及所在位置既然关心哪家培训机构好&#xff0c;基本都是有报班学习的意向&#xff0c;所以就不多说自学和报班的区别了&#xff1b;我是不排…

altium designer 10哪个作者写的好 。

问题截图&#xff1a; 博主解答&#xff1a; 其实这种书籍基本内容都差不多&#xff0c;很多都是作者来回借鉴&#xff0c;我们能根据自己的需要学到知识即可。

新浪微博开发-添加子视图控制器设置颜色

一.添加子视图控制器 二.设置颜色 设置颜色&#xff1a;两种方法 一种较为繁琐&#xff0c;详见视频 第二种&#xff1a; //设置颜色 self.tabBar.tintColor UIColor.orangeColor()转载于:https://www.cnblogs.com/torrescx/p/5237142.html

Android studio的sdk tools下没有LLDB的解决办法

粉丝提问&#xff1a; 博主解答: 解决办法&#xff1a; 点击setting--》plugins--》找到“Android Support”选项&#xff0c;并勾选&#xff0c;然后会提示重启android studio &#xff0c;点击重启&#xff0c;ok&#xff0c;如果已经设置好SDK的路径的话&#xff0c;问题解…

随机JCache内容:多个提供程序和JMX Bean

JCache&#xff08;JSR 107&#xff09;是用于缓存的Java标准…足够了。 没有更多介绍性的东西。 这是一则速成文章&#xff0c;内容涉及 多个JCache提供程序配置&#xff0c;以及 功能&#xff1a;通过JMX Mbeans的JCache统计信息 管理多个JCache提供程序 如果您只使用一个…

linux下spi添加设备,Linux Kernl添加spidev的设备节点

一、spidev介绍如果在内核中配置spidev&#xff0c;会在/dev目录下产生设备节点&#xff0c;通过此节点可以操作挂载在该SPI总线上的设备。用户空间通过该节点可以访问内核空间。二、配置spidev设备步骤在i.MX6&#xff0c;Kernel 4.1.15上配置spidev的支持。1、配置dts支持spi…

Android studio Jin开发生成so文件的具体步骤

粉丝提问&#xff1a; 博主解答&#xff1a; 帖子链接&#xff1a;https://blog.csdn.net/wangsfine/article/details/51445199

linux中改变文件大小,Linux 改变文件大小的方法

函数原型&#xff1a;#include int ftruncate(int fd, off_t length); //改变文件大小为length指定大小;返回值 执行成功则返回0&#xff0c;失败返回-1。函数ftruncate会将参数fd指定的文件大小改为参数length指定的大小。参数fd为已打开的文件描述词&#xff0c;而且必须是以…

apktool重新打包,error:No resource identifier found for attribute ‘compileSdkVersionCodename‘ in package

报错日志:AndroidManifes.xml :1 error:No resource identifier found for attribute compileSdkVersionCodename in package ‘android’ 粉丝提问: 报错图: 博主解答:

终端-进入云服务器

解决办法: 1.先进入管理员模式: 2.下一步&#xff0c;链接服务器。 3.已经连接上服务器&#xff1a; 4.找到云服务器的项目路径: 在这里&#xff1a; 我们可以在cd空格/ 按Tab寻找下个文件夹&#xff0c;也可以输入ls查看文件夹。转载于…

Android studio 清除缓存数据的步骤

导读:在eclipse的当中进行运行Android的运用的程序的时候,就会产生内存缓存的信息,而eclipse是可以直接点击停止运行程序,然后点击清除缓存,就可以解决了这个问题,而Android studio却不能直接点击停止运行的,而只能通过其它的方式来清除Android studio中的缓存。 可以看…

linux 函数 文件校验,Linux中的文件效验命令

在网络传输、设备之间转存、复制大文件等时&#xff0c;可能会出现传输前后数据不一致的情况。这种情况在网络这种相对更不稳定的环境中&#xff0c;容易出现。那么校验文件的完整性&#xff0c;也是势在必行的。md5sum命令用于生成和校验文件的md5值&#xff0c;MD5全称报文摘…

设置按钮5秒后可以点击下一步||5秒后自动关闭网页

场景:业务需要在点击拍摄的时候提示一个用户须知页面,5秒后可以点击下一步。这属于一个js计时器的功能。这里用jQuery实现一下 效果图: html <div style="text-align: center;"><input type="button" value="下一步" id="next…