Carson带你学数据结构:手把手带你了解 ”图“ 所有知识!(含DFS、BFS)
生活随笔
收集整理的這篇文章主要介紹了
Carson带你学数据结构:手把手带你了解 ”图“ 所有知识!(含DFS、BFS)
小編覺得挺不錯的,現在分享給大家,幫大家做個參考.
前言
本文主要講解 數據結構中的圖 結構,包括 深度優先搜索(DFS)、廣度優先搜索(BFS)、最小生成樹算法等,希望你們會喜歡。
目錄
1. 簡介
- 數據結構的中屬于 圓形結構 的邏輯結構
- 具體介紹如下
2. 基礎概念
- 在圖的數據結構中,有許多基礎概念,如 邊類型、圖頂點 & 邊間的關系等等
- 具體請看下圖
3. 類型
圖的類型分為很多種,具體如下:
3.1 有向圖 & 無向圖
3.2 連通圖
-
定義
圖中任意頂點都是連通的圖 -
具體相關概念
對于有向圖 & 無向圖,連通圖的的具體概念又不同,具體如下
對于無向圖:
對于有向圖:
3.3 其余類型圖
4. 存儲結構
圖的存儲結構共有5種,具體請看下圖
5. 圖的遍歷
數據結構:圖文詳解二叉樹(遍歷、類型、操作)
5.1 定義
從圖中某1頂點出發,遍歷圖中其余所有頂點 & 使每1個頂點僅被訪問1次
5.2 遍歷方式
深度優先遍歷(DFS)、廣度優先遍歷(BFS)
5.3 具體介紹
5.3.1 深度優先遍歷( DFS )
- 簡介
- 算法示意圖
- 具體實現:遞歸 & 非遞歸
此處圖的存儲結構 = 鄰接矩陣
import java.util.Stack;public class MyGraph {/*** 準備工作1:設置變量*/private int vexnum; // 存放圖中頂點數量private char[] vertices; // 存放結點數據private int [][] arcs; // 存放圖的所有邊private boolean[] visited;// 記錄節點是否已被遍歷/*** 準備工作2:初始化圖的頂點數量、數據 & 邊*/public MyGraph(int n){vexnum = n;vertices = new char[n];visited = new boolean[n];arcs = new int[n][n];}/*** 圖的深度優先遍歷算法實現:遞歸* 類似 前序遍歷*/public void DFSTraverse(){// 1. 初始化所有頂點的訪問標記// 即,都是未訪問狀態for (int i = 0; i < vexnum; i++) {visited[i] = false;}// 2. 深度優先遍歷頂點(從未被訪問的頂點開始)for(int i=0;i < vexnum;i++){if(visited[i]==false){// 若是連通圖,只會執行一次traverse(i); // ->>看關注1}}}/*** 關注1:鄰接矩陣的深度優先搜索遞歸算法* 即,從第i個頂點開始深度優先遍歷*/private void traverse(int i){// 1. 標記第i個頂點已遍歷visited[i] = true;// 2. (輸出)訪問當前遍歷的頂點visit(i);// 3. 遍歷鄰接矩陣中第i個頂點的所有鄰接頂點for(int j=0;j<vexnum;j++){// a. 若當前頂點的鄰接頂點存在 & 未被訪問,則遞歸 深度優先搜索 算法if(arcs[i][j]==1 && visited[j]==false){// b. 將當前頂點的鄰接頂點作為當前頂點,遞歸 深度優先搜索 算法traverse(j);}}}/*** 輔助算法1:訪問頂點值*/public void visit(int i){System.out.print(vertices[i] + " ");}/*** 圖的深度優先遍歷算法實現:非遞歸* 原理:采用 棧實現*/public void DFSTraverse2(){// 1. 初始化頂點訪問標記// 全部標記為:未訪問for (int i = 0; i < vexnum; i++) {visited[i] = false;}// 2. 創建棧Stack<Integer> s = new Stack<Integer>();for(int i=0 ; i<vexnum; i++){// 3. 若該頂點未被訪問if(!visited[i]){// 4. 入棧該頂點s.add(i);do{// 出棧int curr = s.pop();// 如果該節點還沒有被遍歷,則遍歷該節點并將子節點入棧if(visited[curr]==false){// 遍歷并打印visit(curr);visited[curr] = true;// 沒遍歷的子節點入棧for(int j=vexnum-1; j>=0 ; j-- ){if(arcs[curr][j]==1 && visited[j]==false){s.add(j);}}}}while(!s.isEmpty());}}}/*** 測試(遞歸 & 非遞歸)*/public static void main(String[] args) {// 1. 初始化圖的結構(頂點數量 = 9)MyGraph g = new MyGraph(9);// 2. 設置頂點數據char[] vertices = {'A','B','C','D','E','F','G','H','I'};g.setVertices(vertices);// 3. 設置邊g.addEdge(0, 1);g.addEdge(0, 5);g.addEdge(1, 0);g.addEdge(1, 2);g.addEdge(1, 6);g.addEdge(1, 8);g.addEdge(2, 1);g.addEdge(2, 3);g.addEdge(2, 8);g.addEdge(3, 2);g.addEdge(3, 4);g.addEdge(3, 6);g.addEdge(3, 7);g.addEdge(3, 8);g.addEdge(4, 3);g.addEdge(4, 5);g.addEdge(4, 7);g.addEdge(5, 0);g.addEdge(5, 4);g.addEdge(5, 6);g.addEdge(6, 1);g.addEdge(6, 3);g.addEdge(6, 5);g.addEdge(6, 7);g.addEdge(7, 3);g.addEdge(7, 4);g.addEdge(7, 6);g.addEdge(8, 1);g.addEdge(8, 2);g.addEdge(8, 3);// 4. 執行 圖的深度優先遍歷:(遞歸 & 非遞歸)System.out.println("深度優先遍歷(遞歸)");g.DFSTraverse();System.out.println("深度優先遍歷(非遞歸)");g.DFSTraverse2();}/*** 輔助算法1:添加邊(無向圖)*/public void addEdge(int i, int j) {// 邊的頭尾不能為同一節點if (i == j) return;// 將鄰接矩陣的第i行第j列的元素值置為1;arcs[i][j] = 1;// 將鄰接矩陣的第j行第i列的元素值置為1;arcs[j][i] = 1;// 設置為1代表2頂點之間存在 邊 (設置相等原因 = 鄰接矩陣 是對稱的)}/*** 輔助算法2:設置頂點數據*/public void setVertices(char[] vertices) {this.vertices = vertices;} }- 測試結果
-
特別注意
對于圖的存儲結構 = 鄰接表實現,只需要將 存儲邊 的2維數組 改成鏈表即可。 -
圖的存儲結構 = 鄰接矩陣 / 鄰接表 的性能對比
5.3.2 廣度優先遍歷(BFS)
- 簡介
- 算法示意圖
- 具體流程
注:G 比 I 先訪問的原因 = 用數組存儲頂點時,G的下標 比 I的下標小(按ABCDEFGHI順序存儲)
- 具體實現
非遞歸:采用隊列
import java.util.LinkedList; import java.util.Queue; import java.util.Stack;public class MyGraph {/*** 準備工作1:設置變量*/private int vexnum; // 存放圖中頂點數量private char[] vertices; // 存放結點數據private int [][] arcs; // 存放圖的所有邊private boolean[] visited;// 記錄節點是否已被遍歷/*** 準備工作2:初始化圖的頂點數量、數據 & 邊*/public MyGraph(int n){vexnum = n;vertices = new char[n];visited = new boolean[n];arcs = new int[n][n];}/*** 廣度優先搜索 算法實現* 原理:非遞歸(采用隊列)*/public void BFS(){// 1. 初始化所有頂點的訪問標記// 即,設置為未訪問狀態for (int i = 0; i < vexnum; i++) {visited[i] = false;}// 2. 創建隊列Queue<Integer> q=new LinkedList<Integer>();// 3. 對所有頂點做遍歷循環(從第1個頂點開始)// 若遍歷完畢,則結束整個層序遍歷for(int i=0;i < vexnum;i++){// 4. 若當前頂點未被訪問,就進行處理// 若當前頂點已被訪問,則回到3進行判斷if( visited[i]==false ) {// 5. (輸出)訪問當前頂點visit(i);// 6. 標記當前頂點已被訪問visited[i] = true;// 7. 入隊當前頂點q.add(i);// 8.判斷當前隊列是否為空// 若為空則跳出循環,回到3進行判斷while(!q.isEmpty()) {// 9. 出隊隊首元素 & 將出隊的元素 賦值為 當前頂點i = q.poll();// 10. 遍歷當前頂點的所有鄰接點// 若遍歷完畢,則回到8判斷for(int j=0; j< vexnum ; j++){// 11. 若當前頂點的鄰接頂點存在 & 未被訪問,則執行處理// 否則回到10判斷if(arcs[i][j]==1 && visited[j]==false){// 12. (輸出)訪問當前頂點的鄰接頂點visit(j);// 13. 標記當前頂點的鄰接頂點已被訪問visited[j] = true;// 14. 入隊當前頂點的鄰接頂點q.add(j);}}}}}}/*** 輔助算法1:訪問該頂點*/public void visit(int i){System.out.print(vertices[i] + " ");}/** * 測試算法*/public static void main(String[] args) {// 1. 初始化圖的結構(頂點數量 = 9MyGraph g = new MyGraph(9);// 2. 設置頂點數據char[] vertices = {'A','B','C','D','E','F','G','H','I'};g.setVertices(vertices);// 3. 設置邊g.addEdge(0, 1);g.addEdge(0, 5);g.addEdge(1, 0);g.addEdge(1, 2);g.addEdge(1, 6);g.addEdge(1, 8);g.addEdge(2, 1);g.addEdge(2, 3);g.addEdge(2, 8);g.addEdge(3, 2);g.addEdge(3, 4);g.addEdge(3, 6);g.addEdge(3, 7);g.addEdge(3, 8);g.addEdge(4, 3);g.addEdge(4, 5);g.addEdge(4, 7);g.addEdge(5, 0);g.addEdge(5, 4);g.addEdge(5, 6);g.addEdge(6, 1);g.addEdge(6, 3);g.addEdge(6, 5);g.addEdge(6, 7);g.addEdge(7, 3);g.addEdge(7, 4);g.addEdge(7, 6);g.addEdge(8, 1);g.addEdge(8, 2);g.addEdge(8, 3);// 4. 執行 圖的廣度優先遍歷(非遞歸)System.out.print("廣度優先遍歷(非遞歸):");g.BFS();}/*** 輔助算法1:添加邊(無向圖)*/public void addEdge(int i, int j) {// 邊的頭尾不能為同一節點if (i == j) return;// 將鄰接矩陣的第i行第j列的元素值置為1;arcs[i][j] = 1;// 將鄰接矩陣的第j行第i列的元素值置為1;arcs[j][i] = 1;// 設置為1代表2頂點之間存在 邊 (設置相等原因 = 鄰接矩陣 是對稱的)}/*** 輔助算法2:設置頂點數據*/public void setVertices(char[] vertices) {this.vertices = vertices;}}- 執行結果
5.4 遍歷方式對比
6. 最小生成樹
本節主要講解 圖中的 最小生成樹
6.1 定義
構造 連通網圖 的最小成本生成樹
6.2 尋找最小生成樹的算法
- 主要包括:(Prim)普利姆算法 & (Kruskal)克魯斯卡爾算法
- 具體介紹如下
6.2.1 (Prim)普利姆算法
- 算法概述
- 算法原理流程示意圖
- 舉例說明
6.2.2(Kruskal)克魯斯卡爾算法
- 算法概述
6.3 算法對比
7. 最短路徑
7.1 定義
- 對于非網圖(無權值),最短路徑 = 兩頂點間經過的邊數最少的路徑
- 對于網圖(有權值):最短路徑 = 兩頂點間經過的邊上權值和最少的路徑
第1個頂點 = 源點、第2個頂點 = 終點
7.2 需解決的問題
從源點 -> 其余各頂點的最短路徑
7.3 尋找最短路徑 算法
-
主要包括:迪杰斯特拉算法(Dijkstra)、弗洛伊德算法(Floyd)
-
具體介紹如下
8. 總結
- 本文主要講解了數據結構中的圖
- 下面我將繼續對 數據結構,有興趣可以繼續關注Carson_Ho的安卓開發筆記
幫頂 / 評論點贊!因為你的鼓勵是我寫作的最大動力!
總結
以上是生活随笔為你收集整理的Carson带你学数据结构:手把手带你了解 ”图“ 所有知识!(含DFS、BFS)的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 手游开发攻防——二、基础篇
- 下一篇: 国家级示范高等职业院校网址