絕對均勻圖生成算法

最近在研究圖計算的性能,須要構造不一樣的測試數據對圖算法進行壓測,其中就涉及到均勻圖的概念。java

由於作的是理論測試,所以就須要一種理論上絕對均勻的圖測試數據,接下來咱們就討論一下絕對均勻圖的生成。git

1、何爲絕對均勻圖?

爲了方便討論,咱們只討論無向圖,並且圖中的邊是無權值的,且兩點之間只能存在一條邊,即邊僅表明結點之間的關聯。github

從圖論角度出發,咱們都知道圖都是由結點以及結點之間的關聯邊組成的。直觀上理解,絕對均勻的圖應該是圖中的全部結點的度都徹底相同,這樣每一個結點都是同構的,也就是說從任何一個結點進行觀察,獲得的都是一樣的結果。算法

形式化的描述應該是這樣,對於圖 \(G=(V, E)\) ,其中\(V\)是結點集合,\(E\)是邊集合,記 \(|V|\) 爲結點數, \(|E|\) 爲邊數,圖的平均度爲 \(D\) ,因爲每條邊爲圖貢獻兩個度,因而存在如下關係:
$
D = \frac{2\cdot|E|}{|V|}(公式1)
$框架

所以,根據前面對均勻概念的理解,對於絕對均勻圖,任何一個節點的度數都知足:
$
d_v = D = \frac{2\cdot|E|}{|V|}(公式2)
$性能

2、簡單討論一下

明確了絕對均勻圖的概念後,接下來就是如何生成的問題。因爲
$
|E| = \frac{d_v\cdot|V|}{2}(公式3)
$
咱們只須要控制結點數 \(|V|\) 和每一個結點的度數 \(d_v\) 這兩個變量便可。所以咱們的目標就是生成任意結點數,且結點度數任意的絕對均勻圖測試

咱們知道,徹底圖其實就是一種絕對均勻圖,其全部節點的度數爲 \(|V| - 1\) ,這已是圖中結點能夠達到的最高度數了。相應的,空圖(只有點,沒有邊)也是絕對均勻圖,即全部節點的度數都爲 \(0\),爲最低度數。所以絕對均勻圖的結點度數老是知足:
$
0\le d_v\lt|V|(公式4)
$spa

經過觀察上面的公式2,咱們還能夠得出以下結論:3d

  1. 當結點數爲奇數時,\(|V| = 2k - 1, k=1,2...\) , 因爲 \(|E|\) 是整數,所以 \(d_v\) 必爲偶數。
  2. 當結點數爲偶數時,\(|V| = 2k, k=1,2...\)\(d_v\) 沒有限制,由於總有 \(|E| = d_v\cdot k\)

一言以蔽之,對於奇數點數的絕對均勻圖,結點度數只能取 \([0, |V|)\) 以內的偶數。故而在圖生成算法上須要對奇數點數圖區分對待。code

3、試一下遞歸?

那麼如何構建絕對均勻圖呢?首先比較容易想到的就是遞歸思想,遞歸的基本思路是:

  1. 構建問題最簡單的規模實例,即遞歸的初值,或稱爲終止條件。
  2. 在最簡單規模的實例基礎上,經過增長問題規模,推測問題規模增大時,問題變化的規律。
  3. 繼而推導在問題規模爲\(n\)的時,構造問題規模爲\(n+1\)的遞歸條件。這也就意味着,問題規模增大時獲得的結果,老是蘊含,甚至包含上一級規模問題的結果

上面討論過,對於絕對均勻圖,有兩個變量影響圖的規模:結點數 \(|V|\) 和結點度數 \(d_v\) 。所以分析時,要假定其中有一個不變量才比較好思考。

1. 結點度數不變,增大結點數

因爲奇數結點數的圖的結點度數不可能爲奇數,所以咱們保持結點度數爲偶數不變,保證結點數從奇數到偶數再到奇數時,能夠連續地推導問題變化規律。

這裏取\(d_v = 2(0度不具有參考性,可做爲邊界條件考慮)\),令 \(|V| = 3, 4, 5, 6\),能夠獲得以下圖實例。

貌似按照環形圖的思考方式,問題是能夠遞歸的。每增長一個結點時,只須要選取一條邊斷開,而後鏈接到新的結點便可。

再考慮一下\(d_v = 4\)的狀況,令 \(|V| = 5, 6\),能夠獲得以下圖實例。

這種狀況下,好像使用上述的遞歸擴展方式就不太容易了。那另一種狀況呢?

2. 結點數不變,增大結點度數

這裏取 \(|V| = 6\),令 \(d_v = 0, 1, 2, 3, 4, 5, 6\),能夠獲得以下圖實例。

能夠看到,當度從\(3\)增加到\(4\)時,新規模問題的解並不包含上一級問題全部的解,並且每一級變化的規律並不穩定。

所以用上面的遞歸思想去分析絕對均勻圖生成的問題可能並不方便,咱們須要轉換一下思路。

4、核心思想

回到第一節對絕對均勻圖的概念描述:絕對均勻圖的結點是同構的,知足各向同性。這就意味着咱們能夠從一個結點出發,去設法尋找它的關聯節點,而且這種方式對任何一個結點都是相同的。

那麼如何找到關聯結點呢?考慮到絕對均勻圖每一個點都是同構的,所以絕對均勻圖必定是中心對稱的!假設這個虛擬的對稱中心爲\(O\),在\(d_v = 1\)的狀況下,關聯結點必定是當前結點的中心對稱結點。

那在\(d_v = 2\)的狀況下呢?

或許會有人好奇,這個\(d_v = 2\)的圖怎麼不是環呢?其實對於一樣結點數和度數的絕對均勻圖,圖的結構可能不止一種

按照中心對稱思想依此類推,能夠獲得其餘度的絕對均勻圖。

所以,關聯結點的尋找思路以下:

  1. \(d_v=2k(k=0, 1, 2...)\) 時,關聯結點爲當前結點的中心對稱結點兩側的各\(k\)個結點。
  2. \(d_v = 2k + 1(k=0, 1, 2...)\) 時,關聯結點爲當前結點的中心對稱結點加上中心對稱結點兩側的各\(k\)個結點。

咱們發現,前面討論的不可行的遞歸方式主要是被環形圖的思路干擾了。利用中心對稱的關聯結點尋找方式是也是能夠遞歸的,不過使用循環實現可能更方便。

5、算法實現與測試

基於中心對稱思想的絕對均勻圖生成算法實現以下:

public boolean generate(int count, int degree) {

    // 基本參數校驗
    if (!(count > 0 && degree >= 0 && degree < count)) {
        System.err.println("Invalid arguments !");
        return false;
    }

    // 檢查奇數點圖的度是不是偶數
    if (count % 2 == 1 && degree % 2 != 0) {
        System.err.println("Degree should be odd when vertices' count is even !");
        return false;
    }

    // 生成點
    System.out.println("Generating vertices:");
    for (int index = 0; index < count; index++) {
        System.out.println(index);
    }

    // 生成邊
    System.out.println("Generating edges:");
    for (int index = 0; index < count; index++) {

        // 對面的點
        int opposite = (index + count / 2) % count;

        // 點偶數,度奇數,連接中心對稱結點
        if (count % 2 == 0 && degree % 2 == 1) {
            System.out.println(index + " -> " + opposite);
        }

        // 連接中心對稱結點兩側的點
        for (int i = (count + 1) % 2; i <= (degree - count % 2) / 2; i++) {
            final int previous = (opposite - i + count) % count;
            final int next = (opposite + i + count % 2) % count;

            System.out.println(index + " -> " + previous);
            System.out.println(index + " -> " + next);
        }
    }

    return true;
}

爲了更直觀的展現生成的絕對均勻圖,能夠藉助vis.js庫進行繪製。

具體實現方式能夠訪問github源碼drawG,該項目實現了一個簡單的圖生成與繪製框架,能夠方便定製和擴展圖生成器和處理器。

最後,看一下使用該框架生成的絕對均勻圖:

相關文章
相關標籤/搜索