社會網絡分析之連通分量分組算法


0.引言

在社會網絡分析領域,非常重要的一塊就是尋找網絡中的有聯系的小團體,比較正式的說法是“成分”。通常將圖論中最大的連通分量定義為“成分”,成分內部的各點之間必然有一條途徑相連,而成分之外的點與成分內部的點沒有聯系。

 1.概念

連通分量是圖論非常重要的一個概念。與它有一個相近的概念,叫連通圖。對於初學者而言,很容易混淆這兩個概念。

(1)連通圖是相對整體而言的,連通分量是相對局部子集而言。

(2)連通圖只有一個連通分量即本身,非連通的無向圖有多個連通分量。

(3)連通分量內部任意兩點之間都可達

例如:上圖是無向圖G4,有兩個連通分量H1、H2,H1、H2內部任意兩點都可達。

2.分組算法

思路1:對於任意給定的無向圖G。

step1:隨機從中取出一個節點X,添加到集合S1。以x為起點進行廣度搜索,將有連接的節點Y和邊E添加到集合S1,並將節點E標志位設置為已訪問。

step2:從G中剔除集合S1中所有的節點。

step3:重復step1、step2操作,直到G中的節點數為0,由此生成了分組S1、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 };
code1

 

 

思路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);
    }
}
code2

 

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


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM