Supposons que vous ayez un arbre binaire complet (c'est-à-dire que chaque nœud interne a exactement deux descendants non vides). Chaque nœud contient un entier différent de zéro. Vous êtes chargé d'encoder et de décoder l'arbre dans / à partir d'une liste d'entiers.
L'arbre est stocké en interne quelque chose comme:
struct node {
int data;
struct node *left, *right;
};
Et vous devez implémenter deux fonctions:
int *encode(struct node *root);
struct node *decode(int *array);
C'est à vous de décider comment encoder et décoder.
Points pour:
- longueur d'encodage minimale
- complexité (idéalement linéaire en nombre de nœuds)
- originalité
Aucun point pour la longueur du code source et vous n'êtes pas limité à C.
Exemple d'arbre:
5
/ \
3 2
/ \
2 1
/ \
9 9
code-challenge
tree-traversal
Alexandru
la source
la source
int *
est une boîte noire pour l'utilisateur.Réponses:
~ 1,03 N
Il semble que toutes les réponses jusqu'à présent prennent au moins 2 * N * 32 bits pour être stockées. (À l'exception des solutions dans les langues qui autorisent des valeurs entières supérieures à 32 bits, comme les solutions Haskell et Ruby - mais celles-ci vont encore prendre des octets supplémentaires à coder chaque fois que les données sont supérieures à 16 Ko.)
Voici une solution qui ne prend que N + plafond (N / 32) +1 pouce de stockage. Cela se rapproche de 1,03125 N pour le grand N et est inférieur à 1,1 N pour tout N supérieur à 20.
L'idée est de stocker un bit supplémentaire pour chaque nœud où 1 est "hasChildren". Ces bits sont regroupés en N / 32 mots à l'avance.
(terminer la mise en œuvre ici)
la source
Ce programme Haskell code un arbre de n nœuds en n entiers. L'astuce est qu'il code les données du nœud doublé, puis utilise le bit de poids faible pour indiquer s'il s'agit d'un nœud feuille ou d'un nœud intérieur.
Techniquement, la
Parser
monade ici est trop destructrice, car il n'y a qu'un seul analyseur créé,decoder
et j'aurais pu mettre la logique de chaînage de l'analyseur directement là. Mais de cette façon, le décodeur est très clair, etParser
malgré sa petite taille, est un cadre d'analyse simple et raisonnable.L'exécution de ceci vous obtient:
la source
En C
L'encode:
Le décodage:
Principale:
Remarque. Chaque nœud est codé en deux entiers (plus un entier pour le nombre de nœuds).
L'arbre fourni code donc comme ceci:
la source
En Ruby, avec le même encodage que @MtnViewMark :
Le coût est d'un entier par nœud (
data << 1 | has_childs
):la source
Étant donné un arbre binaire avec des
n
nœuds, cela l'encode dans une liste d'2n + 1
entiers. Les algorithmes de codage et de décodage sont tous deuxO(n)
complexes.J'utilise l'entier 0 comme marqueur sentinelle lors de l'encodage, indiquant quand je déplie la récursivité. Ensuite, lorsque je décode, je place les nœuds d'arbre que je crée sur une pile (en quelque sorte) et j'utilise les 0 de la liste pour garder une trace de l'endroit où ajouter le nœud suivant. Je n'ai pas essayé, mais je suis sûr que le décodage se briserait si l'arbre n'était pas complet.
Enregistré comme
encode.c
puis compilé et exécuté. Ce programme utilise l'exemple d'arbre que vous avez fourni et je l'ai testé avec succès sur quelques autres.la source
Mon code encode l'arbre dans une traversée en précommande, chaque feuille en deux entiers (ses données suivies de 0) et chaque nœud interne en un int (ses données suivies de son enfant gauche, puis sa droite). Pour un arbre binaire complet (tel que vous le définissez) avec n nœuds, n doit être impair, et il y a (n + 1) / 2 feuilles et (n-1) / 2 nœuds internes, donc c'est 3n / 2 + 1 / 2 entiers pour l'encodage.
avertissement: non testé, il suffit de le saisir.
la source
Voici mon essai. Il stocke l'arbre dans un tableau de taille 2 ** profondeur + 1. Il utilise
a[0]
pour maintenir la taille eta[size]
pour maintenir l'index du premier "nœud vide" qu'il rencontre dans une traversée en profondeur d'abord. (Un nœud vide est l'endroit où un enfant serait stocké si le parent en avait un). Chaque nœud vide contient l'index du prochain nœud vide qui sera rencontré.Ce schéma évite de réserver des bits pour marquer les enfants de présence, de sorte que chaque nœud peut utiliser la plage entière entière. Il permet également des arbres déséquilibrés - un parent ne peut avoir qu'un seul enfant.
production:
L'encodeur:
Le décodeur:
(merci @daniel sobral pour avoir corrigé la mise en forme)
la source
Scala:
Il s'agit d'une approche qui utilise la syntaxe obsolète, mais se compile sans erreur dans Scala 2.9.1. Il génère un arbre et décode chaque arbre encodé dans le même tableau que celui utilisé pour l'encodage. Peut-être que je me débarrasse en quelque sorte des avertissements obsolètes aujourd'hui.Wow - c'était simple. La première idée a fonctionné immédiatement.
la source