Skip to content

Commit 64e1754

Browse files
committed
slides
1 parent 14fb535 commit 64e1754

File tree

3 files changed

+94
-51
lines changed

3 files changed

+94
-51
lines changed

com/williamfiset/algorithms/graphtheory/treealgorithms/TreeIsomorphism.java

Lines changed: 54 additions & 51 deletions
Original file line numberDiff line numberDiff line change
@@ -38,8 +38,8 @@ public int id() {
3838
return id;
3939
}
4040

41-
public boolean isLeaf() {
42-
return children.size() == 0;
41+
public TreeNode parent() {
42+
return parent;
4343
}
4444

4545
public List<TreeNode> children() {
@@ -52,23 +52,48 @@ public String toString() {
5252
}
5353
}
5454

55-
private static TreeNode rootTree(List<List<Integer>> graph, int rootId) {
56-
TreeNode root = new TreeNode(rootId);
57-
return buildTree(graph, root, /*parent=*/ null);
58-
}
55+
// Determines if two unrooted trees are isomorphic
56+
public static boolean treesAreIsomorphic(List<List<Integer>> tree1, List<List<Integer>> tree2) {
57+
if (tree1.isEmpty() || tree2.isEmpty()) {
58+
throw new IllegalArgumentException("Empty tree input");
59+
}
5960

60-
// Do dfs to construct rooted tree.
61-
private static TreeNode buildTree(List<List<Integer>> graph, TreeNode node, TreeNode parent) {
62-
for (int childId : graph.get(node.id)) {
63-
// Ignore adding an edge pointing back to parent.
64-
if (parent != null && childId == parent.id) continue;
61+
List<Integer> centers1 = findTreeCenters(tree1);
62+
List<Integer> centers2 = findTreeCenters(tree2);
6563

66-
TreeNode child = new TreeNode(childId, node);
67-
node.addChildren(child);
64+
TreeNode rootedTree1 = rootTree(tree1, centers1.get(0));
65+
String tree1Encoding = encode(rootedTree1);
6866

69-
buildTree(graph, child, node);
67+
for (int center : centers2) {
68+
TreeNode rootedTree2 = rootTree(tree2, center);
69+
String tree2Encoding = encode(rootedTree2);
70+
71+
if (tree1Encoding.equals(tree2Encoding)) {
72+
return true;
73+
}
7074
}
71-
return node;
75+
return false;
76+
}
77+
78+
private static boolean areIsomorphic(TreeNode root1, TreeNode root2) {
79+
return encode(root1).equals(encode(root2));
80+
}
81+
82+
// Constructs the canonical form representation of a tree as a string.
83+
public static String encode(TreeNode node) {
84+
if (node == null) {
85+
return "";
86+
}
87+
List<String> labels = new LinkedList<>();
88+
for (TreeNode child : node.children()) {
89+
labels.add(encode(child));
90+
}
91+
Collections.sort(labels);
92+
StringBuilder sb = new StringBuilder();
93+
for (String label : labels) {
94+
sb.append(label);
95+
}
96+
return "(" + sb.toString() + ")";
7297
}
7398

7499
private static List<Integer> findTreeCenters(List<List<Integer>> tree) {
@@ -85,9 +110,7 @@ private static List<Integer> findTreeCenters(List<List<Integer>> tree) {
85110

86111
int processedLeafs = leaves.size();
87112

88-
// Remove leaf nodes and decrease the degree of
89-
// each node adding new leaf nodes progressively
90-
// until only the centers remain.
113+
// Iteratively remove all leaf nodes layer by layer until only the centers remain.
91114
while (processedLeafs < n) {
92115
List<Integer> newLeaves = new ArrayList<>();
93116
for (int node : leaves) {
@@ -104,43 +127,23 @@ private static List<Integer> findTreeCenters(List<List<Integer>> tree) {
104127
return leaves;
105128
}
106129

107-
// Determines if two unrooted trees are isomorphic
108-
public static boolean treesAreIsomorphic(List<List<Integer>> tree1, List<List<Integer>> tree2) {
109-
if (tree1.isEmpty() || tree2.isEmpty()) {
110-
throw new IllegalArgumentException("Empty tree input");
111-
}
112-
113-
List<Integer> centers1 = findTreeCenters(tree1);
114-
List<Integer> centers2 = findTreeCenters(tree2);
115-
116-
TreeNode rootedTree1 = rootTree(tree1, centers1.get(0));
117-
for (int center : centers2) {
118-
if (areIsomorphic(rootedTree1, rootTree(tree2, center))) {
119-
return true;
120-
}
121-
}
122-
return false;
130+
private static TreeNode rootTree(List<List<Integer>> graph, int rootId) {
131+
TreeNode root = new TreeNode(rootId);
132+
return buildTree(graph, root, /*parent=*/ null);
123133
}
124134

125-
private static boolean areIsomorphic(TreeNode root1, TreeNode root2) {
126-
return encode(root1).equals(encode(root2));
127-
}
135+
// Do dfs to construct rooted tree.
136+
private static TreeNode buildTree(List<List<Integer>> graph, TreeNode node, TreeNode parent) {
137+
for (int childId : graph.get(node.id)) {
138+
// Ignore adding an edge pointing back to parent.
139+
if (parent != null && childId == parent.id) continue;
128140

129-
// Constructs the canonical form representation of a tree as a string.
130-
public static String encode(TreeNode node) {
131-
if (node == null) {
132-
return "";
133-
}
134-
List<String> labels = new LinkedList<>();
135-
for (TreeNode child : node.children()) {
136-
labels.add(encode(child));
137-
}
138-
Collections.sort(labels);
139-
StringBuilder sb = new StringBuilder();
140-
for (String label : labels) {
141-
sb.append(label);
141+
TreeNode child = new TreeNode(childId, node);
142+
node.addChildren(child);
143+
144+
buildTree(graph, child, node);
142145
}
143-
return "(" + sb.toString() + ")";
146+
return node;
144147
}
145148

146149
/* Graph/Tree creation helper methods. */

slides/graphtheory/trees.txt

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -756,15 +756,55 @@ and subscribe for more mathematics and computer science videos.
756756

757757
Isomorphism source code
758758

759+
Hello and welcome, my name is William, today we're going to take a
760+
look at some source code for identifying isomorphic trees.
759761

762+
In the previous video, we talked about identifying isomorphic trees by first
763+
serializing the tree into a string and then using that as a means for equality.
764+
Today we will be looking at the same approach in more details, so make sure
765+
you've given the previous video a watch if you haven't done so. There should be
766+
a link in the description below.
760767

768+
All the source code you see today can be found on Github at github dot com slash
769+
william fiset slash algorithms. Alright, let's jump in.
761770

771+
Alright, here we are in the source code for identifying isomorphic trees written
772+
in Java.
762773

774+
The first thing I do is define a TreeNode object we'll be using to represent our
775+
rooted trees. TreeNode's are straightforward, they only contain three members,
776+
a unique id, a parent node reference and a list of references to all its children.
763777

778+
To create a TreeNode, all you need is to give that TreeNode a unique id, you can
779+
also optionally create a TreeNode with an id and a parent node.
764780

781+
The one useful method I've added to this class is the ability to add children
782+
to this TreeNode. Simply pass in any number of TreeNodes you wish to add as child
783+
node to this node and they'll get added to the children's list.
765784

785+
The rest of the methods in this class are just getter methods.
766786

787+
The next interesting method is the treesAreIsomorphic method which takes as
788+
input two undirected tree stored as adjacency lists tree1 and tree2.
767789

790+
Just so that we don't have to worry about it, I check if either trees are empty
791+
and throw an exception.
792+
793+
After that, I find the center or centers of both trees.
794+
795+
TODO(waf): descripbe the whole flow here before moving on,
796+
797+
798+
Then I root tree1 using its first center node.
799+
Afterwhich I loop through bot of tree2's centers and do the isomorphism check.
800+
You need to
801+
802+
Now the next thing we want to do is encode the
803+
second tree and compare the encoded results, but if the tree has 2 centers we
804+
don't know which center node in the second tree is the correct one, so we need
805+
to try both. For this, iterate over both centers and root the tree comparing the
806+
encoded result with the one from the first tree. If there's any match then we
807+
know the trees are isomorphic.
768808

769809

770810

slides/graphtheory/trees_slides.key

66.5 KB
Binary file not shown.

0 commit comments

Comments
 (0)