• 《算法》第四章部分程序 part 7


    ▶ 书中第四章部分程序,包括在加上自己补充的代码,图中找欧拉环

    ● 无向图中寻找欧拉环

      1 package package01;
      2 
      3 import edu.princeton.cs.algs4.StdOut;
      4 import edu.princeton.cs.algs4.StdRandom;
      5 import edu.princeton.cs.algs4.GraphGenerator;
      6 import edu.princeton.cs.algs4.Graph;
      7 import edu.princeton.cs.algs4.Stack;
      8 import edu.princeton.cs.algs4.Queue;
      9 import edu.princeton.cs.algs4.BreadthFirstPaths;
     10 
     11 public class class01
     12 {
     13     private Stack<Integer> cycle = new Stack<Integer>();    // 用栈来保存欧拉环的路径,栈空表示无欧拉环
     14 
     15     private static class Edge                               // 图的边的结构
     16     {
     17         private final int v;
     18         private final int w;
     19         private boolean isUsed;
     20 
     21         public Edge(int v, int w)
     22         {
     23             this.v = v;
     24             this.w = w;
     25             isUsed = false;
     26         }
     27 
     28         public int other(int vertex)
     29         {
     30             if (vertex == v)
     31                 return w;
     32             if (vertex == w)
     33                 return v;
     34             throw new IllegalArgumentException("
    <other> No such vertex.
    ");
     35         }
     36     }
     37 
     38     public class01(Graph G)
     39     {
     40         if (G.E() == 0)                 // 至少有 1 条边
     41             return;
     42         for (int v = 0; v < G.V(); v++) // 欧拉环要求每个顶点的度均为偶数
     43         {
     44             if (G.degree(v) % 2 != 0)
     45                 return;
     46         }
     47         Queue<Edge>[] adj = (Queue<Edge>[]) new Queue[G.V()];   // 把邻接表每个链表转化为一个队列,以便遍历(其实可以不要?)
     48         for (int v = 0; v < G.V(); v++)
     49             adj[v] = new Queue<Edge>();
     50         for (int v = 0; v < G.V(); v++)
     51         {
     52             boolean selfEdge = false;           // 用于判断奇偶
     53             for (int w : G.adj(v))
     54             {
     55                 if (v == w)
     56                 {
     57                     if (!selfEdge)              // 考虑某个顶点的链表出现 2k 次自己,实际只有 k 条自边,即 k 个自环
     58                     {
     59                         Edge e = new Edge(v, w);
     60                         adj[v].enqueue(e);
     61                         adj[w].enqueue(e);
     62                     }
     63                     selfEdge = !selfEdge;
     64                 }
     65                 else if (v < w)                 // 控制索引只添加向后顶点的边,防止重复计数
     66                 {
     67                     Edge e = new Edge(v, w);
     68                     adj[v].enqueue(e);
     69                     adj[w].enqueue(e);
     70                 }
     71             }
     72         }
     73         Stack<Integer> stack = new Stack<Integer>();            // 用栈保存遍历顺序,也即欧拉环中顶点顺序
     74         stack.push(nonIsolatedVertex(G));                       // 第一个非孤立点压栈
     75         for (cycle = new Stack<Integer>(); !stack.isEmpty();)
     76         {
     77             int v = stack.pop();
     78             for (; !adj[v].isEmpty();)                          // 深度优先遍历
     79             {
     80                 Edge edge = adj[v].dequeue();
     81                 if (edge.isUsed)
     82                     continue;
     83                 edge.isUsed = true;     // 从 adj[v] 处改 edge(v,w) 则 adj[w] 相应顶点也变化,保证每条边只修改一次,防止回头路
     84                 stack.push(v);
     85                 v = edge.other(v);
     86             }
     87             cycle.push(v);              // 遍历完成,把终点入栈
     88         }
     89         if (cycle.size() != G.E() + 1)  // 存储了遍历顺序,起点终点记两次,所以比边数多 1
     90             cycle = null;        
     91     }
     92 
     93     public Iterable<Integer> cycle()
     94     {
     95         return cycle;
     96     }
     97 
     98     public boolean hasEulerianCycle()
     99     {
    100         return cycle != null;
    101     }
    102 
    103     private static int nonIsolatedVertex(Graph G)   // 寻找图上的第一个非独立点,也即度数大于 0 的点
    104     {
    105         for (int v = 0; v < G.V(); v++)
    106         {
    107             if (G.degree(v) > 0)
    108                 return v;
    109         }
    110         return -1;
    111     }
    112 
    113     private static boolean satisfiesNecessaryAndSufficientConditions(Graph G)   // 用欧拉环的充要条件进行判定
    114     {
    115         if (G.E() == 0)                             // 至少有一条边
    116             return false;
    117         for (int v = 0; v < G.V(); v++)             // 每个顶点的度是偶数
    118         {
    119             if (G.degree(v) % 2 != 0)
    120                 return false;
    121         }
    122         BreadthFirstPaths bfs = new BreadthFirstPaths(G, nonIsolatedVertex(G)); // 图是连通的
    123         for (int v = 0; v < G.V(); v++)
    124         {
    125             if (G.degree(v) > 0 && !bfs.hasPathTo(v))
    126                 return false;
    127         }
    128         return true;
    129     }  
    130 
    131     private static void unitTest(Graph G, String description)
    132     {
    133         System.out.printf("
    %s--------------------------------
    ", description);
    134         StdOut.print(G);
    135         class01 euler = new class01(G);
    136         System.out.printf("Eulerian cycle: ");
    137         if (euler.hasEulerianCycle())
    138         {
    139             for (int v : euler.cycle())
    140                 System.out.printf(" %d", v);
    141         }
    142         System.out.println();
    143     }
    144 
    145     public static void main(String[] args)
    146     {
    147         int V = Integer.parseInt(args[0]);
    148         int E = Integer.parseInt(args[1]);
    149 
    150         Graph G1 = GraphGenerator.eulerianCycle(V, E);
    151         unitTest(G1, "Eulerian cycle");
    152 
    153         Graph G2 = GraphGenerator.eulerianPath(V, E);
    154         unitTest(G2, "Eulerian path");
    155 
    156         Graph G3 = new Graph(V);
    157         unitTest(G3, "Empty graph");
    158 
    159         Graph G4 = new Graph(V);
    160         int v4 = StdRandom.uniform(V);
    161         G4.addEdge(v4, v4);
    162         unitTest(G4, "Single self loop");
    163 
    164         Graph H1 = GraphGenerator.eulerianCycle(V / 2, E / 2);          // 把两个欧拉环连在一起
    165         Graph H2 = GraphGenerator.eulerianCycle(V - V / 2, E - E / 2);
    166         int[] perm = new int[V];
    167         for (int i = 0; i < V; i++)
    168             perm[i] = i;
    169         StdRandom.shuffle(perm);
    170         Graph G5 = new Graph(V);
    171         for (int v = 0; v < H1.V(); v++)
    172         {
    173             for (int w : H1.adj(v))
    174                 G5.addEdge(perm[v], perm[w]);
    175         }
    176         for (int v = 0; v < H2.V(); v++)
    177         {
    178             for (int w : H2.adj(v))
    179                 G5.addEdge(perm[V / 2 + v], perm[V / 2 + w]);
    180         }
    181         unitTest(G5, "Union of two disjoint cycles");
    182 
    183         Graph G6 = GraphGenerator.simple(V, E);
    184         unitTest(G6, "Random simple graph");
    185     }
    186 }

    ● 有向图中寻找欧拉环,只注释了与上面不同的地方

      1 package package01;
      2 
      3 import java.util.Iterator;
      4 import edu.princeton.cs.algs4.StdOut;
      5 import edu.princeton.cs.algs4.StdRandom;
      6 import edu.princeton.cs.algs4.DigraphGenerator;
      7 import edu.princeton.cs.algs4.Graph;
      8 import edu.princeton.cs.algs4.Digraph;
      9 import edu.princeton.cs.algs4.Stack;
     10 import edu.princeton.cs.algs4.BreadthFirstPaths;
     11 
     12 public class class01
     13 {
     14     private Stack<Integer> cycle = new Stack<Integer>();
     15 
     16     public class01(Digraph G)
     17     {
     18         if (G.E() == 0)                 // 至少有一条边
     19             return;
     20         for (int v = 0; v < G.V(); v++) // 要求每个店的入度等于出度(否则至多为欧拉环路径,不能是环)
     21         {
     22             if (G.outdegree(v) != G.indegree(v))
     23                 return;
     24         }
     25         Iterator<Integer>[] adj = (Iterator<Integer>[]) new Iterator[G.V()];    // 使用迭代器而不是队列来存储
     26         for (int v = 0; v < G.V(); v++)
     27             adj[v] = G.adj(v).iterator();
     28         Stack<Integer> stack = new Stack<Integer>();        
     29         for (stack.push(nonIsolatedVertex(G)); !stack.isEmpty();)
     30         {
     31             int v = stack.pop();
     32             for (; adj[v].hasNext(); v = adj[v].next())
     33                 stack.push(v);
     34             cycle.push(v);
     35         }
     36         if (cycle.size() != G.E() + 1)
     37             cycle = null;
     38     }
     39 
     40     public Iterable<Integer> cycle()
     41     {
     42         return cycle;
     43     }
     44 
     45     public boolean hasEulerianCycle()
     46     {
     47         return cycle != null;
     48     }
     49 
     50     private static int nonIsolatedVertex(Digraph G)
     51     {
     52         for (int v = 0; v < G.V(); v++)
     53         {
     54             if (G.outdegree(v) > 0)
     55                 return v;
     56         }
     57         return -1;
     58     }
     59 
     60     private static boolean satisfiesNecessaryAndSufficientConditions(Digraph G) // 用欧拉环的充要条件进行判定
     61     {
     62         if (G.E() == 0)                 // 至少有 1 条边
     63             return false;
     64         for (int v = 0; v < G.V(); v++) // 每个顶点的入度等于出度
     65         {
     66             if (G.outdegree(v) != G.indegree(v))
     67                 return false;
     68         }
     69         Graph H = new Graph(G.V());     // 把图做成无向的,判断所有顶点连通
     70         for (int v = 0; v < G.V(); v++)
     71         {
     72             for (int w : G.adj(v))
     73                 H.addEdge(v, w);
     74         }
     75         BreadthFirstPaths bfs = new BreadthFirstPaths(H, nonIsolatedVertex(G));
     76         for (int v = 0; v < G.V(); v++)
     77         {
     78             if (H.degree(v) > 0 && !bfs.hasPathTo(v))
     79                 return false;
     80         }
     81         return true;
     82     }
     83 
     84     private static void unitTest(Digraph G, String description)
     85     {
     86         System.out.printf("
    %s--------------------------------
    ", description);
     87         StdOut.print(G);
     88         class01 euler = new class01(G);
     89         System.out.printf("Eulerian cycle: ");
     90         if (euler.hasEulerianCycle())
     91         {
     92             for (int v : euler.cycle())
     93                 System.out.printf(" %d", v);
     94         }
     95         StdOut.println();
     96     }
     97 
     98     public static void main(String[] args)
     99     {
    100         int V = Integer.parseInt(args[0]);
    101         int E = Integer.parseInt(args[1]);
    102 
    103         Digraph G1 = DigraphGenerator.eulerianCycle(V, E);
    104         unitTest(G1, "Eulerian cycle");
    105 
    106         Digraph G2 = DigraphGenerator.eulerianPath(V, E);
    107         unitTest(G2, "Eulerian path");
    108 
    109         Digraph G3 = new Digraph(V);
    110         unitTest(G3, "Empty digraph");
    111 
    112         Digraph G4 = new Digraph(V);
    113         int v4 = StdRandom.uniform(V);
    114         G4.addEdge(v4, v4);
    115         unitTest(G4, "single self loop");
    116 
    117         Digraph H1 = DigraphGenerator.eulerianCycle(V / 2, E / 2);
    118         Digraph H2 = DigraphGenerator.eulerianCycle(V - V / 2, E - E / 2);
    119         int[] perm = new int[V];
    120         for (int i = 0; i < V; i++)
    121             perm[i] = i;
    122         StdRandom.shuffle(perm);
    123         Digraph G5 = new Digraph(V);
    124         for (int v = 0; v < H1.V(); v++)
    125         {
    126             for (int w : H1.adj(v))
    127                 G5.addEdge(perm[v], perm[w]);
    128         }
    129         for (int v = 0; v < H2.V(); v++)
    130         {
    131             for (int w : H2.adj(v))
    132                 G5.addEdge(perm[V / 2 + v], perm[V / 2 + w]);
    133         }
    134         unitTest(G5, "Union of two disjoint cycles");
    135 
    136         Digraph G6 = DigraphGenerator.simple(V, E);
    137         unitTest(G6, "Simple digraph");
    138         /*
    139         Digraph G7 = new Digraph(new In("eulerianD.txt"));
    140         unitTest(G7, "4-vertex Eulerian digraph from file");
    141         */
    142     }
    143 }
  • 相关阅读:
    ReportingServices报表管理器实现订阅
    sharepoint部署
    在sharepoint工程中添加引用
    asp:DropDownList选择事件出错
    ETL项目
    javascript refresh page 刷新页面的几种方法(转)
    innerHtml 和 innerText用法:(转载)
    用JavaScript隐藏控件的方法(转)
    JS中onpropertychange事件和onchange事件区别
    Window 对象
  • 原文地址:https://www.cnblogs.com/cuancuancuanhao/p/9821619.html
Copyright © 2020-2023  润新知