Skip to content

Commit 67e9b13

Browse files
authored
Update DSU to use both path compression and union by size (rust-lang#278)
1 parent ce9fc3c commit 67e9b13

File tree

1 file changed

+36
-17
lines changed

1 file changed

+36
-17
lines changed

src/graph/minimum_spanning_tree.rs

Lines changed: 36 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,12 @@ pub struct Edge {
77
cost: i64,
88
}
99

10+
#[derive(Debug)]
11+
struct DSUNode {
12+
parent: i64,
13+
subtree_size: i64,
14+
}
15+
1016
impl PartialEq for Edge {
1117
fn eq(&self, other: &Self) -> bool {
1218
self.source == other.source
@@ -27,34 +33,47 @@ impl Edge {
2733
}
2834
}
2935

30-
fn make_sets(number_of_vertices: i64) -> Vec<i64> {
31-
let mut parent: Vec<i64> = Vec::with_capacity(number_of_vertices as usize);
36+
fn make_sets(number_of_vertices: i64) -> Vec<DSUNode> {
37+
let mut dsu_nodes: Vec<DSUNode> = Vec::with_capacity(number_of_vertices as usize);
3238
for i in 0..number_of_vertices {
33-
parent.push(i);
39+
dsu_nodes.push(DSUNode {
40+
parent: i,
41+
subtree_size: 1,
42+
});
3443
}
35-
parent
44+
dsu_nodes
3645
}
3746

38-
fn find(parent: &mut Vec<i64>, x: i64) -> i64 {
47+
fn find(dsu_nodes: &mut Vec<DSUNode>, x: i64) -> i64 {
3948
let idx: usize = x as usize;
40-
if parent[idx] != x {
41-
parent[idx] = find(parent, parent[idx]);
49+
if dsu_nodes[idx].parent != x {
50+
dsu_nodes[idx].parent = find(dsu_nodes, dsu_nodes[idx].parent);
51+
// subtree_size of this vertex might become invalid, but only size of
52+
// roots are important and used, so it doesn't matter
4253
}
43-
parent[idx]
54+
dsu_nodes[idx].parent
4455
}
4556

46-
fn merge(parent: &mut Vec<i64>, x: i64, y: i64) {
47-
let idx_x: usize = find(parent, x) as usize;
48-
let parent_y: i64 = find(parent, y);
49-
parent[idx_x] = parent_y;
57+
fn merge(dsu_nodes: &mut Vec<DSUNode>, x: i64, y: i64) {
58+
let mut idx_x: usize = find(dsu_nodes, x) as usize;
59+
let mut idx_y: usize = find(dsu_nodes, y) as usize;
60+
61+
// We should make the smaller root a child of the other
62+
// We assume idx_x is the bigger one, and swap it if it is not
63+
if dsu_nodes[idx_y].subtree_size > dsu_nodes[idx_x].subtree_size {
64+
std::mem::swap(&mut idx_y, &mut idx_x);
65+
}
66+
67+
dsu_nodes[idx_y].parent = idx_x as i64;
68+
dsu_nodes[idx_x].subtree_size += dsu_nodes[idx_y].subtree_size;
5069
}
5170

52-
fn is_same_set(parent: &mut Vec<i64>, x: i64, y: i64) -> bool {
53-
find(parent, x) == find(parent, y)
71+
fn is_same_set(dsu_nodes: &mut Vec<DSUNode>, x: i64, y: i64) -> bool {
72+
find(dsu_nodes, x) == find(dsu_nodes, y)
5473
}
5574

5675
pub fn kruskal(mut edges: Vec<Edge>, number_of_vertices: i64) -> (i64, Vec<Edge>) {
57-
let mut parent: Vec<i64> = make_sets(number_of_vertices);
76+
let mut dsu_nodes: Vec<DSUNode> = make_sets(number_of_vertices);
5877

5978
edges.sort_unstable_by(|a, b| a.cost.cmp(&b.cost));
6079
let mut total_cost: i64 = 0;
@@ -67,8 +86,8 @@ pub fn kruskal(mut edges: Vec<Edge>, number_of_vertices: i64) -> (i64, Vec<Edge>
6786

6887
let source: i64 = edge.source;
6988
let destination: i64 = edge.destination;
70-
if !is_same_set(&mut parent, source, destination) {
71-
merge(&mut parent, source, destination);
89+
if !is_same_set(&mut dsu_nodes, source, destination) {
90+
merge(&mut dsu_nodes, source, destination);
7291
merge_count += 1;
7392
let cost: i64 = edge.cost;
7493
total_cost += cost;

0 commit comments

Comments
 (0)