Skip to content

Commit b65e96c

Browse files
committed
Add Prüfer sequence decoding for labeled trees
1 parent 7f81fcd commit b65e96c

1 file changed

Lines changed: 65 additions & 0 deletions

File tree

‎graphs/prufer_decode.py‎

Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,65 @@
1+
"""Decode a Prüfer sequence into the edges of a labeled tree.
2+
3+
https://en.wikipedia.org/wiki/Pr%C3%BCfer_sequence
4+
"""
5+
6+
from heapq import heapify, heappop, heappush
7+
8+
9+
def prufer_decode(code: list[int]) -> list[tuple[int, int]]:
10+
"""Return the tree encoded by ``code`` using vertices 1 through n.
11+
12+
A code of length n - 2 represents one tree on n labeled vertices. At each
13+
step, the smallest leaf is joined to the next vertex in the code.
14+
The returned edges are undirected and ordered by the decoding steps.
15+
This takes O(n log n) time and O(n) space.
16+
17+
>>> prufer_decode([])
18+
[(1, 2)]
19+
>>> prufer_decode([4, 4, 4, 5])
20+
[(1, 4), (2, 4), (3, 4), (4, 5), (5, 6)]
21+
>>> prufer_decode([1])
22+
[(2, 1), (1, 3)]
23+
>>> prufer_decode([0])
24+
Traceback (most recent call last):
25+
...
26+
ValueError: code vertices must be integers from 1 through n
27+
>>> prufer_decode([True])
28+
Traceback (most recent call last):
29+
...
30+
ValueError: code vertices must be integers from 1 through n
31+
>>> prufer_decode("1")
32+
Traceback (most recent call last):
33+
...
34+
TypeError: code must be a list of integers
35+
"""
36+
if not isinstance(code, list):
37+
raise TypeError("code must be a list of integers")
38+
39+
vertex_count = len(code) + 2
40+
if any(
41+
not isinstance(vertex, int)
42+
or isinstance(vertex, bool)
43+
or not 1 <= vertex <= vertex_count
44+
for vertex in code
45+
):
46+
raise ValueError("code vertices must be integers from 1 through n")
47+
48+
degree = [1] * (vertex_count + 1)
49+
for vertex in code:
50+
degree[vertex] += 1
51+
52+
leaves = [vertex for vertex in range(1, vertex_count + 1) if degree[vertex] == 1]
53+
heapify(leaves)
54+
edges: list[tuple[int, int]] = []
55+
56+
for vertex in code:
57+
leaf = heappop(leaves)
58+
edges.append((leaf, vertex))
59+
degree[leaf] = 0
60+
degree[vertex] -= 1
61+
if degree[vertex] == 1:
62+
heappush(leaves, vertex)
63+
64+
edges.append((heappop(leaves), heappop(leaves)))
65+
return edges

0 commit comments

Comments
 (0)