深度透析圖論基礎(chǔ)

圖論基礎(chǔ)

1强岸、圖的定義

圖(Graph)是由頂點的有窮非空集合和頂點之間邊的集合組成,通常表示為:G(V,E)掩宜,其中蔫骂,G表示一個圖,V是圖G中頂點的集合牺汤,E是圖G中邊的集合辽旋。

2、圖的基本性質(zhì)

  1. 線性表中我們把數(shù)據(jù)元素叫元素檐迟,樹中將數(shù)據(jù)元素叫節(jié)點补胚,在圖中數(shù)據(jù)元素,則稱之為頂點(Vertex)

  2. 線性表中可以沒有數(shù)據(jù)元素追迟,稱為空表溶其。樹中可以沒有節(jié)點,叫做空樹敦间。

  3. 線性表中瓶逃,相鄰的數(shù)據(jù)元素之間具有線性關(guān)系束铭,樹結(jié)構(gòu)中,相鄰兩層的節(jié)點具有層次關(guān)系厢绝,而圖中契沫,任意兩個頂點之間都有可能有關(guān)系,頂點之間的邏輯關(guān)系用邊來表示昔汉,邊集可以是空的懈万。

3、圖的基本概念

1.無向圖

若頂點v1到v2之間的邊沒有方向挤庇,則稱這條邊為無向邊(Edge)钞速,用無序偶對(v?, v??)來表示。
如果圖中任意兩個頂點之間的邊都是無向邊嫡秕,則稱該圖為無向圖(Undirected graphs)渴语。
重要:在無向圖中,如果任意兩個頂點之間都存在邊昆咽,則稱該圖為無向完全圖驾凶。

1.png

2.有向圖

用有序偶<v?, vj>來表示,vi稱為弧尾(Tail)掷酗,Vj稱為弧頭(Head)调违。如果圖中任意兩個頂點之間的邊都是有向邊,則稱該圖為有向圖(Directed graphs)泻轰。
在有向圖中技肩,如果任意兩個頂點之間都存在方向互為相反的兩條弧,則稱該圖為有向完全圖

2.png

3.圖的權(quán)

有些圖的邊或弧具有與它相關(guān)的數(shù)字浮声,這種與圖的邊或弧相關(guān)的數(shù)叫做權(quán)

3.png

4.連通圖

在無向圖 G 中虚婿,如果從頂點 v 到頂點 v'有路徑,則稱 v和v'是連通的泳挥。
如果對于圖中任意兩個頂點v?然痊、vj(E, vi和vj都是連通的屉符,則稱 G 是連通圖(Connected Graphs)剧浸。

4.png

5.度

無向圖頂點的邊數(shù)叫度,有向圖頂點的邊數(shù)叫出度和入度

5.png

4矗钟、圖的數(shù)據(jù)存儲結(jié)構(gòu)

  1. 鄰接矩陣:圖的鄰接矩陣(Adjacency Matrix)存儲方式是用兩個數(shù)組來表示圖唆香。一個一維數(shù)組存儲圖中頂點信息,一個二維數(shù)組(稱為鄰接矩陣)存儲圖中的邊或弧的信息吨艇。有以下性質(zhì)表示:

    1.無向圖躬它, 2.有向圖, 3.帶權(quán)有向圖秸应, 4.鄰接矩陣的問題

  2. 鄰接表

    1.無向圖虑凛, 2.有向圖, 3.帶權(quán)

5软啼、圖的遍歷

  1. 深度優(yōu)先遍歷(Depth Firsh Search)桑谍。

    遍歷規(guī)則:不斷地沿著頂點的深度方向遍歷。頂點的深度方向是指它的鄰接點方向祸挪。

  2. 廣度優(yōu)先遍歷(Breadth First Search)

    1.先訪問完當前頂點的所有鄰接點锣披。(應該看得出廣度的意思)
    2.先訪問頂點的鄰接點先于后訪問頂點的鄰接點被訪問。

6贿条、代碼實現(xiàn)

import java.util.LinkedList;

/**
 * author: bobo
 * create time: 2018/12/22 10:24 PM
 * email: jqbo84@163.com
 */
public class Graph {
    //頂點集合
    private int[] vertices;
    //圖的邊的信息
    private int[][] matrix;

    private int verticesSize;

    public static final int MAX_WEIGHT = Integer.MAX_VALUE;

    private boolean[] isVisited;

    public Graph() {
    }

    public Graph(int verticesSize) {
        this.verticesSize = verticesSize;
        this.vertices = new int[verticesSize];
        this.matrix = new int[verticesSize][verticesSize];
        this.isVisited = new boolean[verticesSize];
        for (int i = 0; i < verticesSize; i++) {
            vertices[i] = i;
        }
    }

    /**
     * 計算V1到V2的權(quán)度(路徑長度)
     */
    public int getWeight(int v1, int v2) {
        int weight = matrix[v1][v2];
        return (weight == 0 ? 0 : (weight == MAX_WEIGHT ? -1 : weight));
    }

    /**
     * 獲取頂點
     *
     * @return
     */
    public int[] getVertices() {
        return vertices;
    }

    /**
     * 獲取圖的邊的信息數(shù)組
     * @return
     */
    public int[][] getMatrix() {
        return matrix;
    }

    /**
     * 計算出度, 橫向計算
     */
    public int getOutDegree(int v) {
        int count = 0;
        for (int i = 0; i < verticesSize; i++) {
            if (matrix[v][i] != 0 && matrix[v][i] != MAX_WEIGHT) {
                count += 1;
            }
        }
        return count;
    }

    /**
     * 計算入度雹仿, 縱向計算
     */
    public int getInDegree(int v) {
        int count = 0;
        for (int i = 0; i < verticesSize; i++) {
            if (matrix[i][v] != 0 && matrix[i][v] != MAX_WEIGHT) {
                count += 1;
            }
        }
        return count;
    }

    /**
     * 獲取第一個鄰接點
     */
    public int getFirstNeightBor(int v){
        for (int i = 0; i < verticesSize; i++) {
            if(matrix[v][i] > 0 && matrix[v][i] != MAX_WEIGHT){
                return i;
            }
        }
        return -1;
    }

    /**
     * 獲取到頂點 v 的鄰接點的index到下一個鄰接點
     */
    public int getNextNeightBor(int v, int index){
        for (int i = index + 1; i < verticesSize; i++) {
            if(matrix[v][i] > 0 && matrix[v][i] != MAX_WEIGHT){
                return i;
            }
        }
        return -1;
    }

    /**
     * 深度優(yōu)先(很像二叉樹的前序排序算法)
     */
    public void dfs(){
        for (int i = 0; i < verticesSize; i++) {
            if(!isVisited[i]){
                System.out.println("Visited Vertice = " + i);
                dfs(i);
            }
        }
    }

    public void dfs(int i){
        isVisited[i] = true;
        int v = getFirstNeightBor(i);
        while (v != -1) {
            if(!isVisited[v]){
                System.out.println("Visited Vertice = " + v);
                dfs(v);
            }
            v = getNextNeightBor(i, v);
        }
    }

    /**
     * 廣度優(yōu)先(有點像二叉樹的第四種排序算法)
     */
    public void bfs(){
        for (int i = 0; i < verticesSize; i++) {
            isVisited[i] = false;
        }
        for (int i = 0; i < verticesSize; i++) {
            if(!isVisited[i]){
                isVisited[i] = true;
                System.out.println("visited vertice = " + i);
                bfs(i);
            }
        }
    }

    public void bfs(int i){
        LinkedList<Integer> queue = new LinkedList<>();
        //找到第一個鄰接點
        int fn = getFirstNeightBor(i);
        if(fn == -1){
            return;
        }
        if(!isVisited[fn]){
            isVisited[fn] = true;
            System.out.println("visited vertice = " + fn);
            queue.offer(fn);
        }
        //開始把后面的鄰接點都入隊
        int next = getNextNeightBor(i, fn);
        while (next != -1){
            if(!isVisited[next]){
                isVisited[next] = true;
                System.out.println("visited vertice = " + next);
                queue.offer(next);
            }
            next = getNextNeightBor(i, next);
        }
        //從隊列中取出來一個,重復之前的操作
        while (!queue.isEmpty()){
            int p = queue.poll();
            bfs(p);
        }
    }
}

7整以、測試

@Test
public void testGraph(){
//        Graph graph=new Graph(5);
//        int[] a0=new int[]{0,MAX_WEIGHT,MAX_WEIGHT,MAX_WEIGHT,6};
//        int[] a1=new int[]{9,0,3,MAX_WEIGHT,MAX_WEIGHT};
//        int[] a2=new int[]{2,MAX_WEIGHT,0,5,MAX_WEIGHT};
//        int[] a3=new int[]{MAX_WEIGHT,MAX_WEIGHT,MAX_WEIGHT,0,1};
//        int[] a4=new int[]{MAX_WEIGHT,MAX_WEIGHT,MAX_WEIGHT,MAX_WEIGHT,0};
//        graph.getMatrix()[0]=a0;
//        graph.getMatrix()[1]=a1;
//        graph.getMatrix()[2]=a2;
//        graph.getMatrix()[3]=a3;
//        graph.getMatrix()[4]=a4;
//        System.out.println(graph.getInDegree(2));
//        System.out.println(graph.getOutDegree(2));

    Graph graph = new Graph(5);
    int[] v0 = new int[]{0, 1, 1, MAX_WEIGHT, MAX_WEIGHT};
    int[] v1 = new int[]{MAX_WEIGHT, 0, MAX_WEIGHT, 1, MAX_WEIGHT};
    int[] v2 = new int[]{MAX_WEIGHT, MAX_WEIGHT, 0, MAX_WEIGHT, MAX_WEIGHT};
    int[] v3 = new int[]{1, MAX_WEIGHT, MAX_WEIGHT, 0, MAX_WEIGHT};
    int[] v4 = new int[]{MAX_WEIGHT, MAX_WEIGHT, 1, MAX_WEIGHT, 0};
    graph.getMatrix()[0] = v0;
    graph.getMatrix()[1] = v1;
    graph.getMatrix()[2] = v2;
    graph.getMatrix()[3] = v3;
    graph.getMatrix()[4] = v4;
    graph.dfs();
    System.out.println("--------------------------------");
    graph.bfs();

}

結(jié)果:
--------------- 入度出度 -----------------
1
2
--------------- 深度優(yōu)先 -----------------
Visited Vertice = 0
Visited Vertice = 1
Visited Vertice = 3
Visited Vertice = 2
Visited Vertice = 4
--------------- 廣度優(yōu)先 -----------------
visited vertice = 0
visited vertice = 1
visited vertice = 2
visited vertice = 3
visited vertice = 4

8胧辽、附測試圖

1.入度出度測試圖:

7.png

2.深度優(yōu)先、廣度優(yōu)先測試圖:

6.png
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末公黑,一起剝皮案震驚了整個濱河市邑商,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌凡蚜,老刑警劉巖人断,帶你破解...
    沈念sama閱讀 219,110評論 6 508
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異朝蜘,居然都是意外死亡恶迈,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,443評論 3 395
  • 文/潘曉璐 我一進店門谱醇,熙熙樓的掌柜王于貴愁眉苦臉地迎上來暇仲,“玉大人,你說我怎么就攤上這事枣抱∪勐穑” “怎么了?”我有些...
    開封第一講書人閱讀 165,474評論 0 356
  • 文/不壞的土叔 我叫張陵佳晶,是天一觀的道長桅狠。 經(jīng)常有香客問我,道長轿秧,這世上最難降的妖魔是什么中跌? 我笑而不...
    開封第一講書人閱讀 58,881評論 1 295
  • 正文 為了忘掉前任,我火速辦了婚禮菇篡,結(jié)果婚禮上漩符,老公的妹妹穿的比我還像新娘。我一直安慰自己驱还,他們只是感情好嗜暴,可當我...
    茶點故事閱讀 67,902評論 6 392
  • 文/花漫 我一把揭開白布凸克。 她就那樣靜靜地躺著,像睡著了一般闷沥。 火紅的嫁衣襯著肌膚如雪萎战。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,698評論 1 305
  • 那天舆逃,我揣著相機與錄音蚂维,去河邊找鬼。 笑死路狮,一個胖子當著我的面吹牛虫啥,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播奄妨,決...
    沈念sama閱讀 40,418評論 3 419
  • 文/蒼蘭香墨 我猛地睜開眼涂籽,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了展蒂?” 一聲冷哼從身側(cè)響起又活,我...
    開封第一講書人閱讀 39,332評論 0 276
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎锰悼,沒想到半個月后柳骄,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,796評論 1 316
  • 正文 獨居荒郊野嶺守林人離奇死亡箕般,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,968評論 3 337
  • 正文 我和宋清朗相戀三年耐薯,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片丝里。...
    茶點故事閱讀 40,110評論 1 351
  • 序言:一個原本活蹦亂跳的男人離奇死亡曲初,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出杯聚,到底是詐尸還是另有隱情臼婆,我是刑警寧澤,帶...
    沈念sama閱讀 35,792評論 5 346
  • 正文 年R本政府宣布幌绍,位于F島的核電站颁褂,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏傀广。R本人自食惡果不足惜颁独,卻給世界環(huán)境...
    茶點故事閱讀 41,455評論 3 331
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望伪冰。 院中可真熱鬧誓酒,春花似錦、人聲如沸贮聂。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,003評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至歼冰,卻和暖如春捣染,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背停巷。 一陣腳步聲響...
    開封第一講書人閱讀 33,130評論 1 272
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留榕栏,地道東北人畔勤。 一個月前我還...
    沈念sama閱讀 48,348評論 3 373
  • 正文 我出身青樓,卻偏偏與公主長得像扒磁,于是被迫代替她去往敵國和親庆揪。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 45,047評論 2 355

推薦閱讀更多精彩內(nèi)容

  • 1. 圖的定義和基本術(shù)語 線性結(jié)構(gòu)中妨托,元素僅有線性關(guān)系缸榛,每個元素只有一個直接前驅(qū)和直接后繼;樹形結(jié)構(gòu)中兰伤,數(shù)據(jù)元素(...
    yinxmm閱讀 5,457評論 0 3
  • 圖的定義與術(shù)語 1内颗、圖按照有無方向分為無向圖和有向圖。無向圖由頂點和邊構(gòu)成敦腔,有向圖由頂點和弧構(gòu)成均澳。弧有弧尾和弧頭之...
    unravelW閱讀 408評論 0 0
  • https://zh.visualgo.net/graphds 淺談圖形結(jié)構(gòu)https://zh.visualgo...
    狼之獨步閱讀 4,156評論 0 0
  • 圖是由頂點的有窮非空集合和頂點之間邊的集合組成符衔,通常表示為:G(V,E)找前,其中,G表示一個圖判族,V是圖G中頂點的集合...
    開心糖果的夏天閱讀 830評論 0 9
  • 一躺盛。出生 一九九八年二月十日,正是這年元宵節(jié)的前一日形帮,正月十四槽惫,父親帶著懷孕的母親在舅舅家做客,傍晚沃缘,外祖母不愿母...
    一只名為汪汪的喵閱讀 349評論 0 0