图 深度优先遍历 广度优先遍历 非递归遍历 图解算法过程
圖的鄰接矩陣表示
通常圖的表示有兩種方法:鄰接矩陣,鄰接表。
本文用鄰接矩陣實現,一是代碼量更少,二是代碼風格也更貼近C語言。但不論是圖的哪種實現方式,其基本的實現思想是不變的。
1:節點的信息,我們用一維數組a[n]來存儲,假設圖共有n個節點。
2:節點與節點間的關系,我們用二維數組b[n][n]存儲。
3:b[i][j]表示,從i到j有向連通,b[j][i]表示從j到i有向連通,而當i=j時(矩陣的對角線上的元素),b[i][j]沒有實際意思,在遍歷時,我可以用來存儲定節點是否訪問過。
圖的深度優先遍歷
DFS類似于樹的先根遍歷,盡可能深的去訪問節點。
DFS算法過程我們用到了遞歸的思想,如果還需要求出路徑,可以借助棧來實現(后文會不斷的實現圖的各種算法)。
步驟1:訪問節點,將該節點標記為已訪問。
步驟2:如果節點還有未標記的鄰接點,繼續步驟1,否則返回。
圖的廣度優先遍歷
BFS我們用隊列來實現。
步驟1:如果隊列為空,則返回,否則,取出隊列頭節點,將該節點標記為已訪問。
步驟2:同時,將該節點所有未標記的鄰接點,加入隊列尾,繼續步驟1。
圖的非遞歸遍歷
我們借助棧來實現。
步驟1:如果棧為空,則退出程序,否則,訪問棧頂節點,但不彈出棧點節點。
步驟2:如果棧頂節點的所有直接鄰接點都已訪問過,則彈出棧頂節點,否則,將該棧頂節點的未訪問的其中一個鄰接點壓入棧,同時,標記該鄰接點為已訪問,繼續步驟1。
如下例子:
package com.collonn.algorithm;import java.util.LinkedList; import java.util.Queue; import java.util.Stack;/*** 無向圖,鄰接矩陣<br/>* 深度優先遍歷<br/>* 廣度優先遍歷<br/>*/ public class GrfDfsBfs {private int total;private String[] nodes;private int[][] matirx;public GrfDfsBfs(int total, String[] nodes) {this.total = total;this.nodes = nodes;this.matirx = new int[total][total];}private void printMatrix() {System.out.println("----------------- matrix -----------------");System.out.println("---0-1-2-3-4-5-6-7-8--");System.out.println("---A-B-C-D-E-F-G-H-I--");for (int i = 0; i < this.total; i++) {System.out.print(" " + this.nodes[i] + "|");for (int j = 0; j < this.total; j++) {System.out.print(this.matirx[i][j] + "-");}System.out.print("\n");}System.out.println("----------------- matrix -----------------");}// 設置[i][i]位置處的元素值為0,0表示圖中的定點i未被訪問,1表示圖中的定點i已被訪問private void resetVisited() {for (int i = 0; i < this.total; i++) {this.matirx[i][i] = 0;}}// 圖的深度優先遍歷(遞歸方法)private void dfsRecursive(int i) {// 如果已訪問,則返回if (this.matirx[i][i] == 1) {return;}this.matirx[i][i] = 1;System.out.print(this.nodes[i]);for (int j = 0; j < this.total; j++) {// i=j時,[i][j]表示節點是否被訪問過,不參與dfsif (i == j) {continue;}if (this.matirx[i][j] == 1) {dfsRecursive(j);}}}// 圖的深度優先遍歷(用棧實現)private void dfsStack(Stack<Integer> stack) {// 如果已訪問,則返回int k = -1;while(!stack.empty()){k = stack.peek().intValue();boolean needPop = true;for(int i = 0; i < this.total; i++){if(this.matirx[k][i] == 1 && this.matirx[i][i] == 0){stack.push(i);this.matirx[i][i] = 1;System.out.print(this.nodes[i]);needPop = false;break;}}if(needPop){stack.pop();}}}// 圖的廣度優先遍歷private void bfsQueue(Queue<Integer> ls) {if (ls == null || ls.size() == 0) {return;}int i = ls.poll().intValue();// 如果已訪問,則跳過該元素,繼續訪問隊列的下一個元素if (this.matirx[i][i] == 1) {this.bfsQueue(ls);return;}this.matirx[i][i] = 1;System.out.print("" + this.nodes[i]);for (int j = 0; j < this.total; j++) {// i=j時,[i][j]表示節點是否被訪問過,不參與bfsif (i == j) {continue;}//如果頂點已訪問過,則不再加入隊列if (this.matirx[i][j] == 1 && this.matirx[j][j] != 1) {ls.offer(j);}}// System.out.print("\n隊列元素:");// for (Integer k : ls) {// System.out.print(k);// }// System.out.println("");this.bfsQueue(ls);}// 初始化圖數據// 0---1---2---3---4---5---6---7---8---// A---B---C---D---E---F---G---H---I---private void initGrf() {// A-B, A-D, A-Ethis.matirx[0][1] = 1;this.matirx[1][0] = 1;this.matirx[0][3] = 1;this.matirx[3][0] = 1;this.matirx[0][4] = 1;this.matirx[4][0] = 1;// B-Cthis.matirx[1][2] = 1;this.matirx[2][1] = 1;// C-Fthis.matirx[2][5] = 1;this.matirx[5][2] = 1;// D-E, D-Gthis.matirx[3][4] = 1;this.matirx[4][3] = 1;this.matirx[3][6] = 1;this.matirx[6][3] = 1;// E-F, E-Hthis.matirx[4][5] = 1;this.matirx[5][4] = 1;this.matirx[4][7] = 1;this.matirx[7][4] = 1;// F-H, F-Ithis.matirx[5][7] = 1;this.matirx[7][5] = 1;this.matirx[5][8] = 1;this.matirx[8][5] = 1;// G-Hthis.matirx[6][7] = 1;this.matirx[7][6] = 1;// H-Ithis.matirx[7][8] = 1;this.matirx[8][7] = 1;}// 初始化圖數據// 0---1---2---3---4---5---6---7---8---// A---B---C---D---E---F---G---H---I---private void initGrf2() {// A-B, A-D, A-Ethis.matirx[0][1] = 1;this.matirx[1][0] = 1;this.matirx[0][3] = 1;this.matirx[3][0] = 1;this.matirx[0][4] = 1;this.matirx[4][0] = 1;// B-Cthis.matirx[1][2] = 1;this.matirx[2][1] = 1;// C-Fthis.matirx[2][5] = 1;this.matirx[5][2] = 1;// D-Ethis.matirx[3][4] = 1;this.matirx[4][3] = 1;// E-F, E-Hthis.matirx[4][5] = 1;this.matirx[5][4] = 1;this.matirx[4][7] = 1;this.matirx[7][4] = 1;// F-H, F-Ithis.matirx[5][7] = 1;this.matirx[7][5] = 1;this.matirx[5][8] = 1;this.matirx[8][5] = 1;// G-Hthis.matirx[6][7] = 1;this.matirx[7][6] = 1;// H-Ithis.matirx[7][8] = 1;this.matirx[8][7] = 1;}// 初始化圖數據// 0---1---2---3---4---5---6---7---8---// A---B---C---D---E---F---G---H---I---private void initGrf3() {// A-D, A-Ethis.matirx[0][3] = 1;this.matirx[3][0] = 1;this.matirx[0][4] = 1;this.matirx[4][0] = 1;// B-Cthis.matirx[1][2] = 1;this.matirx[2][1] = 1;// C-Fthis.matirx[2][5] = 1;this.matirx[5][2] = 1;// E-H, E-Ithis.matirx[4][7] = 1;this.matirx[7][4] = 1;this.matirx[4][8] = 1;this.matirx[8][4] = 1;// F-Ithis.matirx[5][8] = 1;this.matirx[8][5] = 1;// G-Hthis.matirx[6][7] = 1;this.matirx[7][6] = 1;}public static void main(String[] args) {String[] nodes = new String[] { "A", "B", "C", "D", "E", "F", "G", "H", "I" };GrfDfsBfs grf = new GrfDfsBfs(9, nodes);grf.initGrf();grf.printMatrix();System.out.println("------ 深度優先遍歷(遞歸)開始 ------");grf.resetVisited();grf.dfsRecursive(0);System.out.println();System.out.println("------ 深度優先遍歷(遞歸)結束 ------");System.out.println("------ 深度優先遍歷(棧)開始 ------");grf.resetVisited();Stack<Integer> stack = new Stack<Integer>();stack.push(0);grf.matirx[0][0] = 1;System.out.print(grf.nodes[0]);grf.dfsStack(stack);System.out.println();System.out.println("------ 深度優先遍歷(棧)結束 ------");System.out.println("------ 廣度優先遍歷開始 ------");grf.resetVisited();Queue<Integer> queue = new LinkedList<Integer>();queue.add(0);grf.bfsQueue(queue);System.out.println();System.out.println("------ 廣度優先遍歷結束 ------");}}
總結
以上是生活随笔為你收集整理的图 深度优先遍历 广度优先遍历 非递归遍历 图解算法过程的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 图的遍历递归和非递归实现
- 下一篇: ACM 模板--链接表 无向图