加权GN算法的Java实现
本文为加权GN算法的Java实现,具体算法原理请参考前一篇文章GN算法的简介,整个代码可从http://download.csdn.net/detail/u012483487/9447115下载,如有不对,敬请指正。
加权GN 算法求解的具体实现过程为:
(1)忽略边的权重,以无权网络计算网络中所有连接边的边介数;
(2)将边介数除以对应边的权重得到边权比;
(3)找到边权比最高的边将它移除,并计算网络的模块性 Q 函数,在计算中当边权比最高的边有多条时,同时移除这些边,并将此时移除的边和Q值进行存储;
(4)重复步骤(1),(2),直到网络中所有的边均被移除。
(5)GN算法划分结束后,取出Q值最大时的序号,在原始矩阵中依次去除截止到该次划分的边。得出最终连通矩阵,矩阵的值为权值。
现在使用JAVA对上述算法进行简单的实现,声明全局变量:
private double[][] linkMatrix;//原始数据,在算法中不断删除边private double[][] originMatrix;//用于存储原始数据public List<Double> Qlist;//Q的集合public List<edgeInfo> deleteEgdes;//删除的边public ArrayList<nodeInfo> previousNodes;//Gn算法中一次已经成功入队的节点public ArrayList<nodeInfo> currentNodes;//Gn算法中的当前节点public ArrayList<ArrayList<nodeInfo>> resultList;public ArrayList<nodeInfo> record;//Gn算法中上一次访问过节点public double[] disArray;//Gn算法中一次的各个边的距离public double[] weightArray;//Gn算法中一次的各边的权重public double[][] disMatrix;//用于记录源节点与其他节点的距离public double[][] sumDisMatix;//记录边介数private int MAX_NUM;//最大的数目private int coperationNum;//统计社团的数目private int[] belong;//用于区别节点所述社团
以及节点对象和边对象
public class nodeInfo {public List<Integer> parentNodes;//父节点public List<Integer> childrenNodes; //子节点public int name;//public double weightOfNode;//点权,public nodeInfo(int n) {parentNodes=new ArrayList<Integer>();childrenNodes=new ArrayList<Integer>();name=n;//weightOfNode=1;}}//边对象private class edgeInfo{public int start;//开始的节点public int end;//结束的节点public double weightOfEdge;//边权public void setInfo(int a,int b,double c) {this.start=a;this.end=b;this.weightOfEdge=c;}}
初始化变量,申请内存空间。
private void init(){MAX_NUM=100;linkMatrix=new double[MAX_NUM][MAX_NUM];originMatrix=new double[MAX_NUM][MAX_NUM];Qlist=new ArrayList<Double>();deleteEgdes=new ArrayList<edgeInfo>();resultList=new ArrayList<ArrayList<nodeInfo>>();}
现在简单说明算法的实现,主要实现如下,不断对每一个在图中,不孤立的点使用GN算法。去除边介数最大的点,直到所有边都删除为止。结束后求出最大的Q值,依次按照删除边的顺序对originMartrix矩阵进行删除,得出最后的划分图。
public void calGn(){ while (true) {sumDisMatix=new double[MAX_NUM][MAX_NUM];coperationNum=0;belong=new int[MAX_NUM];//使用GN算法计算每一个点,从而得出边介数for(int i=0;i<MAX_NUM;i++)if(isNodeOut(i)==false){calOneNodeGn(i);}double max=0;int x=0,y=0;//删除边权比最高的边for(int i=0;i<MAX_NUM;i++)for(int j=0;j<MAX_NUM;j++){if(linkMatrix[i][j]>0)sumDisMatix[i][j]=sumDisMatix[i][j]/linkMatrix[i][j];else {sumDisMatix[i][j]=0;}}for(int i=0;i<MAX_NUM;i++)for(int j=0;j<MAX_NUM;j++)if(max<sumDisMatix[i][j]){max=sumDisMatix[i][j];x=i;y=j;}if(max==0)break;calQ();deleEdge(x,y);}//查找最大的Q值,此时为最佳划分double maxq=0;int index=0;for(int i=0;i<Qlist.size();i++){if(maxq<Qlist.get(i)){maxq=Qlist.get(i);index=i;}}System.out.print("maxQ:"+maxq+" "+"index:"+index);}
对单独节点使用GN算法,这里先忽略掉边的权值,使用无权GN算法。首先需要对源节点使用一次广度优先遍历,得出访问过的节点列表,之后对这一列表中各个节点依次使用广度优先遍历,直到没有其他相互连接的节点为止。在广度优先遍历的过程中,建立了以源节点为根节点的树状网络。在遍历的过程中,对每一个节点建立了父节点列表和子节点列表,用于确定该节点的父节点(可能有多个)和子节点(可能有多个)。其次,对节点的社团进行标记;最后,对该树状网络进行权值的计算,计算过程请看简介,计算出边介数之后一次算法的目的达到。
public void calOneNodeGn(int n){if(isNodeOut(n)==true)return ;disMatrix=new double[MAX_NUM][MAX_NUM];previousNodes=new ArrayList<dataPreprocessing.nodeInfo>();disArray=new double[MAX_NUM];weightArray=new double[MAX_NUM];Boolean isStop=false; int deep1=2;currentNodes=new ArrayList<dataPreprocessing.nodeInfo>();singleNodeGNFirst(new nodeInfo(n), 1);//不断往下寻找,建立以节点n为源节点的树while(isStop==false){isStop=true; record=currentNodes;currentNodes=new ArrayList<dataPreprocessing.nodeInfo>();for(int i=0;i<record.size();i++){boolean ldl=singleNodeGN(record.get(i),deep1);//如果还有子节点,继续循环if(ldl==true)isStop=false; } deep1++;// System.out.print(previousNodes.size()+"\n");}for(int i=0;i<previousNodes.size();i++){nodeInfo ne=previousNodes.get(i);if(ne.childrenNodes.size()==0) for(int j=0;j<ne.parentNodes.size();j++){int x=ne.parentNodes.get(j);disMatrix[i][x]=weightArray[x]/weightArray[i];disMatrix[x][i]=disMatrix[i][x];}}//对叶子节点进行赋初值double max=0;int num=0;for(int i=0;i<MAX_NUM;i++)if(max<disArray[i]){max=disArray[i];num=i;}//此时把previousNodes中与最后一个相同的节点归为同一社团,并且标记int first=previousNodes.size()-1;if(belong[first]==0){coperationNum++;belong[first]=coperationNum;}for(int i=previousNodes.size()-1;i>=0;i--){int x=previousNodes.get(i).name;if(belong[x]==0)belong[x]=coperationNum;}//进行第二步,计算各边的权重for(int i=previousNodes.size()-1;i>=0;i--)singleSencondStep(previousNodes.get(i).name,n);//计算边介数for(int i=0;i<MAX_NUM;i++)for(int j=0;j<MAX_NUM;j++){sumDisMatix[i][j]+=disMatrix[i][j];}}
public Boolean singleNodeGNFirst(nodeInfo nn,int deep){ //System.out.println(deep+"\n");boolean res=true;int n=nn.name;previousNodes.add(nn); for(int i=0;i<MAX_NUM;i++){if(linkMatrix[n][i]>0){ nodeInfo ne=new nodeInfo(i); nodeInfo parentInfo=findNodeInfoById(n, previousNodes); parentInfo.childrenNodes.add(i);//为父子关系ne.parentNodes.add(n); currentNodes.add(ne);disArray[i]=deep;weightArray[i]=1;}}for(int j=0;j<MAX_NUM;j++){if(linkMatrix[n][j]>0){if(disArray[j]==0)res=false;}}return res;}
//广度优先遍历节点public Boolean singleNodeGN(nodeInfo nn,int deep){ //System.out.println(deep+"\n");boolean res=false;int n=nn.name;if(findNodeInfoById(n, previousNodes)==null)previousNodes.add(nn); for(int i=0;i<MAX_NUM;i++){if(linkMatrix[n][i]>0){ nodeInfo ne=new nodeInfo(i); if(findNodeInfoById(n, record)!=null&&(findNodeInfoById(i, record)!=null))break;if((findNodeInfoById(i, previousNodes)==null)){nodeInfo parentInfo=findNodeInfoById(n, previousNodes);if(findNodeInfoById(i, currentNodes)==null){parentInfo.childrenNodes.add(i);//为父子关系ne.parentNodes.add(n);//currentNodes.add(ne);//如果在当前访问节点中为空并且从未被访问过res=true;}else {{parentInfo.childrenNodes.add(i);//为父子关系findNodeInfoById(i, currentNodes).parentNodes.add(n);res=true;}}if(disArray[i]==0){disArray[i]=deep;weightArray[i]=weightArray[parentInfo.name];}else if(disArray[i]==deep){weightArray[i]=weightArray[n]+weightArray[i];}else if(disArray[i]<deep);else {;}}}}/* for(int j=0;j<MAX_NUM;j++){if(linkMatrix[n][j]>0){if(disArray[j]==0)res=false;}}*/return res;}
//计算各边的权重public void singleSencondStep(int n,int source){nodeInfo neInfo=findNodeInfoById(n, previousNodes);for(int j=0;j<neInfo.parentNodes.size();j++){nodeInfo pa=findNodeInfoById(neInfo.parentNodes.get(j), previousNodes);double q=1;for(int k=0;k<neInfo.childrenNodes.size();k++)q+=disMatrix[n][neInfo.childrenNodes.get(k)];int x=neInfo.parentNodes.get(j);if(pa.name!=source){if(weightArray[n]!=0){disMatrix[n][x]=weightArray[x]*q/weightArray[n];disMatrix[x][n]=disMatrix[n][x];}}else {disMatrix[n][x]=q;disMatrix[x][n]=disMatrix[n][x]; }}}
对边的删除,主要是对linkMatrix矩阵进行删除操作,并将删除的边记录在列表中,也把当时计算的Q值记录,便于查找。对Q值的计算公式详见简介
public void deleEdge(int start,int end){edgeInfo deInfo=new edgeInfo();deInfo.setInfo(start, end, linkMatrix[start][end]);deleteEgdes.add(deInfo);linkMatrix[start][end]=0;linkMatrix[end][start]=0;}
<span style="font-family: Arial, Helvetica, sans-serif;">public double calQ()</span><span style="font-family: Arial, Helvetica, sans-serif;">{</span>
double Q=0;double M=0;double sum=0;double []k=new double[MAX_NUM];for(int i=0;i<MAX_NUM;i++)for(int j=0;j<MAX_NUM;j++){M+=linkMatrix[i][j]; }M=M/2;for(int i=0;i<MAX_NUM;i++)for(int j=0;j<MAX_NUM;j++)if(linkMatrix[i][j]>0){k[i]+=linkMatrix[i][j];}for(int i=0;i<MAX_NUM;i++)for(int j=0;j<MAX_NUM;j++){if(belong[i]==belong[j])sum+=(linkMatrix[i][j]-k[i]*k[j]/(2*M));}Q=sum/(2*M);Qlist.add(Q);// System.out.print(Q+"\n");return Q;}
计算出结果后,可以选择将结果进行打印,调用函数printResult即可,此时打印的矩阵为GN分裂后的社团结构,以二维数组的形式呈现,打印横纵坐标和权值。
public void printResult(){double max=0;int index=0;for(int i=0;i<Qlist.size();i++){if(max<Qlist.get(i)){max=Qlist.get(i);index=i;}}for(int i=0;i<index;i++){edgeInfo eInfo=deleteEgdes.get(i);int ks=eInfo.start;int ke=eInfo.end;originMatrix[ks][ke]=0;originMatrix[ke][ks]=0;}File file = new File("d:/temp", "res.txt"); try { file.createNewFile(); // 创建文件 } catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); } try {FileOutputStream in = new FileOutputStream(file); for(int i=0;i<MAX_NUM;i++)for(int j=0;j<MAX_NUM;j++){String str =""+i+" "+j+" "+originMatrix[i][j]+"\n"; byte bt[] = new byte[1024]; bt = str.getBytes(); try { in.write(bt, 0, bt.length); //in.close(); // boolean success=true; // System.out.println("写入文件成功"); } catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); } }} catch (Exception e) {// TODO: handle exceptione.printStackTrace();}}
加权GN算法的Java实现相关推荐
- 负载均衡算法及其Java代码实现
负载均衡算法及其Java代码实现 什么是负载均衡 负载均衡,英文 名称为Load Balance,指由多台服务器以对称的方式组成一个服务器集合,每台服务器都具有等价的地位,都可以单独对外提供服务而无须 ...
- java负载均衡原理_多种负载均衡算法及其 Java 代码实现
首先给我们介绍下什么是负载均衡 负载均衡 树立在现有网络结构之上,它供给了一种廉价有用通明的办法扩展 网络设备和 效劳器的带宽.添加 吞吐量.加强网络数据处理才能.进步网络的灵敏性和可用性. 负载均衡 ...
- 【LeetCode-面试算法经典-Java实现】【015-3 Sum(三个数的和)】
[015-3 Sum(三个数的和)] [LeetCode-面试算法经典-Java实现][全部题目文件夹索引] 原题 Given an array S of n integers, are there ...
- java实现 k nn算法_数据挖掘(二)——Knn算法的java实现
本文接数据挖掘-基于Kmeans算法.MBSAS算法及DBSCAN算法的newsgroup18828文本聚类器的JAVA实现(上). (update 2012.12.28 关于本项目下载及运行的常见问 ...
- 【LeetCode-面试算法经典-Java实现】【109-Convert Sorted List to Binary Search Tree(排序链表转换成二叉排序树)】...
[109-Convert Sorted List to Binary Search Tree(排序链表转换成二叉排序树)] [LeetCode-面试算法经典-Java实现][全部题目文件夹索引] 原题 ...
- 八大排序算法的java实现
八大排序算法的java实现 有时间再贴算法分析图 JDK7的Collections.sort()的算法是TimSort, 适应性的归并排序, 比较晦涩难懂, 这里没有实现 public class m ...
- 对一致性Hash算法,Java代码实现的深入研究
一致性Hash算法 关于一致性Hash算法,在我之前的博文中已经有多次提到了,MemCache超详细解读一文中"一致性Hash算法"部分,对于为什么要使用一致性Hash算法.一致性 ...
- DES和RSA算法的java实现
2019独角兽企业重金招聘Python工程师标准>>> 一.对称加密算法 对称加密算法是应用较早的加密算法,技术成熟.在对称加密算法中,数据发信方将明文(原始数据)和加密密钥一起经过 ...
- 【建议收藏】MD5 算法的Java Bean
MD5信息摘要算法(英语:MD5 Message-Digest Algorithm),一种被广泛使用的密码散列函数,可以产生出一个128位(16字节)的散列值(hash value),用于确保信息传输 ...
最新文章
- QT的QMutableMapIterator类的使用
- DVWA File Inclusion——Writeup
- C++ 重载左移和右移运算符
- 人群与网络:博弈论基本概念
- 【渝粤教育】国家开放大学2019年春季 2106宪法学 参考试题
- 求职 IT 少年李文星之死:请务必学会保护自己!
- ATL之深入浅出书评(转)
- 单片机0 99c语言程序,单片机C语言程序设计实训99例.doc
- 交互式电子杂志_快速的创建交互式演示和翻转电子书工具-XFlip Enterprise(电子杂志相册制作器) V2.0.5.0 中文版 - 未来软件园...
- 2022最新第四方聚合支付系统源码+详细搭建教程
- 粒子群算法(PSO) C
- linux系统svn安装教程,Linux下SVN安装配置
- HealthKit框架简介
- Wilcoxon秩和检验MATLAB实现
- git获取所有branch_获取Git仓库的所有分支名字
- 迪文串口屏(DMG10600C101-03WTC)的使用测试
- 还在搞公众号互推涨粉?这个小工具助你粉丝躺增!
- Hadoop常用命令参数介绍
- 【刷题篇】避免洪水泛滥
- 根据地址智能识别省市县/区
热门文章
- curl https -k
- 搭配Online:斥资$500000美元!沙特为何抄底疫情重灾股?
- 告诉你怎样选择虚拟主机!
- 软件测试怎么保证数据的准确性,在MT4软件EA测试过程中,如何获得99.9%的数据质量,提高EA测试的准确性 -...
- mysql伪列的使用,mysql伪列的妙用,mysql获取近几天的日期用来连表查询
- 将来是多久,看一看大佬的故事--《绝非偶然》
- 西北乱跑娃 --- python xml转dict
- 中国中药保健品行业发展现状与未来拓展模式分析报告2022-2027年版
- 理解torch.einsum(‘ijk,ilk->ijl‘, a,b)
- Spring Cloud云架构 - SSO单点登录之OAuth2.0登录认证(1)