二十二. java數據結構 - 圖

1.為什么要有圖

  1. 前面我們學了線性表和樹

  2. 線性表局限于一個直接前驅和一個直接后繼的關系

  3. 樹也只能有一個直接前驅也就是父節(jié)點

  4. 當我們需要表示多對多的關系時, 這里我們就用到了圖妄均。

2. 圖的舉例說明

圖是一種數據結構,其中結點可以具有零個或多個相鄰元素拜鹤。兩個結點之間的連接稱為邊。 結點也可以稱為頂點洼怔。

3. 圖的常用概念

  1. 頂點(vertex)

  2. 邊(edge)

  3. 路徑

  4. 無向圖

無向圖
  1. 有向圖

  2. 帶權圖

有向圖/帶權圖

圖的表示方式有兩種:二維數組表示(鄰接矩陣)署惯;鏈表表示(鄰接表)。

4. 鄰接矩陣

鄰接矩陣是表示圖形中頂點之間相鄰關系的矩陣镣隶,對于 n 個頂點的圖而言极谊,矩陣是的 row 和 col 表示的是 1....n個點。

鄰接矩陣

5. 鄰接表

  1. 鄰接矩陣需要為每個頂點都分配 n 個邊的空間安岂,其實有很多邊都是不存在,會造成空間的一定損失.

  2. 鄰接表的實現只關心存在的邊轻猖,不關心不存在的邊。因此沒有空間浪費域那,鄰接表由數組+鏈表組成

鄰接表

6. 實現下圖結構

圖結構

(1) 存儲頂點 String 使用 ArrayList

(2) 保存矩陣 int[][] edges

public class Graph {

    private ArrayList<String> vertexList; //存儲頂點集合
    private int[][] edges; //存儲圖對應的鄰結矩陣
    private int numOfEdges; //表示邊的數目
    //定義給數組boolean[], 記錄某個結點是否被訪問
    private boolean[] isVisited;
    
    //插入結點
    public void insertVertex(String vertex) {
        vertexList.add(vertex);
    }
    
    /**
     * 添加邊
     * @param v1 表示點的下標即使第幾個頂點  "A"-"B" "A"->0 "B"->1
     * @param v2 第二個頂點對應的下標
     * @param weight 表示 
     */
    public void insertEdge(int v1, int v2, int weight) {
        edges[v1][v2] = weight;
        edges[v2][v1] = weight;
        numOfEdges++;
    }
}

7. 圖的深度優(yōu)先遍歷

所謂圖的遍歷咙边,即是對結點的訪問。一個圖有那么多個結點次员,如何遍歷這些結點败许,需要特定策略,

一般有兩種訪問策略:

  • (1)深度優(yōu)先遍歷
  • (2)廣度優(yōu)先遍歷

7.1 深度優(yōu)先遍歷基本思想

    1. 深度優(yōu)先遍歷淑蔚,從初始訪問結點出發(fā)市殷,初始訪問結點可能有多個鄰接結點,深度優(yōu)先遍歷的策略就是首先訪問

    第一個鄰接結點刹衫,然后再以這個被訪問的鄰接結點作為初始結點醋寝,訪問它的第一個鄰接結點搞挣, 可以這樣理解:

    每次都在訪問完當前結點后首先訪問當前結點的第一個鄰接結點。

    1. 我們可以看到音羞,這樣的訪問策略是優(yōu)先往縱向挖掘深入囱桨,而不是對一個結點的所有鄰接結點進行橫向訪問。
    1. 顯然嗅绰,深度優(yōu)先搜索是一個遞歸的過程

7.2 深度優(yōu)先遍歷算法步驟

  1. 訪問初始結點 v舍肠,并標記結點 v 為已訪問。

  2. 查找結點 v 的第一個鄰接結點 w办陷。

  3. 若 w 存在貌夕,則繼續(xù)執(zhí)行 4律歼,如果 w 不存在民镜,則回到第 1 步,將從 v 的下一個結點繼續(xù)险毁。

  4. 若 w 未被訪問制圈,對 w 進行深度優(yōu)先遍歷遞歸(即把 w 當做另一個 v,然后進行步驟 123)畔况。

  5. 查找結點 v 的 w 鄰接結點的下一個鄰接結點鲸鹦,轉到步驟 3。

深度優(yōu)先遍歷算法步驟

7.3 代碼實現

    //深度優(yōu)先遍歷算法
    //i 第一次就是 0
    private void dfs(boolean[] isVisited, int i) {
        //首先我們訪問該結點,輸出
        System.out.print(getValueByIndex(i) + "->");
        //將結點設置為已經訪問
        isVisited[i] = true;
        //查找結點i的第一個鄰接結點w
        int w = getFirstNeighbor(i);
        while(w != -1) {//說明有
            if(!isVisited[w]) {
                dfs(isVisited, w);
            }
            //如果w結點已經被訪問過
            w = getNextNeighbor(i, w);
        }
        
    }
    
    //對dfs 進行一個重載, 遍歷我們所有的結點跷跪,并進行 dfs
    public void dfs() {
        isVisited = new boolean[vertexList.size()];
        //遍歷所有的結點馋嗜,進行dfs[回溯]
        for(int i = 0; i < getNumOfVertex(); i++) {
            if(!isVisited[i]) {
                dfs(isVisited, i);
            }
        }
    }

    //返回結點的個數
    public int getNumOfVertex() {
        return vertexList.size();
    }

8. 圖的廣度優(yōu)先遍歷

8.1 廣度優(yōu)先遍歷基本思想

    1. 圖的廣度優(yōu)先搜索(Broad First Search) 。
    1. 類似于一個分層搜索的過程吵瞻,廣度優(yōu)先遍歷需要使用一個隊列以保持訪問過的結點的順序葛菇,以便按這個順序來訪問這些結點的鄰接結點

8.2 廣度優(yōu)先遍歷算法步驟

    1. 訪問初始結點 v 并標記結點 v 為已訪問。
    1. 結點 v 入隊列
    1. 當隊列非空時橡羞,繼續(xù)執(zhí)行眯停,否則算法結束。
    1. 出隊列卿泽,取得隊頭結點 u莺债。
    1. 查找結點 u 的第一個鄰接結點 w。
    1. 若結點 u 的鄰接結點 w 不存在签夭,則轉到步驟 3齐邦;否則循環(huán)執(zhí)行以下三個步驟:
    • 6.1 若結點 w 尚未被訪問措拇,則訪問結點 w 并標記為已訪問宣羊。

    • 6.2 結點 w 入隊列

    • 6.3 查找結點 u 的繼 w 鄰接結點后的下一個鄰接結點 w仇冯,轉到步驟 6族操。

8.3 代碼實現

    
    //對一個結點進行廣度優(yōu)先遍歷的方法
    private void bfs(boolean[] isVisited, int i) {
        int u ; // 表示隊列的頭結點對應下標
        int w ; // 鄰接結點w
        //隊列色难,記錄結點訪問的順序
        LinkedList queue = new LinkedList();
        //訪問結點,輸出結點信息
        System.out.print(getValueByIndex(i) + "=>");
        //標記為已訪問
        isVisited[i] = true;
        //將結點加入隊列
        queue.addLast(i);
        
        while( !queue.isEmpty()) {
            //取出隊列的頭結點下標
            u = (Integer)queue.removeFirst();
            //得到第一個鄰接結點的下標 w 
            w = getFirstNeighbor(u);
            while(w != -1) {//找到
                //是否訪問過
                if(!isVisited[w]) {
                    System.out.print(getValueByIndex(w) + "=>");
                    //標記已經訪問
                    isVisited[w] = true;
                    //入隊
                    queue.addLast(w);
                }
                //以u為前驅點娇昙,找w后面的下一個鄰結點
                w = getNextNeighbor(u, w); //體現出我們的廣度優(yōu)先
            }
        }
        
    } 
    
    //遍歷所有的結點,都進行廣度優(yōu)先搜索
    public void bfs() {
        isVisited = new boolean[vertexList.size()];
        for(int i = 0; i < getNumOfVertex(); i++) {
            if(!isVisited[i]) {
                bfs(isVisited, i);
            }
        }
    }

9.圖的深度優(yōu)先 VS 廣度優(yōu)先

圖的深度優(yōu)先 VS 廣度優(yōu)先
?著作權歸作者所有,轉載或內容合作請聯系作者
  • 序言:七十年代末召衔,一起剝皮案震驚了整個濱河市苍凛,隨后出現的幾起案子趣席,更是在濱河造成了極大的恐慌吩坝,老刑警劉巖闸迷,帶你破解...
    沈念sama閱讀 206,214評論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件今阳,死亡現場離奇詭異墓臭,居然都是意外死亡,警方通過查閱死者的電腦和手機嗡载,發(fā)現死者居然都...
    沈念sama閱讀 88,307評論 2 382
  • 文/潘曉璐 我一進店門埂息,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事蛀蜜。” “怎么了滴某?”我有些...
    開封第一講書人閱讀 152,543評論 0 341
  • 文/不壞的土叔 我叫張陵磅摹,是天一觀的道長。 經常有香客問我霎奢,道長户誓,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 55,221評論 1 279
  • 正文 為了忘掉前任幕侠,我火速辦了婚禮帝美,結果婚禮上,老公的妹妹穿的比我還像新娘晤硕。我一直安慰自己悼潭,他們只是感情好庇忌,可當我...
    茶點故事閱讀 64,224評論 5 371
  • 文/花漫 我一把揭開白布漆枚。 她就那樣靜靜地躺著,像睡著了一般残制。 火紅的嫁衣襯著肌膚如雪初茶。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 49,007評論 1 284
  • 那天,我揣著相機與錄音搁宾,去河邊找鬼。 笑死爽待,一個胖子當著我的面吹牛鸟款,可吹牛的內容都是我干的何什。 我是一名探鬼主播,決...
    沈念sama閱讀 38,313評論 3 399
  • 文/蒼蘭香墨 我猛地睜開眼霍比,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了暴备?” 一聲冷哼從身側響起望迎,我...
    開封第一講書人閱讀 36,956評論 0 259
  • 序言:老撾萬榮一對情侶失蹤摄欲,失蹤者是張志新(化名)和其女友劉穎胸墙,沒想到半個月后,有當地人在樹林里發(fā)現了一具尸體,經...
    沈念sama閱讀 43,441評論 1 300
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 35,925評論 2 323
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現自己被綠了。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 38,018評論 1 333
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內的尸體忽然破棺而出烫罩,到底是詐尸還是另有隱情,我是刑警寧澤洽故,帶...
    沈念sama閱讀 33,685評論 4 322
  • 正文 年R本政府宣布贝攒,位于F島的核電站,受9級特大地震影響时甚,放射性物質發(fā)生泄漏隘弊。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 39,234評論 3 307
  • 文/蒙蒙 一荒适、第九天 我趴在偏房一處隱蔽的房頂上張望长捧。 院中可真熱鬧,春花似錦吻贿、人聲如沸串结。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,240評論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽肌割。三九已至,卻和暖如春帐要,著一層夾襖步出監(jiān)牢的瞬間把敞,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 31,464評論 1 261
  • 我被黑心中介騙來泰國打工榨惠, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留奋早,地道東北人。 一個月前我還...
    沈念sama閱讀 45,467評論 2 352
  • 正文 我出身青樓赠橙,卻偏偏與公主長得像耽装,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子期揪,可洞房花燭夜當晚...
    茶點故事閱讀 42,762評論 2 345

推薦閱讀更多精彩內容