Aller au contenu
  1. Algorithmes & Structures de données/
#89 Trees Difficile 2 min de lecture

Serialize and Deserialize Binary Tree

Conçois serialize(root) qui transforme un arbre binaire en chaîne, et deserialize(data) qui reconstruit l’arbre EXACT depuis cette chaîne. Le format est libre : seul l’aller-retour compte.

🐻 Vocabulaire pas clair ? Consultez le glossaire algo.

C’est quoi le problème, en clair ? #

Un arbre binaire (une structure où chaque case, ou « nœud », a au plus deux cases enfants) vit en mémoire avec plein de flèches entre les cases : impossible de l’envoyer tel quel dans un fichier ou sur le réseau. Il faut donc l’« aplatir » en une simple chaîne de texte, un peu comme une notice de montage, puis être capable de reconstruire EXACTEMENT le même arbre à partir de ce texte, y compris ses branches vides. C’est comme démonter un meuble, écrire la notice, puis vérifier qu’un inconnu peut le remonter à l’identique juste en la suivant.

L’idée clé #

Un preorder AVEC marqueurs de null (« # ») capture toute la structure sans ambiguïté — c’est ce qui manquait au preorder seul du Construct Binary Tree from Preorder and Inorder. La désérialisation rejoue le même preorder : lire un jeton, créer le nœud, construire récursivement gauche puis droite ; « # » = sous-arbre vide.

Pourquoi cette solution ? #

StringBuilder pour la sérialisation (concaténation O(N), pas O(N²)), split(",") + un index partagé (ou une ArrayDeque de jetons) pour la lecture séquentielle. La SYMÉTRIE parfaite entre les deux fonctions — même parcours, un en écriture, un en lecture — est ce qui rend la solution belle et robuste.

Solution Java #

public class Codec {
    private static final String NULL = "#";
    private static final String SEP = ",";

    // Serialisation : preorder avec marqueurs de null
    public String serialize(TreeNode root) {
        StringBuilder sb = new StringBuilder();
        buildString(root, sb);
        return sb.toString();
    }

    private void buildString(TreeNode node, StringBuilder sb) {
        if (node == null) {
            sb.append(NULL).append(SEP);
            return;
        }
        sb.append(node.val).append(SEP);
        buildString(node.left, sb);
        buildString(node.right, sb);
    }

    // Deserialisation : rejouer le meme preorder en lecture
    public TreeNode deserialize(String data) {
        Deque<String> tokens = new ArrayDeque<>(Arrays.asList(data.split(SEP)));
        return buildTree(tokens);
    }

    private TreeNode buildTree(Deque<String> tokens) {
        String token = tokens.poll();
        if (NULL.equals(token)) return null; // sous-arbre vide

        TreeNode node = new TreeNode(Integer.parseInt(token));
        node.left = buildTree(tokens);   // meme ordre qu'a l'ecriture
        node.right = buildTree(tokens);
        return node;
    }
}

Complexité #

Temps O(N) dans les deux sens : chaque nœud écrit/lu une fois. Espace O(N) : la chaîne + la récursion.