《算法》第四章部分程序 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("\n<other> No such vertex.\n");
 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("\n%s--------------------------------\n", 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("\n%s--------------------------------\n", 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 }

原文地址:https://www.cnblogs.com/cuancuancuanhao/p/9821619.html

时间: 2024-11-08 13:11:49

《算法》第四章部分程序 part 7的相关文章

贪心算法?我全都要!——算法第四章上机实践报告

算法第四章上机实践报告 一.        实践题目 4-1 程序存储问题 (90 分) 设有n 个程序{1,2,…, n }要存放在长度为L的磁带上.程序i存放在磁带上的长度是 li,1≤i≤n. 程序存储问题要求确定这n 个程序在磁带上的一个存储方案, 使得能够在磁带上存储尽可能多的程序. 对于给定的n个程序存放在磁带上的长度,计算磁带上最多可以存储的程序数. 输入格式: 第一行是2 个正整数,分别表示文件个数n和磁带的长度L.接下来的1行中,有n个正整数,表示程序存放在磁带上的长度. 输出

《算法》第一章部分程序

? 书中第一章部分程序,加上自己补充的代码.包括若干种二分搜索和寻找图上连通分量数的两种算法. ● 代码,二分搜索 1 package package01; 2 3 import java.util.Arrays; 4 import edu.princeton.cs.algs4.StdRandom; 5 6 public class class01 7 { 8 public int binarySearch(int [] a, int target) // 非递归实现 9 { 10 int lp

第四章 MySQL程序

目录 4.1 MySQL程序概述 4.2 使用MySQL程序 4.2.1 调用MySQL程序 4.2.2 连接MySQL服务器 4.2.3 指定程序选项 4.2.4 在命令行使用选项 4.2.5 程序选项编辑器 4.2.6 使用选项文件 4.2.7 影响文件选项处理的命令行选项 4.2.8 使用选项设置程序变量 4.2.9 选项默认值,选项期望值和=符号 4.2.10 设置环境变量 4.3 MySQL 服务器和服务启动程序 4.3.1 mysqld --MySQL服务器 4.3.2 mysqld

算法 第四章实践

1.实践题目 程序存储问题 2.问题描述 设有n 个程序{1,2,-, n }要存放在长度为L的磁带上.程序i存放在磁带上的长度是 li,1≤i≤n. 程序存储问题要求确定这n 个程序在磁带上的一个存储方案, 使得能够在磁带上存储尽可能多的程序. 对于给定的n个程序存放在磁带上的长度,计算磁带上最多可以存储的程序数. 3.算法描述 for(int i=0;i<n;i++) cin>>a[i];//将程序的长度存放在数组之中 sort(a,a+n);//将数组中的元素排序 int num=

算法第四章上机实践报告

一.实践题目:删数问题 二.问题描述: 给定一个n位的正整数a,去掉其中任意k(k≤n) 个数字后,剩下的数字按照原次序排列成一个的新的正整数.在给定的n位正整数a和正整数k的情况下,输出完成该操作后剩下的正整数. 三.算法描述: 正整数的位数不定,用long long去存不一定存的下,所以用一个字符数组str[]来存储.此处运用一种贪心策略,不停的对这个整数进行扫描,当发现当前位的后一位比当前位小的情况,将当前位删除(例如1873,删除8肯定比删除7更优),若所有位数的数字按照升序排列,则删除

算法第四章上机实验报告

题目:删数问题 问题描述:输入一个正整数a和一个正整数k(k≤n ),在n位正整数a中去掉其中任意k个数字后,剩下的数字按原次序排列组成一个新 的正整数. 算法描述:从前往后进行比较,删掉升序的最后那个数,若一直保持升序,则删掉最后一位数,重复k次,删掉k个数 时间复杂度:该算法主要进行了k次的for循环,每次循环的时间复杂度是o(n),故其时间复杂度为o(n) 空间复杂度:该算法不需要额外的数组或变量来存放数据,故其空间复杂度为o(1) 心得体会:在做题的时候还要再细心一点,特别对于一些小细节

算法第四章实践报告

1.选择第二题进行分析. 给定n位正整数a,去掉其中任意k≤n 个数字后,剩下的数字按原次序排列组成一个新 的正整数.对于给定的n位正整数a和正整数 k,设计一个算法找出剩下数字组成的新数最 小的删数方案. 输入 178543 4 输出132.问题描述:就是删掉指定数字中的一些数字,然后重新组成一个新的数使得这个数达到最小.3.算法描述:这个问题第一眼看下去容易想到对数组不停的排序然后不断删掉最大的,但是按着这个思路去做却发现,不断提取整型数组然后排序会比较复杂,因为要不断求余数等等,而且代码不

啊哈算法第四章第二节解救小哈Java实现

package corejava; public class FourTwo { static int m;//(m,n)为几行几列 static int n; static int p;//(p,q)为终点 static int q; static int min=9999; static int [][]a=new int [51][51];//存放地图 static int [][]b=new int [51][51];//存放路径 static String []record=new S

java数据结构和算法-----第四章

栈和队列 栈(后进先出) 栈,只允许访问一个数据项:即最后插入的数据项. 栈可以用来检查括号的匹配问题和解析数学表达式,类似于在编译原理中的使用. 该图片的操作实际上归纳起来:1.读到左分隔符入栈,2.读到右分隔符就和从栈顶弹出来的左分割符匹配,匹配成功,就正常进行. 3.读到一般的字母字符,就过滤掉.栈的入栈和出栈的时间复杂度都是O(1) 队列(先进先出) 队列的主要有以下几种方法:insert(),remove(),peek(),isFull(),isEmpty()和size()