Angenommen, Sie haben einen vollständigen Binärbaum (dh jeder interne Knoten hat genau zwei nicht leere Nachkommen). Jeder Knoten enthält eine Ganzzahl ungleich Null. Sie haben die Aufgabe, den Baum in / aus einer Liste von ganzen Zahlen zu codieren und zu decodieren.
Der Baum wird intern in etwa wie folgt gespeichert:
struct node {
int data;
struct node *left, *right;
};
Und Sie müssen zwei Funktionen implementieren:
int *encode(struct node *root);
struct node *decode(int *array);
Es liegt an Ihnen, wie Sie codieren und decodieren.
Punkte für:
- minimale Kodierungslänge
- Komplexität (idealerweise linear in der Anzahl der Knoten)
- Originalität
Keine Punkte für die Quellcodelänge und Sie sind nicht auf C beschränkt.
Baum Beispiel:
5
/ \
3 2
/ \
2 1
/ \
9 9
code-challenge
tree-traversal
Alexandru
quelle
quelle
int *
ist eine Blackbox für Benutzer.Antworten:
~ 1,03 N
Es scheint, dass alle bisherigen Antworten mindestens 2 * N * 32-Bit benötigen, um gespeichert zu werden. (Mit Ausnahme der Lösungen in Sprachen, die ganzzahlige Werte von mehr als 32 Bit zulassen, wie die Lösungen von Haskell und Ruby, für deren Codierung jedoch immer noch zusätzliche Bytes erforderlich sind, wenn die Daten größer als 16 KB sind.)
Hier ist eine Lösung, die nur N + Obergrenze (N / 32) + 1 Zoll Speicher benötigt. Dies nähert sich 1,03125 N für großes N und liegt unter 1,1 N für alle N, die größer als 20 sind.
Die Idee ist, ein zusätzliches Bit für jeden Knoten zu speichern, bei dem 1 "hasChildren" ist. Diese Bits werden vorab in N / 32 Wörter gepackt.
(Umsetzung hier abschließen)
quelle
Dieses Haskell-Programm codiert einen Baum von n Knoten in n ganzen Zahlen. Der Trick besteht darin, dass er die Daten des Knotens doppelt codiert und dann mit dem niederwertigen Bit angibt, ob es sich um einen Blattknoten oder einen inneren Knoten handelt.
Technisch gesehen ist die
Parser
Monade hier Over-Kill, da nur ein Parser erstellt wurde,decoder
und ich hätte die Parser-Verkettungslogik direkt dort platzieren können. Aber auf diese Weise ist der Decoder sehr klar undParser
trotz seiner geringen Größe ein vernünftiges einfaches Parsing-Framework.Wenn Sie dies ausführen, erhalten Sie:
quelle
In C
Die Kodierung:
Die Entschlüsselung:
Main:
Hinweis. Jeder Knoten ist als zwei Ganzzahlen (plus ein Ganzzahl für die Anzahl der Knoten) codiert.
Der mitgelieferte Baum kodiert also wie folgt:
quelle
In Ruby mit derselben Codierung wie @MtnViewMark :
Die Kosten betragen eine Ganzzahl pro Knoten (
data << 1 | has_childs
):quelle
Bei einem Binärbaum mit
n
Knoten wird dieser in eine Liste von2n + 1
Ganzzahlen codiert . Sowohl die Codierungs- als auch die Decodierungsalgorithmen habenO(n)
komplex.Ich verwende die Ganzzahl 0 als Sentinel-Markierung beim Codieren und gebe an, wann ich die Rekursion entfalte. Wenn ich dann dekodiere, lege ich die Baumknoten, die ich erstelle, auf einen Stapel (in gewisser Weise) und verwende die Nullen in der Liste, um zu verfolgen, wo der nächste Knoten hinzugefügt werden soll. Ich habe es nicht versucht, aber ich bin mir ziemlich sicher, dass die Dekodierung brechen würde, wenn der Baum nicht vollständig wäre.
Gespeichert als
encode.c
dann kompiliert und ausgeführt. Dieses Programm verwendet den von Ihnen bereitgestellten Beispielbaum und ich habe ihn an einigen anderen erfolgreich getestet.quelle
Mein Code codiert den Baum in einer Vorbestellungsüberquerung, wobei jedes Blatt in zwei Zoll (seine Daten, gefolgt von 0) und jeder interne Knoten in einem int (seine Daten, gefolgt von seinem linken Kind, dann seinem rechten) codiert wird. Für einen vollständigen Binärbaum (wie Sie ihn definieren) mit n Knoten muss n ungerade sein und es gibt (n + 1) / 2 Blätter und (n-1) / 2 interne Knoten, das sind also 3n / 2 + 1 / 2 ganze Zahlen für die Kodierung.
Warnung: ungetestet, einfach eingetippt.
quelle
Hier ist mein Versuch. Der Baum wird in einem Array der Größe 2 ** Tiefe + 1 gespeichert. Es wird verwendet
a[0]
, um die Größe und zu haltena[size]
den Index des ersten "leeren Knotens" zu speichern, auf den es bei einer Tiefendurchquerung stößt. (Ein leerer Knoten ist der Ort, an dem ein Kind gespeichert würde, wenn das Elternteil eines hätte). Jeder leere Knoten enthält den Index des nächsten leeren Knotens, der angetroffen wird.Bei diesem Schema wird vermieden, dass Bits reserviert werden, um die vorhandenen untergeordneten Elemente zu markieren, sodass jeder Knoten den gesamten ganzzahligen Bereich verwenden kann. Es erlaubt auch unausgeglichene Bäume - ein Elternteil kann nur ein Kind haben.
Ausgabe:
Der Encoder:
Der Decoder:
(danke @daniel sobral für die Korrektur der Formatierung)
quelle
Scala:
Dies ist ein Ansatz, der veraltete Syntax verwendet, in Scala 2.9.1 jedoch fehlerfrei kompiliert wird. Es generiert einen Baum und decodiert jeden codierten Baum in dasselbe Array, das für die Codierung verwendet wird. Vielleicht werde ich die veralteten Warnungen heute irgendwie los.Wow - das war einfach. Erste Idee hat sofort funktioniert.
quelle