图 深度优先遍历 广度优先遍历 非递归遍历 图解算法过程

图的邻接矩阵表示

通常图的表示有两种方法:邻接矩阵邻接表。

本文用邻接矩阵实现,一是代码量更少,二是代码风格也更贴近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。


如下例子:




深度和广度遍历代码如下:

[java]  view plain copy 在CODE上查看代码片 派生到我的代码片
  1. package com.collonn.algorithm;  
  2.   
  3. import java.util.LinkedList;  
  4. import java.util.Queue;  
  5. import java.util.Stack;  
  6.   
  7. /** 
  8.  * 无向图,邻接矩阵<br/> 
  9.  * 深度优先遍历<br/> 
  10.  * 广度优先遍历<br/> 
  11.  */  
  12. public class GrfDfsBfs {  
  13.     private int total;  
  14.     private String[] nodes;  
  15.     private int[][] matirx;  
  16.   
  17.     public GrfDfsBfs(int total, String[] nodes) {  
  18.         this.total = total;  
  19.         this.nodes = nodes;  
  20.         this.matirx = new int[total][total];  
  21.     }  
  22.   
  23.     private void printMatrix() {  
  24.         System.out.println("----------------- matrix -----------------");  
  25.         System.out.println("---0-1-2-3-4-5-6-7-8--");  
  26.         System.out.println("---A-B-C-D-E-F-G-H-I--");  
  27.         for (int i = 0; i < this.total; i++) {  
  28.             System.out.print(" " + this.nodes[i] + "|");  
  29.             for (int j = 0; j < this.total; j++) {  
  30.                 System.out.print(this.matirx[i][j] + "-");  
  31.             }  
  32.             System.out.print("\n");  
  33.         }  
  34.         System.out.println("----------------- matrix -----------------");  
  35.     }  
  36.   
  37.     // 设置[i][i]位置处的元素值为0,0表示图中的定点i未被访问,1表示图中的定点i已被访问  
  38.     private void resetVisited() {  
  39.         for (int i = 0; i < this.total; i++) {  
  40.             this.matirx[i][i] = 0;  
  41.         }  
  42.     }  
  43.   
  44.     // 图的深度优先遍历(递归方法)  
  45.     private void dfsRecursive(int i) {  
  46.         // 如果已访问,则返回  
  47.         if (this.matirx[i][i] == 1) {  
  48.             return;  
  49.         }  
  50.   
  51.         this.matirx[i][i] = 1;  
  52.         System.out.print(this.nodes[i]);  
  53.   
  54.         for (int j = 0; j < this.total; j++) {  
  55.             // i=j时,[i][j]表示节点是否被访问过,不参与dfs  
  56.             if (i == j) {  
  57.                 continue;  
  58.             }  
  59.   
  60.             if (this.matirx[i][j] == 1) {  
  61.                 dfsRecursive(j);  
  62.             }  
  63.         }  
  64.     }  
  65.       
  66.     // 图的深度优先遍历(用栈实现)  
  67.     private void dfsStack(Stack<Integer> stack) {  
  68.         // 如果已访问,则返回  
  69.         int k = -1;  
  70.           
  71.         while(!stack.empty()){  
  72.             k = stack.peek().intValue();  
  73.             boolean needPop = true;  
  74.             for(int i = 0; i < this.total; i++){  
  75.                 if(this.matirx[k][i] == 1 && this.matirx[i][i] == 0){  
  76.                     stack.push(i);  
  77.                     this.matirx[i][i] = 1;  
  78.                     System.out.print(this.nodes[i]);  
  79.                     needPop = false;  
  80.                     break;  
  81.                 }  
  82.             }  
  83.             if(needPop){  
  84.                 stack.pop();  
  85.             }  
  86.         }  
  87.     }  
  88.   
  89.     // 图的广度优先遍历  
  90.     private void bfsQueue(Queue<Integer> ls) {  
  91.         if (ls == null || ls.size() == 0) {  
  92.             return;  
  93.         }  
  94.   
  95.         int i = ls.poll().intValue();  
  96.         // 如果已访问,则跳过该元素,继续访问队列的下一个元素  
  97.         if (this.matirx[i][i] == 1) {  
  98.             this.bfsQueue(ls);  
  99.             return;  
  100.         }  
  101.   
  102.         this.matirx[i][i] = 1;  
  103.         System.out.print("" + this.nodes[i]);  
  104.   
  105.         for (int j = 0; j < this.total; j++) {  
  106.             // i=j时,[i][j]表示节点是否被访问过,不参与bfs  
  107.             if (i == j) {  
  108.                 continue;  
  109.             }  
  110.   
  111.             //如果顶点已访问过,则不再加入队列  
  112.             if (this.matirx[i][j] == 1 && this.matirx[j][j] != 1) {  
  113.                 ls.offer(j);  
  114.             }  
  115.         }  
  116.   
  117.         // System.out.print("\n队列元素:");  
  118.         // for (Integer k : ls) {  
  119.         // System.out.print(k);  
  120.         // }  
  121.         // System.out.println("");  
  122.   
  123.         this.bfsQueue(ls);  
  124.     }  
  125.   
  126.     // 初始化图数据  
  127.     // 0---1---2---3---4---5---6---7---8---  
  128.     // A---B---C---D---E---F---G---H---I---  
  129.     private void initGrf() {  
  130.         // A-B, A-D, A-E  
  131.         this.matirx[0][1] = 1;  
  132.         this.matirx[1][0] = 1;  
  133.         this.matirx[0][3] = 1;  
  134.         this.matirx[3][0] = 1;  
  135.         this.matirx[0][4] = 1;  
  136.         this.matirx[4][0] = 1;  
  137.         // B-C  
  138.         this.matirx[1][2] = 1;  
  139.         this.matirx[2][1] = 1;  
  140.         // C-F  
  141.         this.matirx[2][5] = 1;  
  142.         this.matirx[5][2] = 1;  
  143.         // D-E, D-G  
  144.         this.matirx[3][4] = 1;  
  145.         this.matirx[4][3] = 1;  
  146.         this.matirx[3][6] = 1;  
  147.         this.matirx[6][3] = 1;  
  148.         // E-F, E-H  
  149.         this.matirx[4][5] = 1;  
  150.         this.matirx[5][4] = 1;  
  151.         this.matirx[4][7] = 1;  
  152.         this.matirx[7][4] = 1;  
  153.         // F-H, F-I  
  154.         this.matirx[5][7] = 1;  
  155.         this.matirx[7][5] = 1;  
  156.         this.matirx[5][8] = 1;  
  157.         this.matirx[8][5] = 1;  
  158.         // G-H  
  159.         this.matirx[6][7] = 1;  
  160.         this.matirx[7][6] = 1;  
  161.         // H-I  
  162.         this.matirx[7][8] = 1;  
  163.         this.matirx[8][7] = 1;  
  164.     }  
  165.   
  166.     // 初始化图数据  
  167.     // 0---1---2---3---4---5---6---7---8---  
  168.     // A---B---C---D---E---F---G---H---I---  
  169.     private void initGrf2() {  
  170.         // A-B, A-D, A-E  
  171.         this.matirx[0][1] = 1;  
  172.         this.matirx[1][0] = 1;  
  173.         this.matirx[0][3] = 1;  
  174.         this.matirx[3][0] = 1;  
  175.         this.matirx[0][4] = 1;  
  176.         this.matirx[4][0] = 1;  
  177.         // B-C  
  178.         this.matirx[1][2] = 1;  
  179.         this.matirx[2][1] = 1;  
  180.         // C-F  
  181.         this.matirx[2][5] = 1;  
  182.         this.matirx[5][2] = 1;  
  183.         // D-E  
  184.         this.matirx[3][4] = 1;  
  185.         this.matirx[4][3] = 1;  
  186.         // E-F, E-H  
  187.         this.matirx[4][5] = 1;  
  188.         this.matirx[5][4] = 1;  
  189.         this.matirx[4][7] = 1;  
  190.         this.matirx[7][4] = 1;  
  191.         // F-H, F-I  
  192.         this.matirx[5][7] = 1;  
  193.         this.matirx[7][5] = 1;  
  194.         this.matirx[5][8] = 1;  
  195.         this.matirx[8][5] = 1;  
  196.         // G-H  
  197.         this.matirx[6][7] = 1;  
  198.         this.matirx[7][6] = 1;  
  199.         // H-I  
  200.         this.matirx[7][8] = 1;  
  201.         this.matirx[8][7] = 1;  
  202.     }  
  203.   
  204.     // 初始化图数据  
  205.     // 0---1---2---3---4---5---6---7---8---  
  206.     // A---B---C---D---E---F---G---H---I---  
  207.     private void initGrf3() {  
  208.         // A-D, A-E  
  209.         this.matirx[0][3] = 1;  
  210.         this.matirx[3][0] = 1;  
  211.         this.matirx[0][4] = 1;  
  212.         this.matirx[4][0] = 1;  
  213.         // B-C  
  214.         this.matirx[1][2] = 1;  
  215.         this.matirx[2][1] = 1;  
  216.         // C-F  
  217.         this.matirx[2][5] = 1;  
  218.         this.matirx[5][2] = 1;  
  219.         // E-H, E-I  
  220.         this.matirx[4][7] = 1;  
  221.         this.matirx[7][4] = 1;  
  222.         this.matirx[4][8] = 1;  
  223.         this.matirx[8][4] = 1;  
  224.         // F-I  
  225.         this.matirx[5][8] = 1;  
  226.         this.matirx[8][5] = 1;  
  227.         // G-H  
  228.         this.matirx[6][7] = 1;  
  229.         this.matirx[7][6] = 1;  
  230.     }  
  231.   
  232.     public static void main(String[] args) {  
  233.         String[] nodes = new String[] { "A""B""C""D""E""F""G""H""I" };  
  234.         GrfDfsBfs grf = new GrfDfsBfs(9, nodes);  
  235.         grf.initGrf();  
  236.         grf.printMatrix();  
  237.   
  238.         System.out.println("------ 深度优先遍历(递归)开始 ------");  
  239.         grf.resetVisited();  
  240.         grf.dfsRecursive(0);  
  241.         System.out.println();  
  242.         System.out.println("------ 深度优先遍历(递归)结束 ------");  
  243.           
  244.         System.out.println("------ 深度优先遍历(栈)开始 ------");  
  245.         grf.resetVisited();  
  246.         Stack<Integer> stack = new Stack<Integer>();  
  247.         stack.push(0);  
  248.         grf.matirx[0][0] = 1;  
  249.         System.out.print(grf.nodes[0]);  
  250.         grf.dfsStack(stack);  
  251.         System.out.println();  
  252.         System.out.println("------ 深度优先遍历(栈)结束 ------");  
  253.   
  254.         System.out.println("------ 广度优先遍历开始 ------");  
  255.         grf.resetVisited();  
  256.         Queue<Integer> queue = new LinkedList<Integer>();  
  257.         queue.add(0);  
  258.         grf.bfsQueue(queue);  
  259.         System.out.println();  
  260.         System.out.println("------ 广度优先遍历结束 ------");  
  261.     }  
  262.   
  263. }  
  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值