0.引言html
在社會網絡分析領域,很是重要的一塊就是尋找網絡中的有聯繫的小團體,比較正式的說法是「成分」。一般將圖論中最大的連通份量定義爲「成分」,成份內部的各點之間必然有一條途徑相連,而成分以外的點與成份內部的點沒有聯繫。node
1.概念算法
連通份量是圖論很是重要的一個概念。與它有一個相近的概念,叫連通圖。對於初學者而言,很容易混淆這兩個概念。數組
(1)連通圖是相對總體而言的,連通份量是相對局部子集而言。網絡
(2)連通圖只有一個連通份量即自己,非連通的無向圖有多個連通份量。ide
(3)連通份量內部任意兩點之間均可達函數
例如:上圖是無向圖G4,有兩個連通份量H一、H2,H一、H2內部任意兩點均可達。性能
2.分組算法this
思路1:對於任意給定的無向圖G。阿里雲
step1:隨機從中取出一個節點X,添加到集合S1。以x爲起點進行廣度搜索,將有鏈接的節點Y和邊E添加到集合S1,並將節點E標誌位設置爲已訪問。
step2:從G中剔除集合S1中全部的節點。
step3:重複step一、step2操做,直到G中的節點數爲0,由今生成了分組S一、S2......Sn。
1 /** 2 * 根據連通劃分分組 3 * @returns {Array} 4 */ 5 GroupDataHelper.prototype.divideGroupByConn = function () { 6 var copyNodes = this.nodes; 7 while (copyNodes.length > 0) { 8 var startId = copyNodes[0].id;//隨機從中取出一個節點X,添加到集合S1 9 var group = this.getSingleGroupByNodeId(startId);//以x爲起點進行廣度搜索 10 this.groups.push(group);//將有鏈接的節點Y和邊E添加到集合S1 11 removeGroupFromNodes(group.nodes, copyNodes);//從G中剔除集合S1中全部的節點 12 } 13 return this.groups; 14 } 15 16 /** 17 * 根據節點Id獲取單個分組 18 * @param nodeId 19 * @returns {{nodes: Array, edges: Array}} 20 */ 21 GroupDataHelper.prototype.getSingleGroupByNodeId = function (nodeId) { 22 var group = {nodes: [], edges: []}; 23 var startNode = this.nodesMap[nodeId]; 24 group.nodes.push(startNode); 25 this.travelGraphByBFS([startNode], group); 26 return group; 27 }; 28 29 /** 30 * 廣度搜索,獲得一個連通份量 31 * @param nodeArr 32 * @param result 33 */ 34 GroupDataHelper.prototype.travelGraphByBFS = function (nodeArr, group) { 35 var nextNodeArr = []; 36 for (var i = 0; i < nodeArr.length; i++) { 37 var node = nodeArr[i]; 38 node.isVisited = true; 39 var neighbours = node.neighbours; 40 if (neighbours && neighbours.length > 0) { 41 for (var j = 0; j < neighbours.length; j++) { 42 var neighbour = neighbours[j]; 43 if (neighbour.isVisited == false) { 44 var temp = this.nodesMap[neighbour.id]; 45 group.nodes.push(temp); 46 group.edges.push(this.edgesMap[temp.id][node.id]); 47 neighbour.isVisited = true; 48 nextNodeArr.push(neighbour); 49 } 50 } 51 } 52 53 } 54 //下一層 55 if (nextNodeArr.length > 0) { 56 this.travelGraphByBFS(nextNodeArr, group); 57 } else { 58 return; 59 } 60 61 };
思路2:對於任意給定的無向圖G。採用並查集的思路,能夠解決連通性問題。並查集是由一個數組pre[]和兩個函數構成的。第一個函數爲find()函數,用於尋找前導點的,第二個函數是join()用於合併路線的。咱們只須要遍歷G的邊集合,使用join()函數將邊的兩個端點合併路線,由此能夠獲得多棵數。而後遍歷點集合使用find()函數將節點的分組ID設置爲前導節點Id便可完成分組。
** * 並查集:查找前導節點 * @param x * @returns {*} */ function find(x) { var r = x; while (pre[r] != r) r = pre[r];//找到他的前導結點 var i = x, j; while (i != r)//路徑壓縮算法 { j = pre[i];//記錄x的前導結點 pre[i] = r;//將i的前導結點設置爲r根節點 i = j; } return r; } /** * 並查集:合併路線 * @param x * @param y */ function join(x, y) { var a = find(x);//x的根節點爲a var b = find(y);//y的根節點爲b if (a != b)//若是a,b不是相同的根節點,則說明ab不是連通的 { pre[a] = b;//咱們將ab相連 將a的前導結點設置爲b } } /** * 獲取分組 * @param data */ function getGroups(data) { var i=0; var nodes = data.nodes.length; var edges = data.edges.length; //初始化前導節點 for(var i=0;i<nodes.length;i++){ var node = nodes[i]; pre[node.index] = node.index;//前導節點初始爲本身 } //遍歷邊集合,合併 for(i=0;i<edges.length;i++){ var edge = edges[i]; var sNode = nodesMap[edge.source]; var tNode = nodesMap[edge.target]; join(sNode.index,tNode.index); } //遍歷點集合,設置分組ID for(i=0;i<nodes.length;i++){ var node = nodes[i]; node.groupId = find(node.index); } }
3.性能比較
其中,k表示分組數量,n表示節點數量,m表示邊數量
思路1的時間複雜度:O(k*n*logn+m)
思路2的時間複雜度:最好的狀況下爲O(m+n),最差的狀況下爲O(m*logn+m)
結論:在邊數量遠遠大於節點數量,且分組比較少時,優先考慮思路1;在節點數量、分組數比較多時,優先考慮思路2
4.參考資料
連通份量:https://blog.csdn.net/qq_33913037/article/details/71213985?locationNum=1&fps=1
藍橋杯算法:https://blog.csdn.net/The_best_man/article/details/62418823
networkX: https://blog.csdn.net/Eastmount/article/details/78452581
igraph: https://blog.csdn.net/yepeng2007fei/article/details/78250088
社會網絡分析:http://blog.sina.com.cn/s/blog_dc8ea6c10101l2lc.html
成分:http://blog.sina.com.cn/s/blog_6249651d0100la5r.html
阿里雲I+關係網絡分析:https://blog.csdn.net/yunqiinsight/article/details/80134024
數據可視化:http://baijiahao.baidu.com/s?id=1600865025454038979&wfr=spider&for=pc