Skip to content

Commit 811971c

Browse files
rostamclaude
andcommitted
Fix DFS root-revisit bug in isConnected; add Prufer sequence report
Issue #41: AlgorithmUtils.isConnected never marked the root node as visited before calling dfs, so any neighbor of node 0 would see parent[0]==-1 and re-enter node 0, causing redundant traversal and potential StackOverflowError on large dense graphs. Fix: set parent[0]=0 before the dfs call. Issue #38: Add PruferSequence report extension under basicreports. Repeatedly removes the leaf with the smallest vertex id and appends its neighbor's id to build the n-2 length Prufer sequence of a labeled tree. Returns an error string if the graph is not a tree. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
1 parent 4e78fc0 commit 811971c

2 files changed

Lines changed: 101 additions & 0 deletions

File tree

src/graphtea/extensions/AlgorithmUtils.java

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,7 @@ public static boolean isConnected(GraphModel g) {
5353
for (int i = 0; i < g.getVerticesCount(); i++) {
5454
parent[i] = -1;
5555
}
56+
parent[0] = 0; // mark root as visited so it is not re-entered during recursion
5657
dfs(g, 0, vs, parent);
5758
return vs.stream().distinct().count() == g.getVerticesCount();
5859
}
Lines changed: 100 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,100 @@
1+
// GraphTea Project: http://github.com/graphtheorysoftware/GraphTea
2+
// Copyright (C) 2012 Graph Theory Software Foundation: http://GraphTheorySoftware.com
3+
// Copyright (C) 2008 Mathematical Science Department of Sharif University of Technology
4+
// Distributed under the terms of the GNU General Public License (GPL): http://www.gnu.org/licenses/
5+
6+
package graphtea.extensions.reports.basicreports;
7+
8+
import graphtea.graph.graph.GraphModel;
9+
import graphtea.graph.graph.Vertex;
10+
import graphtea.platform.lang.CommandAttitude;
11+
import graphtea.plugins.reports.extension.GraphReportExtension;
12+
13+
14+
/**
15+
* Computes the Prüfer sequence of a labeled tree.
16+
*
17+
* The Prüfer sequence is a unique sequence of n-2 vertex labels that encodes
18+
* a labeled tree on n vertices. It is produced by repeatedly removing the leaf
19+
* with the smallest label and appending its neighbor's label to the sequence.
20+
*
21+
* The graph must be an unrooted labeled tree (connected, undirected, n-1 edges).
22+
*/
23+
@CommandAttitude(name = "prufer_sequence", abbreviation = "_ps")
24+
public class PruferSequence implements GraphReportExtension<String> {
25+
26+
public String calculate(GraphModel g) {
27+
int n = g.getVerticesCount();
28+
if (n < 2) {
29+
return "Graph must have at least 2 vertices";
30+
}
31+
if (g.getEdgesCount() != n - 1) {
32+
return "Graph is not a tree (edge count must equal n-1)";
33+
}
34+
35+
// degree[i] mirrors the current degree of vertex with id=i
36+
int[] degree = new int[n];
37+
Vertex[] vertices = g.getVertexArray();
38+
for (Vertex v : vertices) {
39+
degree[v.getId()] = g.getDegree(v);
40+
}
41+
42+
int[] sequence = new int[n - 2];
43+
boolean[] removed = new boolean[n];
44+
45+
for (int step = 0; step < n - 2; step++) {
46+
// find the leaf with the smallest id
47+
int leaf = -1;
48+
for (int i = 0; i < n; i++) {
49+
if (!removed[i] && degree[i] == 1) {
50+
leaf = i;
51+
break;
52+
}
53+
}
54+
if (leaf == -1) {
55+
return "Graph is not a tree (cycle detected)";
56+
}
57+
58+
// find the unique neighbor of this leaf
59+
Vertex leafVertex = g.getVertex(leaf);
60+
int neighbor = -1;
61+
for (Vertex nb : g.getNeighbors(leafVertex)) {
62+
if (!removed[nb.getId()]) {
63+
neighbor = nb.getId();
64+
break;
65+
}
66+
}
67+
if (neighbor == -1) {
68+
return "Graph is not a tree (disconnected)";
69+
}
70+
71+
sequence[step] = neighbor;
72+
removed[leaf] = true;
73+
degree[leaf] = 0;
74+
degree[neighbor]--;
75+
}
76+
77+
// format as comma-separated list of 1-based labels for readability
78+
StringBuilder sb = new StringBuilder();
79+
for (int i = 0; i < sequence.length; i++) {
80+
sb.append(sequence[i]);
81+
if (i < sequence.length - 1) {
82+
sb.append(", ");
83+
}
84+
}
85+
return sb.toString();
86+
}
87+
88+
public String getName() {
89+
return "Prufer Sequence";
90+
}
91+
92+
public String getDescription() {
93+
return "Prufer sequence of a labeled tree";
94+
}
95+
96+
@Override
97+
public String getCategory() {
98+
return "General";
99+
}
100+
}

0 commit comments

Comments
 (0)