# Given a Tree generate its Prüfer Code

In a Prüfer code is a unique sequence of integers that denotes a specific tree.

You can find the Prüfer code of a tree with the following algorithm taken from Wikipedia:

Consider a labeled tree T with vertices {1, 2, ..., n}. At step i, remove the leaf with the smallest label and set the ith element of the Prüfer sequence to be the label of this leaf's neighbor.

(Note that since it's a leaf it will only have one neighbor).

You should stop the iteration when only two vertices remain in the graph.

Given a labeled tree as input output its Prüfer code. You may take input in any reasonable manner. Such as an adjacency matrix or your languages builtin graph representation. (You may not take input as a Prüfer code).

This is so you should aim to minimize the bytes in your source.

# Test cases

Here are some inputs in ASCII with their outputs below. You do not need to support ASCII input like this.

    3
|
1---2---4---6
|
5

{2,2,2,4}


1---4---3
|
5---2---6---7
|
8

{4,4,2,6,2,5}


5---1---4   6
|       |
2---7---3

{1,1,2,7,3}

• Can we take in a rooted tree as input?
– xnor
May 11, 2017 at 23:51
• Can we take input as something like [[2,1],[2,3],[2,5],[2,4,6]] for the first case? (i.e. each branch) May 11, 2017 at 23:52
• @xnor Yes you can May 11, 2017 at 23:58
• I feel like taking an input with edges or paths directed towards a root is precomputation towards the Prüfer Code. Either way, I think you should be clearer on "You may take input in any reasonable manner (You may not take input as a Prüfer code)."
– xnor
May 12, 2017 at 0:24
• @xnor Oh I didn't understand what Hyper Neutrino was asking. May 12, 2017 at 0:29

# Mathematica, 34 bytes

<<Combinatorica
LabeledTreeToCode


After loading the Combinatorica package, the function LabeledTreeToCode expects a tree input as an undirected graph with explicitly listed edges and vertices; for example, the input in the second test case could be Graph[{{{1, 4}}, {{4, 3}}, {{4, 2}}, {{2, 5}}, {{2, 6}}, {{6, 7}}, {{5, 8}}}, {1, 2, 3, 4, 5, 6, 7, 8}].

• Of course there's a built-in to do this. >_> May 12, 2017 at 1:34

# Python 3, 136131 127 bytes

def f(t):
while len(t)>2:
m=min(x for x in t if len(t[x])<2);yield t[m];del t[m]
for x in t:m in t[x]and t[x].remove(m)


Takes input as an adjacency matrix. First example:

>>> [*f({1:,2:[1,3,4,5],3:,4:[2,6],5:,6:})]
[2, 2, 2, 4]

• well I failed... May 12, 2017 at 0:16
• @HyperNeutrino You were about 4 seconds faster! May 12, 2017 at 0:17
• Hehe yup! And about 2.7 times as long! :D gg May 12, 2017 at 0:17
• del exists? >_> May 12, 2017 at 0:19
• @WheatWizard You're right about the semicolons, but mixing tabs and spaces is an error in Python 3. May 12, 2017 at 8:29

# Jelly, 31 bytes

FĠLÞḢḢ
0ịµÇHĊṙ@µÇCịṪ,
WÇÐĿḢ€ṖṖḊ


A monadic link which takes a list of pairs of nodes (defining the edges) in any order (and each in any orientation) and returns the Prüfer Code as a list.

Try it online!

### How?

FĠLÞḢḢ - Link 1, find leaf location: list of edges (node pairs)
F      - flatten
Ġ     - group indices by value (sorted smallest to largest by value)
LÞ   - sort by length (stable sort, so equal lengths remain in prior order)
ḢḢ - head head (get the first of the first group. If there are leaves this yields
-   the index of the smallest leaf in the flattened version of the list of edges)

0ịµÇHĊṙ@µÇCịṪ, - Link 2, separate smallest leaf: list with last item a list of edges
0ị             - item at index zero - the list of edges
µ            - monadic chain separation (call that g)
Ç           - call last link (1) as a monad (index of smallest leaf if flattened)
H          - halve
Ċ         - ceiling (round up)
ṙ@       - rotate g left by that amount (places the edge to remove at the right)
µ      - monadic chain separation (call that h)
C    - complement (1-x)
Ṫ  - tail h (removes and yields the edge)
ị   - index into, 1-based and modular (gets the other node of the edge)
, - pair with the modified h
-    (i.e. [otherNode, restOfTree], ready for the next iteration)

WÇÐĿḢ€ṖṖḊ - Main link: list of edges (node pairs)
W         - wrap in a list (this is so the first iteration works)
ÐĿ      - loop and collect intermediate results until no more change:
Ḣ€    - head €ach (get the otherNodes, although the original tree is also collected)
ṖṖ  - discard the two last results (they are excess to requirements)
Ḋ - discard the first result (the tree, leaving just the Prüfer Code)


# 05AB1E, 29 bytes

[Dg#ÐD˜{γé¬U\X.å©ÏXKˆ®_Ï]¯


Try it online!

Explanation

[Dg#                           # loop until only 1 link (2 vertices) remain
˜{                       # flatten and sort values
γé                     # group by value and order by length of runs
¬U                  # store the smallest leaf in X
\X                # discard the sorted list and push X
Ï           # keep only that link
XKˆ       # add the value that isn't X to the global list
]   # end loop
¯  # output global list


## Clojure, 111 bytes

#(loop[r[]G %](if-let[i(first(sort(remove(set(vals G))(keys G))))](recur(conj r(G i))(dissoc G i))(butlast r)))


Requires the input to be a hash-map, having "leaf-like" labels as keys and "root-like" labels as values. For example:

{1 2, 3 2, 5 2, 4 2, 6 4}
{1 4, 3 4, 4 2, 8 5, 5 2, 7 6, 6 2}


On each iteration it finds the smallest key which is not referenced by any other node, adds it to the result r and removes the node from the graph definition G. if-let goes to else case when G is empty, as first returns nil. Also the last element has to be dropped.

# Python 2, 91 bytes

d=input()
while len(d)>2:m=min(d,key=lambda k:len(d[k]));n,=d[m];del d[m];d[n]-={m};print n
`

Try it online!

Based on L3viathan's solution. Takes a dictionary of sets representing adjacency lists.