{
  "chapter": {
    "id": "arbres-binaires-de-recherche",
    "level": "terminale",
    "theme": "Structures de données",
    "title": "Arbres binaires de recherche",
    "description": "Propriété d'ordre dans un arbre binaire de\nrecherche, opérations de recherche, d'insertion et\nde suppression, complexité dans le meilleur et\ndans le pire cas, équilibrage, applications aux\nensembles ordonnés dynamiques et aux dictionnaires\ntriés.",
    "parties": [
      {
        "id": "definition",
        "title": "Définition et propriété"
      },
      {
        "id": "operations",
        "title": "Recherche et insertion"
      },
      {
        "id": "complexite",
        "title": "Équilibre et complexité"
      }
    ],
    "prerequisites": [],
    "references": []
  },
  "questions": [
    {
      "id": "q01",
      "difficulty": 1,
      "skills": [
        "definition"
      ],
      "title": "Propriété fondamentale",
      "partie": "definition",
      "statement": "Quelle est la **propriété fondamentale** d'un\narbre binaire de recherche ?",
      "options": [
        {
          "text": "Toutes les feuilles se trouvent exactement au même niveau",
          "correct": false,
          "feedback": "Cette description correspond à un arbre\nparfait, et non à un arbre binaire de\nrecherche. Un arbre binaire de recherche\nse définit par une propriété d'ordre, pas\npar la position de ses feuilles.\n"
        },
        {
          "text": "Chaque nœud possède exactement deux enfants",
          "correct": false,
          "feedback": "Cette description correspond à un arbre\nplein, qui n'a aucun rapport direct avec\nl'ordre des valeurs.\n"
        },
        {
          "text": "Sous-arbre gauche inférieur, sous-arbre droit supérieur",
          "correct": true,
          "feedback": "C'est la propriété d'ordre qui rend la\nrecherche efficace en $O(\\log n)$ dans un\narbre équilibré. Cette propriété doit être\nvérifiée pour **chaque** nœud de l'arbre, et\nnon uniquement pour la racine.\n"
        },
        {
          "text": "La racine contient toujours la plus grande valeur de l'arbre",
          "correct": false,
          "feedback": "Dans un arbre binaire de recherche, la racine n'a aucune raison de porter la plus grande valeur : les valeurs plus grandes qu'elle se trouvent dans son sous-arbre droit, et la racine peut être n'importe quelle valeur.\n"
        }
      ],
      "explanation": "Les arbres binaires de recherche permettent de\nmaintenir un ensemble ordonné dynamique, en\noffrant des opérations de recherche,\nd'insertion et de suppression efficaces lorsque\nl'arbre reste équilibré."
    },
    {
      "id": "q02",
      "difficulty": 1,
      "skills": [
        "recherche",
        "complexite"
      ],
      "title": "Complexité de la recherche",
      "partie": "operations",
      "statement": "Dans un arbre binaire de recherche **équilibré**\ncontenant $n$ éléments, quelle est la complexité\nde la recherche d'une valeur ?",
      "options": [
        {
          "text": "$O(n^2)$",
          "correct": false,
          "feedback": "Aucune raison d'avoir une complexité\nquadratique pour une simple recherche dans\nun arbre.\n"
        },
        {
          "text": "$O(1)$",
          "correct": false,
          "feedback": "On ne peut pas accéder à un élément\nquelconque en temps constant dans un arbre\nbinaire de recherche. La complexité dépend\nau moins de la hauteur de l'arbre.\n"
        },
        {
          "text": "$O(n)$",
          "correct": false,
          "feedback": "Cette complexité correspond au pire cas\nd'un arbre dégénéré en peigne. Pour un\narbre équilibré, on fait nettement mieux.\n"
        },
        {
          "text": "$O(\\log n)$",
          "correct": true,
          "feedback": "À chaque comparaison, on élimine la moitié\ndes nœuds (on descend dans le sous-arbre\ngauche ou dans le sous-arbre droit). Le\nnombre d'étapes est donc proportionnel à\nla hauteur de l'arbre, qui vaut\n$O(\\log n)$ lorsque l'arbre est équilibré.\n"
        }
      ],
      "explanation": "Cette efficacité explique pourquoi les arbres\nbinaires de recherche sont utilisés pour\nimplémenter des ensembles et dictionnaires\ntriés. Cette complexité dépend néanmoins\ncrucialement du fait que l'arbre reste\néquilibré."
    },
    {
      "id": "q03",
      "difficulty": 1,
      "skills": [
        "degenerescence"
      ],
      "title": "Cas pire",
      "partie": "complexite",
      "statement": "Quelle est la complexité de la recherche dans\nun arbre binaire de recherche dans le **pire cas**, sans contrainte d'équilibrage ?",
      "options": [
        {
          "text": "$O(\\sqrt{n})$",
          "correct": false,
          "feedback": "Aucune raison particulière n'amène à une\ncomplexité de cette forme dans un arbre\nbinaire de recherche.\n"
        },
        {
          "text": "$O(\\log n)$ dans tous les cas",
          "correct": false,
          "feedback": "Sans équilibrage, l'arbre peut dégénérer.\nLa complexité $O(\\log n)$ n'est garantie\nque si l'arbre reste équilibré.\n"
        },
        {
          "text": "$O(n^2)$, soit quadratique",
          "correct": false,
          "feedback": "Même dans le pire cas, la recherche reste\nen $O(n)$. La hauteur de l'arbre, qui peut\natteindre $n$, est en cause, mais la\ncomplexité ne devient pas quadratique.\n"
        },
        {
          "text": "$O(n)$, arbre dégénéré en peigne",
          "correct": true,
          "feedback": "Si l'on insère par exemple les valeurs\n$1, 2, 3, \\ldots, n$ dans l'ordre, l'arbre\ndevient une liste chaînée par la droite.\nLa recherche y est alors en $O(n)$, comme\ndans un parcours linéaire.\n"
        }
      ],
      "explanation": "Ce phénomène de dégénérescence explique pourquoi on cherche à garder l'arbre équilibré : la recherche dans un arbre binaire de recherche équilibré est de coût logarithmique, en $O(\\log n)$."
    },
    {
      "id": "q04",
      "difficulty": 1,
      "skills": [
        "parcours-infixe"
      ],
      "title": "Parcours infixe",
      "partie": "definition",
      "statement": "Que donne un parcours **infixe** sur un arbre\nbinaire de recherche ?",
      "options": [
        {
          "text": "Les valeurs dans un ordre aléatoire",
          "correct": false,
          "feedback": "Un parcours d'arbre est strictement\ndéterministe : il ne fait jamais appel au\nhasard.\n"
        },
        {
          "text": "Les valeurs dans l'ordre croissant",
          "correct": true,
          "feedback": "C'est précisément la propriété remarquable\ndes arbres binaires de recherche. Le\nparcours infixe (sous-arbre gauche, racine,\nsous-arbre droit) visite naturellement les\nvaleurs dans l'ordre croissant.\n"
        },
        {
          "text": "Les valeurs dans l'ordre décroissant",
          "correct": false,
          "feedback": "Pour obtenir l'ordre décroissant, il\nfaudrait inverser le parcours infixe en\nvisitant d'abord le sous-arbre droit, puis\nla racine, puis le sous-arbre gauche.\n"
        },
        {
          "text": "Aucune valeur particulière n'est visitée",
          "correct": false,
          "feedback": "Un parcours visite chaque nœud exactement\nune fois. Toutes les valeurs sont donc\nparcourues.\n"
        }
      ],
      "explanation": "Cette propriété permet de transformer un\narbre binaire de recherche en un tableau\ntrié en $O(n)$. C'est aussi pour cette raison\nque cette structure est naturelle pour\nmaintenir un ensemble ordonné."
    },
    {
      "id": "q05",
      "difficulty": 1,
      "skills": [
        "insertion"
      ],
      "title": "Insertion",
      "partie": "operations",
      "statement": "Pour insérer une valeur $v$ dans un arbre\nbinaire de recherche, on procède de la manière\nsuivante :",
      "options": [
        {
          "text": "On descend en comparant, puis on insère comme nouvelle feuille",
          "correct": true,
          "feedback": "Si la valeur $v$ est plus petite que celle\ndu nœud courant, on descend dans le\nsous-arbre gauche ; sinon dans le\nsous-arbre droit. On répète jusqu'à\nrencontrer une place vide, où l'on crée\nune nouvelle feuille.\n"
        },
        {
          "text": "On trie les valeurs, puis on la place",
          "correct": false,
          "feedback": "L'insertion est une opération locale qui\npréserve l'invariant d'ordre. Aucun tri\nglobal n'est nécessaire.\n"
        },
        {
          "text": "On la place toujours à la racine",
          "correct": false,
          "feedback": "Insérer la nouvelle valeur à la racine\nbriserait la propriété d'ordre. L'insertion\ndoit au contraire respecter la structure\nexistante.\n"
        },
        {
          "text": "On la place dans la première feuille rencontrée, sans comparaison",
          "correct": false,
          "feedback": "Sans comparaison avec la valeur des nœuds,\nla propriété d'ordre serait violée et\nl'arbre cesserait d'être un arbre binaire\nde recherche.\n"
        }
      ],
      "explanation": "L'insertion s'effectue en $O(h)$, où $h$ est\nla hauteur de l'arbre. Lorsque l'arbre est\néquilibré, on a $h = O(\\log n)$. Sinon, dans\nle pire cas, l'insertion peut atteindre\n$O(n)$."
    },
    {
      "id": "q06",
      "difficulty": 1,
      "skills": [
        "recherche",
        "chemin"
      ],
      "title": "Nœuds visités lors d'une recherche",
      "partie": "operations",
      "statement": "Dans un arbre binaire de recherche, la racine porte $50$ ; ses enfants sont $30$ à gauche et $70$ à droite ; $30$ a pour enfants $20$ et $40$, et $70$ a pour enfants $60$ et $80$. On recherche la clé $60$. Quels nœuds sont visités, dans l'ordre ?",
      "options": [
        {
          "text": "$50$, $30$, $70$, $60$",
          "correct": false,
          "feedback": "Erreur : tu visites l'arbre niveau par niveau. La recherche compare $60$ à $50$ et part aussitôt à droite : le sous-arbre gauche, qui ne contient que des clés plus petites que $50$, n'est jamais visité.\n"
        },
        {
          "text": "$50$, $70$, $60$",
          "correct": true,
          "feedback": "Bonne réponse : $60 > 50$, on descend à droite vers $70$ ; $60 < 70$, on descend à gauche et l'on trouve $60$. Trois nœuds suffisent.\n"
        },
        {
          "text": "$20$, $30$, $40$, $50$, $60$",
          "correct": false,
          "feedback": "Erreur : tu suis le parcours infixe jusqu'à trouver la clé. La recherche part de la racine et, grâce à la propriété d'ordre, ne descend que d'un côté à chaque étape.\n"
        },
        {
          "text": "$50$, $30$, $20$, $40$, $70$, $60$",
          "correct": false,
          "feedback": "Erreur : tu suis le parcours préfixe jusqu'à trouver la clé. Comparer $60$ à la racine suffit pour savoir qu'il est inutile d'explorer le sous-arbre gauche.\n"
        }
      ],
      "explanation": "La recherche d'une clé part de la racine et, à chaque nœud, compare la clé cherchée à celle du nœud : plus petite, on descend à gauche ; plus grande, à droite. On visite ainsi au plus un nœud par niveau de l'arbre."
    },
    {
      "id": "q07",
      "difficulty": 1,
      "skills": [
        "comparaison-tableau"
      ],
      "title": "Comparaison avec un tableau trié",
      "partie": "complexite",
      "statement": "Quel est l'**avantage** d'un arbre binaire de\nrecherche équilibré par rapport à un tableau\ntrié ?",
      "options": [
        {
          "text": "La recherche y est plus rapide",
          "correct": false,
          "feedback": "La recherche dichotomique dans un tableau\ntrié est elle aussi en $O(\\log n)$. Les\ndeux structures sont équivalentes pour la\nrecherche.\n"
        },
        {
          "text": "Aucune différence n'existe entre les deux structures",
          "correct": false,
          "feedback": "Les deux structures se distinguent\nprécisément par leur comportement face\naux opérations dynamiques d'ajout et de\nsuppression.\n"
        },
        {
          "text": "Insertion et suppression en $O(\\log n)$ au lieu de $O(n)$",
          "correct": true,
          "feedback": "C'est le principal atout d'un arbre\nbinaire de recherche équilibré. On peut y\nmaintenir un ensemble trié dynamique avec\ntoutes les opérations en $O(\\log n)$,\nalors qu'une insertion ou une suppression\nau milieu d'un tableau trié coûte $O(n)$.\n"
        },
        {
          "text": "Il consomme moins de mémoire qu'un tableau",
          "correct": false,
          "feedback": "Au contraire, un arbre binaire de\nrecherche consomme en général plus de\nmémoire qu'un tableau, en raison des\nréférences entre nœuds.\n"
        }
      ],
      "explanation": "Le compromis est clair. Si l'on a beaucoup de\nrecherches mais peu d'insertions, le tableau\ntrié peut suffire. Pour un mélange dynamique\nd'opérations, l'arbre binaire de recherche\néquilibré est mieux adapté."
    },
    {
      "id": "q08",
      "difficulty": 1,
      "skills": [
        "insertion",
        "racine"
      ],
      "title": "Construire l'arbre",
      "partie": "definition",
      "statement": "On insère successivement les valeurs $5$, $3$, $7$, $1$, $4$ dans un arbre binaire de\nrecherche initialement vide. Que devient la\nracine ?",
      "options": [
        {
          "text": "$5$",
          "correct": true,
          "feedback": "La première valeur insérée devient la\nracine. Toutes les insertions suivantes\ndeviennent des descendants de cette\nracine.\n"
        },
        {
          "text": "$7$",
          "correct": false,
          "feedback": "La valeur $7$ est plus grande que $5$,\ndonc elle est insérée à droite de la\nracine, mais elle ne devient pas la\nracine elle-même.\n"
        },
        {
          "text": "$1$",
          "correct": false,
          "feedback": "La valeur $1$ est la plus petite de toutes et\nfinit en feuille tout à gauche. La racine est toujours\nla **première** valeur insérée.\n"
        },
        {
          "text": "$4$",
          "correct": false,
          "feedback": "La valeur $4$ est insérée en dernier. Elle\nfinit comme enfant droit de $3$, et n'occupe\npas la racine.\n"
        }
      ],
      "explanation": "L'ordre d'insertion détermine la forme de\nl'arbre. Insérer dans l'ordre $1, 3, 4, 5, 7$\ndonnerait un peigne à droite (cas dégénéré).\nC'est précisément pour cette raison que les\nstructures auto-équilibrantes sont\nimportantes en pratique.",
      "variants": [
        {
          "statement": "On insère successivement les valeurs $5$, $3$, $7$, $1$, $4$ dans un arbre binaire de\nrecherche initialement vide. Que devient la\nracine ?",
          "options": [
            {
              "text": "$5$",
              "correct": true,
              "feedback": "La première valeur insérée devient la\nracine. Toutes les insertions suivantes\ndeviennent des descendants de cette\nracine.\n"
            },
            {
              "text": "$7$",
              "correct": false,
              "feedback": "La valeur $7$ est plus grande que $5$,\ndonc elle est insérée à droite de la\nracine, mais elle ne devient pas la\nracine elle-même.\n"
            },
            {
              "text": "$1$",
              "correct": false,
              "feedback": "La valeur $1$ est la plus petite de toutes et\nfinit en feuille tout à gauche. La racine est toujours\nla **première** valeur insérée.\n"
            },
            {
              "text": "$4$",
              "correct": false,
              "feedback": "La valeur $4$ est insérée en dernier. Elle\nfinit comme enfant droit de $3$, et n'occupe\npas la racine.\n"
            }
          ],
          "explanation": "L'ordre d'insertion détermine la forme de\nl'arbre. Insérer dans l'ordre $1, 3, 4, 5, 7$\ndonnerait un peigne à droite (cas dégénéré).\nC'est précisément pour cette raison que les\nstructures auto-équilibrantes sont\nimportantes en pratique."
        },
        {
          "statement": "On insère successivement les valeurs $8$, $2$, $9$, $5$, $7$ dans un arbre binaire de\nrecherche initialement vide. Que devient la\nracine ?",
          "options": [
            {
              "text": "$8$",
              "correct": true,
              "feedback": "La première valeur insérée devient la\nracine. Toutes les insertions suivantes\ndeviennent des descendants de cette\nracine.\n"
            },
            {
              "text": "$9$",
              "correct": false,
              "feedback": "La valeur $9$ est plus grande que $8$,\ndonc elle est insérée à droite de la\nracine, mais elle ne devient pas la\nracine elle-même.\n"
            },
            {
              "text": "$2$",
              "correct": false,
              "feedback": "La valeur $2$ est la plus petite de toutes et\nfinit en feuille tout à gauche. La racine est toujours\nla **première** valeur insérée.\n"
            },
            {
              "text": "$7$",
              "correct": false,
              "feedback": "La valeur $7$ est insérée en dernier. Elle\nfinit comme enfant droit de $5$, et n'occupe\npas la racine.\n"
            }
          ],
          "explanation": "L'ordre d'insertion détermine la forme de\nl'arbre. Insérer dans l'ordre $2, 5, 7, 8, 9$\ndonnerait un peigne à droite (cas dégénéré).\nC'est précisément pour cette raison que les\nstructures auto-équilibrantes sont\nimportantes en pratique."
        },
        {
          "statement": "On insère successivement les valeurs $6$, $9$, $3$, $8$, $4$ dans un arbre binaire de\nrecherche initialement vide. Que devient la\nracine ?",
          "options": [
            {
              "text": "$6$",
              "correct": true,
              "feedback": "La première valeur insérée devient la\nracine. Toutes les insertions suivantes\ndeviennent des descendants de cette\nracine.\n"
            },
            {
              "text": "$9$",
              "correct": false,
              "feedback": "La valeur $9$ est plus grande que $6$,\ndonc elle est insérée à droite de la\nracine, mais elle ne devient pas la\nracine elle-même.\n"
            },
            {
              "text": "$3$",
              "correct": false,
              "feedback": "La valeur $3$ est la plus petite de toutes et\nfinit en feuille tout à gauche. La racine est toujours\nla **première** valeur insérée.\n"
            },
            {
              "text": "$4$",
              "correct": false,
              "feedback": "La valeur $4$ est insérée en dernier. Elle\nfinit comme enfant droit de $3$, et n'occupe\npas la racine.\n"
            }
          ],
          "explanation": "L'ordre d'insertion détermine la forme de\nl'arbre. Insérer dans l'ordre $3, 4, 6, 8, 9$\ndonnerait un peigne à droite (cas dégénéré).\nC'est précisément pour cette raison que les\nstructures auto-équilibrantes sont\nimportantes en pratique."
        }
      ]
    },
    {
      "id": "q09",
      "difficulty": 1,
      "skills": [
        "usage"
      ],
      "title": "Cas d'usage",
      "partie": "definition",
      "statement": "Lequel des cas suivants est un usage typique\nd'un arbre binaire de recherche ?",
      "options": [
        {
          "text": "Maintenir un ensemble trié dynamique avec ajouts fréquents",
          "correct": true,
          "feedback": "C'est l'usage emblématique. On peut par\nexemple gérer une liste de scores triés\nen temps réel, ou un dictionnaire dont\nles clés doivent rester ordonnées.\n"
        },
        {
          "text": "Compter le nombre de mots dans un texte",
          "correct": false,
          "feedback": "Un compteur simple suffit pour cette\ntâche. L'utilisation d'un arbre binaire\nde recherche serait disproportionnée.\n"
        },
        {
          "text": "Afficher une image",
          "correct": false,
          "feedback": "L'affichage d'une image n'a aucun rapport\navec la structure d'arbre binaire de\nrecherche.\n"
        },
        {
          "text": "Calculer la somme de tous les éléments d'une liste donnée",
          "correct": false,
          "feedback": "Un parcours linéaire de la liste suffit.\nAucune structure ordonnée n'est\nnécessaire.\n"
        }
      ],
      "explanation": "En pratique, un arbre binaire de recherche maintenu équilibré permet d'ajouter et de chercher rapidement des éléments tout en les gardant ordonnés : le parcours infixe les restitue triés à tout moment."
    },
    {
      "id": "q10",
      "difficulty": 1,
      "skills": [
        "implementation",
        "code"
      ],
      "title": "Recherche récursive",
      "partie": "operations",
      "statement": "Quelle fonction Python recherche correctement\nla valeur `v` dans un arbre binaire de\nrecherche ?",
      "options": [
        {
          "text": "```python\ndef chercher(n, v):\n    if n is None: return False\n    if v == n.valeur: return True\n    if v < n.valeur:\n        return chercher(n.gauche, v)\n    return chercher(n.droit, v)\n```\n",
          "correct": true,
          "feedback": "Cette fonction ne descend que dans **un seul** sous-arbre selon la comparaison.\nC'est ce qui donne la complexité\n$O(\\log n)$ pour un arbre équilibré.\n"
        },
        {
          "text": "```python\ndef chercher(n, v):\n    if v == n.valeur: return True\n    if v < n.valeur:\n        return chercher(n.gauche, v)\n    return chercher(n.droit, v)\n```\n",
          "correct": false,
          "feedback": "Erreur classique : le cas de base de l'arbre\nvide manque. Dès que `v` est absente, la\ndescente atteint un sous-arbre `None` et\n`n.valeur` lève une `AttributeError` au lieu\nde renvoyer `False`.\n"
        },
        {
          "text": "```python\ndef chercher(n, v):\n    if n is None: return False\n    if v == n.valeur: return True\n    if v < n.valeur:\n        return chercher(n.droit, v)\n    return chercher(n.gauche, v)\n```\n",
          "correct": false,
          "feedback": "Erreur : les directions sont inversées. Dans\nun arbre binaire de recherche, les valeurs\nplus petites que `n.valeur` sont à **gauche**.\nCette fonction ne trouve que la valeur de la\nracine.\n"
        },
        {
          "text": "```python\ndef chercher(n, v):\n    if n is None: return False\n    if n.valeur == v: return True\n    return chercher(n.gauche, v) or chercher(n.droit, v)\n```\n",
          "correct": false,
          "feedback": "Cette fonction parcourt l'arbre entier\nsans exploiter la propriété d'ordre. Sa\ncomplexité est en $O(n)$ et non en\n$O(\\log n)$.\n"
        }
      ],
      "explanation": "C'est précisément la propriété d'ordre qui\npermet d'éliminer la moitié de l'arbre à\nchaque comparaison. Sans cette propriété, on\nretomberait sur un parcours linéaire de tous\nles nœuds."
    },
    {
      "id": "q13",
      "difficulty": 2,
      "skills": [
        "insertion-pire-cas"
      ],
      "title": "Insertion dans le pire cas",
      "partie": "complexite",
      "statement": "Dans un arbre binaire de recherche **non équilibré**, quelle séquence d'insertions\nconduit au pire cas (forme dégénérée) ?",
      "options": [
        {
          "text": "Insérer les valeurs en commençant par la médiane",
          "correct": false,
          "feedback": "Au contraire, insérer la médiane en\npremier conduit à un arbre bien\néquilibré.\n"
        },
        {
          "text": "Insérer une seule valeur",
          "correct": false,
          "feedback": "Un arbre composé d'un seul nœud ne pose\névidemment aucun problème de\ndégénérescence.\n"
        },
        {
          "text": "Insérer les valeurs dans un ordre aléatoire",
          "correct": false,
          "feedback": "Avec un ordre aléatoire, on tend vers une\nbonne forme d'arbre, dont la hauteur est\nen $O(\\log n)$ en espérance.\n"
        },
        {
          "text": "Insérer les valeurs déjà triées",
          "correct": true,
          "feedback": "En insérant les valeurs $1, 2, 3, \\ldots, n$\ndans l'ordre, chaque nouvelle valeur va à\ndroite de la précédente, ce qui crée un\npeigne. La hauteur atteint alors $n - 1$\net toutes les opérations dégénèrent en\n$O(n)$.\n"
        }
      ],
      "explanation": "Pour éviter ce piège, on peut mélanger les valeurs avant de les insérer, ou choisir un ordre d'insertion qui place en premier la médiane, puis les médianes de chaque moitié."
    },
    {
      "id": "q14",
      "difficulty": 2,
      "skills": [
        "parcours-infixe"
      ],
      "title": "Application du parcours infixe",
      "partie": "definition",
      "statement": "Comment obtenir efficacement les valeurs\n**triées** d'un arbre binaire de recherche ?",
      "options": [
        {
          "text": "Trier les valeurs à chaque opération",
          "correct": false,
          "feedback": "Un arbre binaire de recherche maintient\ndéjà l'ordre par sa structure même. Il\nserait redondant de retrier les valeurs.\n"
        },
        {
          "text": "Ne renvoyer que les feuilles de l'arbre",
          "correct": false,
          "feedback": "On perdrait alors toutes les valeurs des\nnœuds internes, ce qui est manifestement\nincorrect.\n"
        },
        {
          "text": "Effectuer plutôt un simple parcours préfixe",
          "correct": false,
          "feedback": "Le parcours préfixe ne donne pas les\nvaleurs triées en général. Seul le\nparcours infixe possède cette propriété.\n"
        },
        {
          "text": "Effectuer un parcours infixe (ordre croissant)",
          "correct": true,
          "feedback": "Le parcours infixe en $O(n)$ donne\ndirectement les valeurs triées. On ne\npeut pas faire mieux : il faut bien\nvisiter chaque élément au moins une\nfois.\n"
        }
      ],
      "explanation": "Cette propriété permet d'utiliser un arbre\nbinaire de recherche pour réaliser un tri.\nSi l'arbre reste équilibré, les $n$ insertions\ncoûtent $O(n \\log n)$ au total ; avec le\nparcours infixe en $O(n)$, on obtient un tri\nen $O(n \\log n)$, comparable au tri fusion."
    },
    {
      "id": "q15",
      "difficulty": 2,
      "skills": [
        "code-insertion"
      ],
      "title": "Code d'insertion récursive",
      "partie": "operations",
      "statement": "Quelle fonction Python insère correctement la\nvaleur `v` dans un arbre binaire de\nrecherche, en renvoyant la nouvelle racine ?",
      "options": [
        {
          "text": "```python\ndef inserer(n, v):\n    if n is None: return Noeud(v)\n    if v < n.valeur:\n        n.gauche = inserer(n.gauche, v)\n    else:\n        n.droit = inserer(n.droit, v)\n    return n\n```\n",
          "correct": true,
          "feedback": "Si l'arbre est vide, la fonction crée un\nnouveau nœud. Sinon, elle descend\nrécursivement à gauche ou à droite selon\nla comparaison, puis réaffecte le\nsous-arbre modifié.\n"
        },
        {
          "text": "```python\ndef inserer(n, v):\n    if n is None:\n        n = Noeud(v)\n    elif v < n.valeur:\n        inserer(n.gauche, v)\n    else:\n        inserer(n.droit, v)\n    return n\n```\n",
          "correct": false,
          "feedback": "Erreur classique : les appels récursifs ne\nréaffectent pas leur résultat. Le nœud créé\nau cas de base est perdu (l'affectation\nlocale `n = Noeud(v)` ne modifie pas l'arbre\ndu parent). Il faut écrire\n`n.gauche = inserer(n.gauche, v)`.\n"
        },
        {
          "text": "```python\ndef inserer(n, v):\n    if n is None: return Noeud(v)\n    if v < n.valeur:\n        n.gauche = inserer(n.gauche, v)\n    else:\n        n.droit = inserer(n.droit, v)\n```\n",
          "correct": false,
          "feedback": "Erreur classique : le `return n` final manque.\nPour tout arbre non vide, la fonction renvoie\n`None`, que le parent affecte à `n.gauche` ou\n`n.droit` : le sous-arbre existant est détruit\nà chaque insertion.\n"
        },
        {
          "text": "```python\ndef inserer(n, v):\n    if v < n.valeur:\n        n.gauche = Noeud(v)\n    else:\n        n.droit = Noeud(v)\n    return n\n```\n",
          "correct": false,
          "feedback": "Erreur : la fonction ne descend pas dans\nl'arbre. Elle accroche le nouveau nœud\ndirectement sous la racine, en écrasant le\nsous-arbre qui s'y trouvait déjà, et elle\néchoue sur un arbre vide.\n"
        }
      ],
      "explanation": "Cette fonction est typique : elle parcourt\nl'arbre depuis la racine en comparant les\nvaleurs, et crée un nouveau nœud à la place\nvide trouvée. Sa complexité est en $O(h)$,\noù $h$ est la hauteur de l'arbre."
    },
    {
      "id": "q16",
      "difficulty": 2,
      "skills": [
        "equilibre-construction"
      ],
      "title": "Construire un arbre équilibré",
      "partie": "complexite",
      "statement": "Pour construire un arbre binaire de recherche\néquilibré à partir d'un tableau trié, quelle\nstratégie est la plus simple ?",
      "options": [
        {
          "text": "Insérer les éléments dans un ordre aléatoire",
          "correct": false,
          "feedback": "Cette approche donne un arbre presque\néquilibré en moyenne, mais sans aucune\ngarantie absolue.\n"
        },
        {
          "text": "Insérer les éléments directement dans l'ordre exact du tableau",
          "correct": false,
          "feedback": "Cette stratégie produit précisément un\npeigne dégénéré, puisque les valeurs\nsont déjà triées.\n"
        },
        {
          "text": "Le milieu comme racine, puis récursivement des deux côtés",
          "correct": true,
          "feedback": "C'est l'algorithme classique. La moitié\nde gauche devient le sous-arbre gauche,\nconstruit récursivement par la même\nméthode, et de même pour la moitié de\ndroite. L'arbre obtenu est parfaitement\néquilibré, de hauteur $O(\\log n)$.\n"
        },
        {
          "text": "Insérer les éléments du dernier au premier",
          "correct": false,
          "feedback": "Cette stratégie produit un peigne\ndégénéré dans l'autre sens, ce qui n'est\npas plus satisfaisant.\n"
        }
      ],
      "explanation": "Cet algorithme est en $O(n)$. Il est utile\npour reconstruire un arbre équilibré à\npartir d'une séquence triée, par exemple\nlors d'une migration de données."
    },
    {
      "id": "q17",
      "difficulty": 2,
      "skills": [
        "recherche-pas-trouve"
      ],
      "title": "Échec de la recherche",
      "partie": "operations",
      "statement": "Lorsque la recherche d'une valeur **absente**\nse termine dans un arbre binaire de recherche,\nà quel endroit s'arrête-t-on ?",
      "options": [
        {
          "text": "À la racine de l'arbre",
          "correct": false,
          "feedback": "On s'arrête en général à un endroit plus\nprofond dans l'arbre, lorsque la branche\nrecherchée est vide.\n"
        },
        {
          "text": "La fonction lève une exception",
          "correct": false,
          "feedback": "On renvoie typiquement la valeur `False`\nou `None`, sans lever d'exception\n(sauf si on adopte volontairement cette\nconvention).\n"
        },
        {
          "text": "À un sous-arbre vide (`None`)",
          "correct": true,
          "feedback": "À chaque étape, on choisit le sous-arbre\ngauche ou le sous-arbre droit. Si la\nvaleur n'est jamais égale au nœud\ncourant et que l'on atteint un\nsous-arbre vide, c'est qu'elle est\nabsente.\n"
        },
        {
          "text": "À une feuille quelconque, peu importe sa valeur",
          "correct": false,
          "feedback": "On ne s'arrête pas systématiquement à\nune feuille. On peut s'arrêter à un\nsous-arbre vide pendant à un nœud\ninterne.\n"
        }
      ],
      "explanation": "C'est ce comportement qui permet la recherche\nen $O(h)$ : on ne descend que dans une seule\nbranche, ce qui prend au plus $\\log n$\nétapes pour un arbre équilibré."
    },
    {
      "id": "q18",
      "difficulty": 2,
      "skills": [
        "verification"
      ],
      "title": "Vérifier la propriété d'ordre",
      "partie": "definition",
      "statement": "Pour vérifier qu'un arbre binaire respecte la\npropriété d'arbre binaire de recherche, il\n**ne suffit pas** de vérifier localement à\nchaque nœud que :",
      "options": [
        {
          "text": "Les feuilles se trouvent toutes au même niveau",
          "correct": false,
          "feedback": "Aucune contrainte de niveau n'est\nimposée dans un arbre binaire de\nrecherche.\n"
        },
        {
          "text": "La hauteur des sous-arbres est équilibrée",
          "correct": false,
          "feedback": "Cette propriété correspond à\nl'équilibre, et non à la propriété\nd'ordre qui définit un arbre binaire de\nrecherche.\n"
        },
        {
          "text": "L'enfant gauche est plus petit, le droit plus grand",
          "correct": true,
          "feedback": "C'est un piège classique. Vérifier\nuniquement les enfants directs ne\nsuffit pas. La propriété d'arbre\nbinaire de recherche demande que\n**tout** le sous-arbre gauche soit\ninférieur à la valeur du nœud, et pas\nseulement la racine de ce sous-arbre.\n"
        },
        {
          "text": "La valeur du nœud est exactement la moyenne de celles de ses enfants",
          "correct": false,
          "feedback": "Cette propriété correspond à un autre\ntype d'arbre, mais elle n'a aucun\nrapport avec la définition d'un arbre\nbinaire de recherche.\n"
        }
      ],
      "explanation": "L'algorithme correct consiste à transmettre\nrécursivement les bornes (`min`, `max`) que\nla valeur de chaque nœud doit respecter. La\nracine accepte toutes les valeurs, le\nsous-arbre gauche reçoit l'intervalle\n$(\\min, \\text{valeur})$ et le sous-arbre\ndroit reçoit l'intervalle\n$(\\text{valeur}, \\max)$."
    },
    {
      "id": "q20",
      "difficulty": 2,
      "skills": [
        "parcours-infixe",
        "insertion"
      ],
      "title": "Lecture d'un arbre",
      "partie": "operations",
      "statement": "On insère successivement les valeurs $5$, $2$, $8$, $1$, $3$ dans un arbre binaire de\nrecherche initialement vide. Quel est le\nrésultat de son parcours infixe ?",
      "options": [
        {
          "text": "$8, 5, 3, 2, 1$ (ordre décroissant)",
          "correct": false,
          "feedback": "Cette séquence correspond au parcours\ninfixe inversé, et non au parcours\ninfixe standard.\n"
        },
        {
          "text": "$1, 2, 3, 5, 8$ (ordre croissant)",
          "correct": true,
          "feedback": "Le parcours infixe donne toujours les\nvaleurs en ordre croissant. On peut le\nvérifier en construisant l'arbre :\nracine $5$, sous-arbre gauche enraciné en $2$ (avec $1$ et $3$), sous-arbre droit réduit à $8$. Le parcours infixe\ndonne bien $1, 2, 3, 5, 8$.\n"
        },
        {
          "text": "$5, 2, 1, 3, 8$ (parcours préfixe)",
          "correct": false,
          "feedback": "Cette séquence correspond au parcours\n**préfixe** (racine, gauche, droite),\net non au parcours infixe.\n"
        },
        {
          "text": "$5, 2, 8, 1, 3$ (ordre d'insertion)",
          "correct": false,
          "feedback": "Le parcours infixe d'un arbre binaire\nde recherche donne les valeurs triées,\net non l'ordre d'insertion d'origine.\n"
        }
      ],
      "explanation": "Cet exemple illustre parfaitement la\npropriété d'ordre. Dessiner l'arbre est\nsouvent utile pour visualiser et vérifier\nles différents parcours.",
      "variants": [
        {
          "statement": "On insère successivement les valeurs $5$, $2$, $8$, $1$, $3$ dans un arbre binaire de\nrecherche initialement vide. Quel est le\nrésultat de son parcours infixe ?",
          "options": [
            {
              "text": "$8, 5, 3, 2, 1$ (ordre décroissant)",
              "correct": false,
              "feedback": "Cette séquence correspond au parcours\ninfixe inversé, et non au parcours\ninfixe standard.\n"
            },
            {
              "text": "$1, 2, 3, 5, 8$ (ordre croissant)",
              "correct": true,
              "feedback": "Le parcours infixe donne toujours les\nvaleurs en ordre croissant. On peut le\nvérifier en construisant l'arbre :\nracine $5$, sous-arbre gauche enraciné en $2$ (avec $1$ et $3$), sous-arbre droit réduit à $8$. Le parcours infixe\ndonne bien $1, 2, 3, 5, 8$.\n"
            },
            {
              "text": "$5, 2, 1, 3, 8$ (parcours préfixe)",
              "correct": false,
              "feedback": "Cette séquence correspond au parcours\n**préfixe** (racine, gauche, droite),\net non au parcours infixe.\n"
            },
            {
              "text": "$5, 2, 8, 1, 3$ (ordre d'insertion)",
              "correct": false,
              "feedback": "Le parcours infixe d'un arbre binaire\nde recherche donne les valeurs triées,\net non l'ordre d'insertion d'origine.\n"
            }
          ],
          "explanation": "Cet exemple illustre parfaitement la\npropriété d'ordre. Dessiner l'arbre est\nsouvent utile pour visualiser et vérifier\nles différents parcours."
        },
        {
          "statement": "On insère successivement les valeurs $7$, $4$, $9$, $2$, $6$ dans un arbre binaire de\nrecherche initialement vide. Quel est le\nrésultat de son parcours infixe ?",
          "options": [
            {
              "text": "$9, 7, 6, 4, 2$ (ordre décroissant)",
              "correct": false,
              "feedback": "Cette séquence correspond au parcours\ninfixe inversé, et non au parcours\ninfixe standard.\n"
            },
            {
              "text": "$2, 4, 6, 7, 9$ (ordre croissant)",
              "correct": true,
              "feedback": "Le parcours infixe donne toujours les\nvaleurs en ordre croissant. On peut le\nvérifier en construisant l'arbre :\nracine $7$, sous-arbre gauche enraciné en $4$ (avec $2$ et $6$), sous-arbre droit réduit à $9$. Le parcours infixe\ndonne bien $2, 4, 6, 7, 9$.\n"
            },
            {
              "text": "$7, 4, 2, 6, 9$ (parcours préfixe)",
              "correct": false,
              "feedback": "Cette séquence correspond au parcours\n**préfixe** (racine, gauche, droite),\net non au parcours infixe.\n"
            },
            {
              "text": "$7, 4, 9, 2, 6$ (ordre d'insertion)",
              "correct": false,
              "feedback": "Le parcours infixe d'un arbre binaire\nde recherche donne les valeurs triées,\net non l'ordre d'insertion d'origine.\n"
            }
          ],
          "explanation": "Cet exemple illustre parfaitement la\npropriété d'ordre. Dessiner l'arbre est\nsouvent utile pour visualiser et vérifier\nles différents parcours."
        },
        {
          "statement": "On insère successivement les valeurs $10$, $15$, $5$, $12$, $20$ dans un arbre binaire de\nrecherche initialement vide. Quel est le\nrésultat de son parcours infixe ?",
          "options": [
            {
              "text": "$20, 15, 12, 10, 5$ (ordre décroissant)",
              "correct": false,
              "feedback": "Cette séquence correspond au parcours\ninfixe inversé, et non au parcours\ninfixe standard.\n"
            },
            {
              "text": "$5, 10, 12, 15, 20$ (ordre croissant)",
              "correct": true,
              "feedback": "Le parcours infixe donne toujours les\nvaleurs en ordre croissant. On peut le\nvérifier en construisant l'arbre :\nracine $10$, sous-arbre gauche réduit à $5$, sous-arbre droit enraciné en $15$ (avec $12$ et $20$). Le parcours infixe\ndonne bien $5, 10, 12, 15, 20$.\n"
            },
            {
              "text": "$10, 5, 15, 12, 20$ (parcours préfixe)",
              "correct": false,
              "feedback": "Cette séquence correspond au parcours\n**préfixe** (racine, gauche, droite),\net non au parcours infixe.\n"
            },
            {
              "text": "$10, 15, 5, 12, 20$ (ordre d'insertion)",
              "correct": false,
              "feedback": "Le parcours infixe d'un arbre binaire\nde recherche donne les valeurs triées,\net non l'ordre d'insertion d'origine.\n"
            }
          ],
          "explanation": "Cet exemple illustre parfaitement la\npropriété d'ordre. Dessiner l'arbre est\nsouvent utile pour visualiser et vérifier\nles différents parcours."
        }
      ]
    },
    {
      "id": "q21",
      "difficulty": 3,
      "skills": [
        "parcours",
        "prefixe",
        "suffixe"
      ],
      "title": "Du parcours préfixe au parcours suffixe",
      "partie": "definition",
      "statement": "Le parcours préfixe d'un arbre binaire de recherche donne les clés $8$, $3$, $1$, $6$, $10$, $14$. Quel est le parcours suffixe de cet arbre ?",
      "options": [
        {
          "text": "$1$, $3$, $6$, $8$, $10$, $14$",
          "correct": false,
          "feedback": "Erreur : c'est le parcours infixe, qui donne toujours les clés triées dans un arbre binaire de recherche. Le parcours suffixe traite chaque nœud après ses deux sous-arbres.\n"
        },
        {
          "text": "$14$, $10$, $6$, $1$, $3$, $8$",
          "correct": false,
          "feedback": "Erreur : le parcours suffixe n'est pas le préfixe lu à l'envers. Il visite d'abord le sous-arbre gauche, puis le droit, puis le nœud.\n"
        },
        {
          "text": "$1$, $6$, $3$, $10$, $14$, $8$",
          "correct": false,
          "feedback": "Erreur : $14$ est l'enfant droit de $10$. En suffixe, un nœud vient après ses enfants : $14$ doit donc précéder $10$.\n"
        },
        {
          "text": "$1$, $6$, $3$, $14$, $10$, $8$",
          "correct": true,
          "feedback": "Bonne réponse : la racine est $8$ ; à gauche, $3$ a pour enfants $1$ et $6$ ; à droite, $10$ a pour enfant droit $14$. Le suffixe donne $1$, $6$, $3$, puis $14$, $10$, et enfin $8$.\n"
        }
      ],
      "explanation": "Le parcours préfixe commence par la racine, ici $8$. En insérant les clés dans l'ordre du parcours préfixe, on reconstruit le même arbre : $3$ à gauche de $8$, $1$ et $6$ sous $3$, $10$ à droite de $8$, puis $14$ à droite de $10$. Il ne reste qu'à le parcourir en ordre suffixe."
    },
    {
      "id": "q23",
      "difficulty": 3,
      "skills": [
        "analyse-comparaison"
      ],
      "title": "Tri par arbre binaire de recherche",
      "partie": "complexite",
      "statement": "Le tri par arbre binaire de recherche, qui\nconsiste à insérer $n$ valeurs dans un arbre\npuis à effectuer un parcours infixe, a une\ncomplexité de :",
      "options": [
        {
          "text": "$O(n!)$, à cause des $n!$ ordres d'insertion possibles",
          "correct": false,
          "feedback": "Le nombre d'ordres d'insertion possibles\nn'intervient pas : on n'en suit qu'un\nseul, celui des données. Une complexité\nfactorielle ne correspond à aucun\nalgorithme de tri raisonnable.\n"
        },
        {
          "text": "$O(n \\log n)$ en moyenne, $O(n^2)$ au pire",
          "correct": true,
          "feedback": "Chaque insertion est en $O(\\log n)$ en\nmoyenne, ce qui donne $O(n \\log n)$\npour les $n$ insertions, auxquelles\ns'ajoute $O(n)$ pour le parcours\ninfixe. Total : $O(n \\log n)$ en\nmoyenne. Mais avec un ordre\nd'insertion défavorable, la hauteur\nexplose et la complexité atteint\n$O(n^2)$.\n"
        },
        {
          "text": "$O(n)$ quel que soit l'ordre d'insertion",
          "correct": false,
          "feedback": "Chaque insertion descend dans l'arbre en faisant une comparaison par niveau. Même dans un arbre équilibré, de hauteur proche de $\\log_2 n$, les $n$ insertions demandent de l'ordre de $n \\log_2 n$ comparaisons, et bien davantage si l'arbre dégénère.\n"
        },
        {
          "text": "$O(2^n)$, car chaque nœud possède deux sous-arbres",
          "correct": false,
          "feedback": "Chaque insertion ne suit qu'un seul\nchemin de la racine vers une feuille ;\nles deux sous-arbres d'un nœud ne sont\njamais explorés tous les deux. Une\ncomplexité exponentielle n'a aucune\nraison d'apparaître dans un tri.\n"
        }
      ],
      "explanation": "Cet algorithme illustre un compromis : il est avantageux pour des données aléatoires, mais fragile dans le pire cas. C'est pourquoi on préfère souvent le tri fusion, dont le coût reste en $O(n \\log n)$ dans tous les cas."
    },
    {
      "id": "q25",
      "difficulty": 3,
      "skills": [
        "synthese"
      ],
      "title": "Quand utiliser un arbre binaire de recherche ?",
      "partie": "complexite",
      "statement": "Lequel des cas suivants justifie l'usage d'un arbre binaire de recherche plutôt qu'une autre structure ?",
      "options": [
        {
          "text": "Un dictionnaire à clés triées dynamiquement",
          "correct": true,
          "feedback": "C'est exactement le cas d'usage d'un arbre binaire de recherche : maintenu équilibré, il permet d'ajouter ou de chercher une clé en $O(\\log n)$ tout en gardant les clés ordonnées, que le parcours infixe restitue triées.\n"
        },
        {
          "text": "Calculer la somme de tous les éléments d'une grande liste",
          "correct": false,
          "feedback": "Un parcours linéaire en $O(n)$ suffit\npour cette tâche. Aucune structure\nd'arbre n'apporterait de gain.\n"
        },
        {
          "text": "Stocker une liste fixe de noms à afficher",
          "correct": false,
          "feedback": "Pour des données statiques, une liste\ntriée stockée dans un tableau suffit.\nAucun arbre binaire de recherche\nn'est nécessaire.\n"
        },
        {
          "text": "Trier $1\\,000$ entiers une seule fois",
          "correct": false,
          "feedback": "Pour ce besoin, un algorithme de tri classique, comme le tri fusion, est plus simple et tout aussi efficace.\n"
        }
      ],
      "explanation": "Pour résumer : on utilise un arbre binaire\nde recherche pour des accès **dynamiques**\navec maintien d'un **ordre** sur les\nvaleurs. Pour des données statiques ou\nsans besoin d'ordre, des structures plus\nsimples suffisent."
    },
    {
      "id": "q26",
      "difficulty": 2,
      "skills": [
        "trace-insertion"
      ],
      "title": "Trace d'insertions successives",
      "partie": "operations",
      "statement": "On part d'un arbre binaire de recherche\nvide. On y insère successivement les valeurs\n$10, 5, 15, 3, 7, 12$. À quoi ressemble la\nstructure obtenue ?",
      "options": [
        {
          "text": "Tous les nœuds sont des feuilles d'une\nracine vide\n",
          "correct": false,
          "feedback": "Erreur : un arbre binaire de recherche\nn'a pas de « racine vide ». La première\nvaleur insérée devient la racine, et les\nsuivantes sont placées comme descendants.\n"
        },
        {
          "text": "Tous les nœuds sur une branche droite,\nformant un peigne\n",
          "correct": false,
          "feedback": "Erreur : on aurait un peigne uniquement\nsi les valeurs étaient insérées dans\nl'ordre croissant ou décroissant. Ici,\nl'ordre est plus équilibré.\n"
        },
        {
          "text": "Racine $5$ ; tous les autres nœuds\nrépartis selon leur valeur\n",
          "correct": false,
          "feedback": "Erreur : la racine est toujours la\n**première** valeur insérée, ici $10$,\npas $5$.\n"
        },
        {
          "text": "Racine $10$, à gauche $5$ (avec $3$ et $7$), à droite $15$ (avec $12$)",
          "correct": true,
          "feedback": "Bonne réponse : à chaque insertion, on\ncompare avec la racine pour choisir le\nsous-arbre. $10$ devient racine. $5 < 10$\nva à gauche. $15 > 10$ va à droite. $3 < 10$\npuis $3 < 5$ va à gauche de $5$. $7 < 10$\npuis $7 > 5$ va à droite de $5$. $12 > 10$\npuis $12 < 15$ va à gauche de $15$.\n"
        }
      ],
      "explanation": "Cet arbre obtenu ($6$ nœuds, hauteur $2$) est\nbien équilibré, ce qui n'est pas un hasard :\nla séquence d'insertion alterne intelligemment\nentre les côtés. Avec une mauvaise séquence\n($1, 2, 3, 4, 5, 6$), on aurait obtenu un\npeigne de hauteur $5$."
    },
    {
      "id": "q27",
      "difficulty": 3,
      "skills": [
        "verification-code"
      ],
      "title": "Code de vérification de la propriété",
      "partie": "definition",
      "statement": "Quelle fonction Python vérifie correctement\nqu'un arbre binaire respecte la propriété\nd'arbre binaire de recherche (en utilisant\ndes bornes minimum et maximum) ?",
      "options": [
        {
          "text": "```python\ndef est_abr(n):\n    if n is None:\n        return True\n    if n.gauche and n.gauche.valeur >= n.valeur:\n        return False\n    if n.droit and n.droit.valeur <= n.valeur:\n        return False\n    return est_abr(n.gauche) and est_abr(n.droit)\n```\n",
          "correct": false,
          "feedback": "Erreur classique : on ne vérifie que la\nrelation parent/enfant direct. Cela rate\ndes cas comme racine $10$, gauche $5$,\ndroite-gauche-droite $20$ (qui est dans\nle sous-arbre gauche de $10$ mais\nsupérieure à $10$). L'arbre serait\ndéclaré valide à tort.\n"
        },
        {
          "text": "```python\ndef est_abr(n, mini=float('-inf'), maxi=float('inf')):\n    if n is None:\n        return True\n    if not (mini < n.valeur < maxi):\n        return False\n    return est_abr(n.gauche, mini, maxi) and est_abr(n.droit, mini, maxi)\n```\n",
          "correct": false,
          "feedback": "Erreur : les bornes sont transmises telles\nquelles aux deux sous-arbres, sans jamais\nêtre resserrées. Avec les bornes infinies\ninitiales, la condition\n`mini < n.valeur < maxi` reste toujours\nvraie : la fonction renvoie `True` pour\nn'importe quel arbre binaire.\n"
        },
        {
          "text": "```python\ndef est_abr(n, mini=float('-inf'), maxi=float('inf')):\n    if n is None:\n        return True\n    if not (mini < n.valeur < maxi):\n        return False\n    return est_abr(n.gauche, mini, n.valeur) and est_abr(n.droit, n.valeur, maxi)\n```\n",
          "correct": true,
          "feedback": "Bonne réponse : on transmet à chaque\nappel récursif les bornes que la valeur\ndu sous-arbre doit respecter. À gauche,\non resserre la borne supérieure ; à\ndroite, la borne inférieure. C'est le\nschéma correct qui détecte aussi les\nviolations « profondes » (par exemple,\nun nœud lointain qui violerait l'ordre).\n"
        },
        {
          "text": "```python\ndef est_abr(n):\n    if n is None:\n        return True\n    return parcours_prefixe(n) == sorted(parcours_prefixe(n))\n```\n",
          "correct": false,
          "feedback": "Erreur : seul le parcours **infixe** d'un\nABR est trié. Le parcours préfixe commence\npar la racine, donc un ABR ordinaire\n(racine $10$, fils gauche $5$) est déclaré\ninvalide, alors qu'une simple chaîne de\nfils droits est acceptée. Même avec le\nparcours infixe, cette approche coûterait\nun tri en $O(n \\log n)$, contre $O(n)$\npour la version à bornes.\n"
        }
      ],
      "explanation": "Le piège pédagogique de cette question est\nla version qui ne compare chaque nœud qu'à ses\nenfants directs : elle semble naturelle mais\nrate les violations à distance. C'est\npour cela que la transmission de bornes par\nparamètre est essentielle : elle propage la\ncontrainte d'ordre tout au long de la\ndescente récursive."
    },
    {
      "id": "q28",
      "difficulty": 2,
      "skills": [
        "extremums"
      ],
      "title": "Minimum et maximum dans un ABR",
      "partie": "operations",
      "statement": "Comment trouver respectivement le **minimum**\net le **maximum** d'un arbre binaire de\nrecherche non vide ?",
      "options": [
        {
          "text": "Le minimum est toujours la racine, le\nmaximum est toujours une feuille\n",
          "correct": false,
          "feedback": "Erreur : la racine est la **première valeur insérée**, pas le minimum. Le\nminimum est dans le sous-arbre le plus à\ngauche. Quant au maximum, il peut être\nn'importe où à droite, pas forcément une\nfeuille.\n"
        },
        {
          "text": "On parcourt tout l'arbre et on retient les\nvaleurs minimale et maximale au fur et à\nmesure\n",
          "correct": false,
          "feedback": "Cette méthode fonctionne (en $O(n)$) mais\nignore la propriété d'ordre. Avec\nl'arbre binaire de recherche, on peut\nfaire bien mieux en descendant\ndirectement à gauche ou à droite, en\n$O(h)$.\n"
        },
        {
          "text": "Le minimum tout à gauche, le maximum tout à droite, en $O(h)$",
          "correct": true,
          "feedback": "Bonne réponse : par la propriété d'ordre,\ntous les nœuds plus petits qu'un nœud\ndonné sont à sa gauche. En descendant\nsystématiquement à gauche jusqu'à\natteindre une feuille (sans enfant\ngauche), on trouve la plus petite valeur.\nSymétriquement à droite pour le maximum.\n"
        },
        {
          "text": "Le minimum et le maximum sont les deux\nenfants de la racine\n",
          "correct": false,
          "feedback": "Erreur : seul l'enfant gauche **direct**\nde la racine peut être plus petit qu'elle,\npas un éventuel descendant plus profond.\nEt symétriquement à droite. La descente\njusqu'au bout est nécessaire.\n"
        }
      ],
      "explanation": "Cette propriété rejoint le parcours infixe : dans un arbre binaire de recherche, le minimum est la première clé affichée par ce parcours et le maximum la dernière."
    },
    {
      "id": "q29",
      "difficulty": 2,
      "skills": [
        "complexite",
        "niveaux",
        "equilibre",
        "calcul"
      ],
      "title": "Le nombre de niveaux minimal pour ranger des clés",
      "partie": "complexite",
      "statement": "Combien de niveaux, au minimum, un arbre binaire de recherche\ndoit-il avoir pour contenir $15$ clés ?",
      "options": [
        {
          "text": "$4$, en remplissant chaque niveau",
          "correct": true,
          "feedback": "Bonne réponse : $4$ niveaux pleins contiennent\n$2^{4} - 1 = 15$ nœuds, juste ce qu'il faut. C'est la\nforme équilibrée, qui donne une recherche en $\\log_2 n$.\n"
        },
        {
          "text": "$7$, la moitié des clés environ",
          "correct": false,
          "feedback": "Erreur : chaque niveau peut contenir le double du précédent,\nles niveaux sont bien moins nombreux.\n"
        },
        {
          "text": "$5$, un niveau de plus pour la racine",
          "correct": false,
          "feedback": "Erreur : la racine occupe le premier niveau, déjà compté.\n"
        },
        {
          "text": "$15$, une clé à chaque niveau",
          "correct": false,
          "feedback": "Erreur : c'est le pire cas, l'arbre filiforme, pas le minimum.\n"
        }
      ],
      "explanation": "Avec $k$ niveaux pleins, un arbre contient $2^k - 1$ clés : le\nnombre minimal de niveaux croît comme $\\log_2 n$.",
      "variants": [
        {
          "statement": "Combien de niveaux, au minimum, un arbre binaire de recherche\ndoit-il avoir pour contenir $15$ clés ?",
          "options": [
            {
              "text": "$4$, en remplissant chaque niveau",
              "correct": true,
              "feedback": "Bonne réponse : $4$ niveaux pleins contiennent\n$2^{4} - 1 = 15$ nœuds, juste ce qu'il faut. C'est la\nforme équilibrée, qui donne une recherche en $\\log_2 n$.\n"
            },
            {
              "text": "$7$, la moitié des clés environ",
              "correct": false,
              "feedback": "Erreur : chaque niveau peut contenir le double du précédent,\nles niveaux sont bien moins nombreux.\n"
            },
            {
              "text": "$5$, un niveau de plus pour la racine",
              "correct": false,
              "feedback": "Erreur : la racine occupe le premier niveau, déjà compté.\n"
            },
            {
              "text": "$15$, une clé à chaque niveau",
              "correct": false,
              "feedback": "Erreur : c'est le pire cas, l'arbre filiforme, pas le minimum.\n"
            }
          ],
          "explanation": "Avec $k$ niveaux pleins, un arbre contient $2^k - 1$ clés : le\nnombre minimal de niveaux croît comme $\\log_2 n$."
        },
        {
          "statement": "Combien de niveaux, au minimum, un arbre binaire de recherche\ndoit-il avoir pour contenir $63$ clés ?",
          "options": [
            {
              "text": "$6$, en remplissant chaque niveau",
              "correct": true,
              "feedback": "Bonne réponse : $6$ niveaux pleins contiennent\n$2^{6} - 1 = 63$ nœuds, juste ce qu'il faut. C'est la\nforme équilibrée, qui donne une recherche en $\\log_2 n$.\n"
            },
            {
              "text": "$31$, la moitié des clés environ",
              "correct": false,
              "feedback": "Erreur : chaque niveau peut contenir le double du précédent,\nles niveaux sont bien moins nombreux.\n"
            },
            {
              "text": "$7$, un niveau de plus pour la racine",
              "correct": false,
              "feedback": "Erreur : la racine occupe le premier niveau, déjà compté.\n"
            },
            {
              "text": "$63$, une clé à chaque niveau",
              "correct": false,
              "feedback": "Erreur : c'est le pire cas, l'arbre filiforme, pas le minimum.\n"
            }
          ],
          "explanation": "Avec $k$ niveaux pleins, un arbre contient $2^k - 1$ clés : le\nnombre minimal de niveaux croît comme $\\log_2 n$."
        },
        {
          "statement": "Combien de niveaux, au minimum, un arbre binaire de recherche\ndoit-il avoir pour contenir $31$ clés ?",
          "options": [
            {
              "text": "$5$, en remplissant chaque niveau",
              "correct": true,
              "feedback": "Bonne réponse : $5$ niveaux pleins contiennent\n$2^{5} - 1 = 31$ nœuds, juste ce qu'il faut. C'est la\nforme équilibrée, qui donne une recherche en $\\log_2 n$.\n"
            },
            {
              "text": "$15$, la moitié des clés environ",
              "correct": false,
              "feedback": "Erreur : chaque niveau peut contenir le double du précédent,\nles niveaux sont bien moins nombreux.\n"
            },
            {
              "text": "$6$, un niveau de plus pour la racine",
              "correct": false,
              "feedback": "Erreur : la racine occupe le premier niveau, déjà compté.\n"
            },
            {
              "text": "$31$, une clé à chaque niveau",
              "correct": false,
              "feedback": "Erreur : c'est le pire cas, l'arbre filiforme, pas le minimum.\n"
            }
          ],
          "explanation": "Avec $k$ niveaux pleins, un arbre contient $2^k - 1$ clés : le\nnombre minimal de niveaux croît comme $\\log_2 n$."
        }
      ]
    },
    {
      "id": "q30",
      "difficulty": 3,
      "skills": [
        "complexite",
        "insertion",
        "ordre-croissant",
        "calcul"
      ],
      "title": "Le coût total d'insertions dans l'ordre croissant",
      "partie": "complexite",
      "statement": "On insère les clés $1, 2, \\ldots, 10$ dans cet ordre dans un\narbre binaire de recherche vide. Chaque insertion compare la\nnouvelle clé à chaque nœud du chemin parcouru. Combien de\ncomparaisons en tout ?",
      "options": [
        {
          "text": "$45$, soit $0 + 1 + \\cdots + 9$",
          "correct": true,
          "feedback": "Bonne réponse : l'arbre devient une chaîne ; la $k$-ième clé\ndescend le long des $k - 1$ nœuds déjà présents. Le total est\n$10 \\times 9 / 2 = 45$, de l'ordre de $n^2$.\n"
        },
        {
          "text": "$10$, une seule par insertion",
          "correct": false,
          "feedback": "Erreur : chaque insertion coûte autant de comparaisons que de\nnœuds sur son chemin, pas une seule.\n"
        },
        {
          "text": "$100$, soit $n$ par insertion",
          "correct": false,
          "feedback": "Erreur : la $k$-ième insertion ne compare qu'avec $k - 1$\nnœuds, pas $n$.\n"
        },
        {
          "text": "$9$, une par nœud déjà présent",
          "correct": false,
          "feedback": "Erreur : $9$ est le coût de la dernière insertion seulement.\n"
        }
      ],
      "explanation": "Les clés triées sont le pire ordre d'insertion : l'arbre dégénère\nen liste et le coût cumulé devient quadratique.",
      "variants": [
        {
          "statement": "On insère les clés $1, 2, \\ldots, 10$ dans cet ordre dans un\narbre binaire de recherche vide. Chaque insertion compare la\nnouvelle clé à chaque nœud du chemin parcouru. Combien de\ncomparaisons en tout ?",
          "options": [
            {
              "text": "$45$, soit $0 + 1 + \\cdots + 9$",
              "correct": true,
              "feedback": "Bonne réponse : l'arbre devient une chaîne ; la $k$-ième clé\ndescend le long des $k - 1$ nœuds déjà présents. Le total est\n$10 \\times 9 / 2 = 45$, de l'ordre de $n^2$.\n"
            },
            {
              "text": "$10$, une seule par insertion",
              "correct": false,
              "feedback": "Erreur : chaque insertion coûte autant de comparaisons que de\nnœuds sur son chemin, pas une seule.\n"
            },
            {
              "text": "$100$, soit $n$ par insertion",
              "correct": false,
              "feedback": "Erreur : la $k$-ième insertion ne compare qu'avec $k - 1$\nnœuds, pas $n$.\n"
            },
            {
              "text": "$9$, une par nœud déjà présent",
              "correct": false,
              "feedback": "Erreur : $9$ est le coût de la dernière insertion seulement.\n"
            }
          ],
          "explanation": "Les clés triées sont le pire ordre d'insertion : l'arbre dégénère\nen liste et le coût cumulé devient quadratique."
        },
        {
          "statement": "On insère les clés $1, 2, \\ldots, 20$ dans cet ordre dans un\narbre binaire de recherche vide. Chaque insertion compare la\nnouvelle clé à chaque nœud du chemin parcouru. Combien de\ncomparaisons en tout ?",
          "options": [
            {
              "text": "$190$, soit $0 + 1 + \\cdots + 19$",
              "correct": true,
              "feedback": "Bonne réponse : l'arbre devient une chaîne ; la $k$-ième clé\ndescend le long des $k - 1$ nœuds déjà présents. Le total est\n$20 \\times 19 / 2 = 190$, de l'ordre de $n^2$.\n"
            },
            {
              "text": "$20$, une seule par insertion",
              "correct": false,
              "feedback": "Erreur : chaque insertion coûte autant de comparaisons que de\nnœuds sur son chemin, pas une seule.\n"
            },
            {
              "text": "$400$, soit $n$ par insertion",
              "correct": false,
              "feedback": "Erreur : la $k$-ième insertion ne compare qu'avec $k - 1$\nnœuds, pas $n$.\n"
            },
            {
              "text": "$19$, une par nœud déjà présent",
              "correct": false,
              "feedback": "Erreur : $19$ est le coût de la dernière insertion seulement.\n"
            }
          ],
          "explanation": "Les clés triées sont le pire ordre d'insertion : l'arbre dégénère\nen liste et le coût cumulé devient quadratique."
        },
        {
          "statement": "On insère les clés $1, 2, \\ldots, 8$ dans cet ordre dans un\narbre binaire de recherche vide. Chaque insertion compare la\nnouvelle clé à chaque nœud du chemin parcouru. Combien de\ncomparaisons en tout ?",
          "options": [
            {
              "text": "$28$, soit $0 + 1 + \\cdots + 7$",
              "correct": true,
              "feedback": "Bonne réponse : l'arbre devient une chaîne ; la $k$-ième clé\ndescend le long des $k - 1$ nœuds déjà présents. Le total est\n$8 \\times 7 / 2 = 28$, de l'ordre de $n^2$.\n"
            },
            {
              "text": "$8$, une seule par insertion",
              "correct": false,
              "feedback": "Erreur : chaque insertion coûte autant de comparaisons que de\nnœuds sur son chemin, pas une seule.\n"
            },
            {
              "text": "$64$, soit $n$ par insertion",
              "correct": false,
              "feedback": "Erreur : la $k$-ième insertion ne compare qu'avec $k - 1$\nnœuds, pas $n$.\n"
            },
            {
              "text": "$7$, une par nœud déjà présent",
              "correct": false,
              "feedback": "Erreur : $7$ est le coût de la dernière insertion seulement.\n"
            }
          ],
          "explanation": "Les clés triées sont le pire ordre d'insertion : l'arbre dégénère\nen liste et le coût cumulé devient quadratique."
        }
      ]
    },
    {
      "id": "q31",
      "difficulty": 2,
      "skills": [
        "complexite",
        "equilibrage",
        "garantie"
      ],
      "title": "L'intérêt de rééquilibrer un arbre",
      "partie": "complexite",
      "statement": "Certaines bibliothèques rééquilibrent l'arbre binaire de recherche\naprès chaque insertion, au prix d'un travail supplémentaire.\nQu'y gagne-t-on ?",
      "options": [
        {
          "text": "Une hauteur en $\\log n$, quel que soit l'ordre des insertions",
          "correct": true,
          "feedback": "Bonne réponse : sans rééquilibrage, des clés insérées dans\nl'ordre dégradent l'arbre en liste ; le rééquilibrage maintient\ntoutes les opérations en $\\log n$.\n"
        },
        {
          "text": "La possibilité de ranger des clés en double sans conflit",
          "correct": false,
          "feedback": "Erreur : les doublons relèvent d'une convention, pas de\nl'équilibre.\n"
        },
        {
          "text": "Un parcours infixe plus rapide, en $\\log n$ au lieu de $n$",
          "correct": false,
          "feedback": "Erreur : le parcours infixe visite tous les nœuds, il reste en\n$n$ quelle que soit la forme.\n"
        },
        {
          "text": "Une mémoire réduite, les nœuds étant rangés plus serrés",
          "correct": false,
          "feedback": "Erreur : le nombre de nœuds ne change pas, la mémoire non\nplus.\n"
        }
      ],
      "explanation": "Les coûts logarithmiques d'un arbre binaire de recherche supposent\nun arbre équilibré ; le garantir a un prix à chaque insertion."
    },
    {
      "id": "q32",
      "difficulty": 1,
      "skills": [
        "complexite",
        "ordre-insertion",
        "forme"
      ],
      "title": "L'ordre d'insertion et la forme de l'arbre",
      "partie": "complexite",
      "statement": "Deux programmes insèrent les mêmes clés dans un arbre binaire de\nrecherche vide, mais dans des ordres différents. Obtiennent-ils le\nmême arbre ?",
      "options": [
        {
          "text": "Pas forcément, l'ordre d'insertion détermine la forme",
          "correct": true,
          "feedback": "Bonne réponse : la première clé devient la racine, et chaque\nsuivante se place sous les précédentes. Les clés $1, 2, 3$\ndonnent une chaîne ; $2, 1, 3$ donnent un arbre équilibré.\n"
        },
        {
          "text": "Oui, un ensemble de clés donne toujours le même arbre",
          "correct": false,
          "feedback": "Erreur : seul le parcours infixe est le même ; la forme dépend\nde l'ordre.\n"
        },
        {
          "text": "Non, jamais, deux ordres donnant deux arbres distincts",
          "correct": false,
          "feedback": "Erreur : deux ordres différents peuvent donner le même arbre,\npar exemple $2, 1, 3$ et $2, 3, 1$.\n"
        },
        {
          "text": "Oui, à condition que les clés soient des entiers",
          "correct": false,
          "feedback": "Erreur : le type des clés ne change rien.\n"
        }
      ],
      "explanation": "Un arbre binaire de recherche garde la trace de l'ordre dans lequel\nil a été construit ; seul le parcours infixe en est indépendant."
    },
    {
      "id": "q33",
      "difficulty": 2,
      "skills": [
        "complexite",
        "minimum",
        "hauteur"
      ],
      "title": "Le coût de la recherche du minimum",
      "partie": "complexite",
      "statement": "Pour trouver la plus petite clé d'un arbre binaire de recherche,\non descend à gauche tant que possible. Quel est le coût de cette\nrecherche ?",
      "options": [
        {
          "text": "Proportionnel à la hauteur, de $\\log n$ à $n$ selon la forme",
          "correct": true,
          "feedback": "Bonne réponse : on suit une seule branche, la plus à gauche ; sa\nlongueur est au plus la hauteur, logarithmique si l'arbre est\néquilibré, linéaire s'il est filiforme.\n"
        },
        {
          "text": "Constant, le minimum étant toujours à la racine de l'arbre",
          "correct": false,
          "feedback": "Erreur : la racine est la première clé insérée, pas la plus\npetite.\n"
        },
        {
          "text": "Toujours en $\\log n$, quelle que soit la forme de l'arbre",
          "correct": false,
          "feedback": "Erreur : dans un arbre filiforme penché à gauche, la branche\ngauche contient tous les nœuds.\n"
        },
        {
          "text": "Toujours en $n$, tous les nœuds devant être comparés",
          "correct": false,
          "feedback": "Erreur : inutile de visiter les sous-arbres droits, qui ne\ncontiennent que des clés plus grandes.\n"
        }
      ],
      "explanation": "Le coût des opérations d'un arbre binaire de recherche se lit sur\nsa hauteur, et la hauteur dépend de l'équilibre."
    },
    {
      "id": "q34",
      "difficulty": 1,
      "skills": [
        "definition",
        "sous-arbre",
        "propriete"
      ],
      "title": "Les sous-arbres d'un arbre binaire de recherche",
      "partie": "definition",
      "statement": "Le sous-arbre droit d'un arbre binaire de recherche est-il\nlui-même un arbre binaire de recherche ?",
      "options": [
        {
          "text": "Oui, tout sous-arbre d'un arbre binaire de recherche en est un",
          "correct": true,
          "feedback": "Bonne réponse : la propriété d'ordre s'applique à chaque nœud,\ndonc à la racine du sous-arbre droit comme à toutes les autres.\nC'est ce qui permet les algorithmes récursifs.\n"
        },
        {
          "text": "Non, seul l'arbre entier respecte la propriété d'ordre",
          "correct": false,
          "feedback": "Erreur : la propriété est locale à chaque nœud, elle vaut dans\ntout sous-arbre.\n"
        },
        {
          "text": "Oui, sauf s'il est réduit à une feuille, qui n'a pas d'ordre",
          "correct": false,
          "feedback": "Erreur : une feuille est un arbre binaire de recherche à un\nseul nœud.\n"
        },
        {
          "text": "Non, ses clés étant toutes plus grandes que la racine",
          "correct": false,
          "feedback": "Erreur : être plus grandes que la racine n'empêche pas ces\nclés d'être ordonnées entre elles.\n"
        }
      ],
      "explanation": "La définition récursive d'un arbre binaire de recherche impose la\npropriété à chaque nœud : chaque sous-arbre la satisfait."
    },
    {
      "id": "q35",
      "difficulty": 2,
      "skills": [
        "definition",
        "propriete",
        "piege",
        "verification"
      ],
      "title": "Une clé mal placée malgré l'ordre local",
      "partie": "definition",
      "statement": "La racine porte $8$, son fils gauche porte $3$, et ce fils\ngauche a pour fils droit $9$. Cet arbre est-il un arbre binaire\nde recherche ?",
      "options": [
        {
          "text": "Non, $9$ est dans le sous-arbre gauche de $8$ mais lui est supérieur",
          "correct": true,
          "feedback": "Bonne réponse : $9 > 3$, l'ordre local est respecté, mais\ntoute clé du sous-arbre gauche de $8$ doit être inférieure à\n$8$. La propriété porte sur des sous-arbres entiers, pas\nseulement sur les enfants directs.\n"
        },
        {
          "text": "Oui, chaque enfant droit étant plus grand que son parent direct",
          "correct": false,
          "feedback": "Erreur : vérifier chaque nœud avec son seul parent ne suffit\npas.\n"
        },
        {
          "text": "Non, $3$ ne devrait pas avoir d'enfant droit, seulement un gauche",
          "correct": false,
          "feedback": "Erreur : un enfant droit de $3$ est permis, à condition d'être\ncompris entre $3$ et $8$.\n"
        },
        {
          "text": "Non, $8$ devrait être la plus petite clé, étant la racine",
          "correct": false,
          "feedback": "Erreur : la racine n'a aucune raison d'être la plus petite\nclé.\n"
        }
      ],
      "explanation": "La propriété d'ordre est globale : toutes les clés du sous-arbre\ngauche sont inférieures à la racine, toutes celles du droit\nsupérieures.",
      "variants": [
        {
          "statement": "La racine porte $8$, son fils gauche porte $3$, et ce fils\ngauche a pour fils droit $9$. Cet arbre est-il un arbre binaire\nde recherche ?",
          "options": [
            {
              "text": "Non, $9$ est dans le sous-arbre gauche de $8$ mais lui est supérieur",
              "correct": true,
              "feedback": "Bonne réponse : $9 > 3$, l'ordre local est respecté, mais\ntoute clé du sous-arbre gauche de $8$ doit être inférieure à\n$8$. La propriété porte sur des sous-arbres entiers, pas\nseulement sur les enfants directs.\n"
            },
            {
              "text": "Oui, chaque enfant droit étant plus grand que son parent direct",
              "correct": false,
              "feedback": "Erreur : vérifier chaque nœud avec son seul parent ne suffit\npas.\n"
            },
            {
              "text": "Non, $3$ ne devrait pas avoir d'enfant droit, seulement un gauche",
              "correct": false,
              "feedback": "Erreur : un enfant droit de $3$ est permis, à condition d'être\ncompris entre $3$ et $8$.\n"
            },
            {
              "text": "Non, $8$ devrait être la plus petite clé, étant la racine",
              "correct": false,
              "feedback": "Erreur : la racine n'a aucune raison d'être la plus petite\nclé.\n"
            }
          ],
          "explanation": "La propriété d'ordre est globale : toutes les clés du sous-arbre\ngauche sont inférieures à la racine, toutes celles du droit\nsupérieures."
        },
        {
          "statement": "La racine porte $10$, son fils gauche porte $4$, et ce fils\ngauche a pour fils droit $12$. Cet arbre est-il un arbre binaire\nde recherche ?",
          "options": [
            {
              "text": "Non, $12$ est dans le sous-arbre gauche de $10$ mais lui est supérieur",
              "correct": true,
              "feedback": "Bonne réponse : $12 > 4$, l'ordre local est respecté, mais\ntoute clé du sous-arbre gauche de $10$ doit être inférieure à\n$10$. La propriété porte sur des sous-arbres entiers, pas\nseulement sur les enfants directs.\n"
            },
            {
              "text": "Oui, chaque enfant droit étant plus grand que son parent direct",
              "correct": false,
              "feedback": "Erreur : vérifier chaque nœud avec son seul parent ne suffit\npas.\n"
            },
            {
              "text": "Non, $4$ ne devrait pas avoir d'enfant droit, seulement un gauche",
              "correct": false,
              "feedback": "Erreur : un enfant droit de $4$ est permis, à condition d'être\ncompris entre $4$ et $10$.\n"
            },
            {
              "text": "Non, $10$ devrait être la plus petite clé, étant la racine",
              "correct": false,
              "feedback": "Erreur : la racine n'a aucune raison d'être la plus petite\nclé.\n"
            }
          ],
          "explanation": "La propriété d'ordre est globale : toutes les clés du sous-arbre\ngauche sont inférieures à la racine, toutes celles du droit\nsupérieures."
        },
        {
          "statement": "La racine porte $20$, son fils gauche porte $7$, et ce fils\ngauche a pour fils droit $25$. Cet arbre est-il un arbre binaire\nde recherche ?",
          "options": [
            {
              "text": "Non, $25$ est dans le sous-arbre gauche de $20$ mais lui est supérieur",
              "correct": true,
              "feedback": "Bonne réponse : $25 > 7$, l'ordre local est respecté, mais\ntoute clé du sous-arbre gauche de $20$ doit être inférieure à\n$20$. La propriété porte sur des sous-arbres entiers, pas\nseulement sur les enfants directs.\n"
            },
            {
              "text": "Oui, chaque enfant droit étant plus grand que son parent direct",
              "correct": false,
              "feedback": "Erreur : vérifier chaque nœud avec son seul parent ne suffit\npas.\n"
            },
            {
              "text": "Non, $7$ ne devrait pas avoir d'enfant droit, seulement un gauche",
              "correct": false,
              "feedback": "Erreur : un enfant droit de $7$ est permis, à condition d'être\ncompris entre $7$ et $20$.\n"
            },
            {
              "text": "Non, $20$ devrait être la plus petite clé, étant la racine",
              "correct": false,
              "feedback": "Erreur : la racine n'a aucune raison d'être la plus petite\nclé.\n"
            }
          ],
          "explanation": "La propriété d'ordre est globale : toutes les clés du sous-arbre\ngauche sont inférieures à la racine, toutes celles du droit\nsupérieures."
        }
      ]
    },
    {
      "id": "q36",
      "difficulty": 3,
      "skills": [
        "definition",
        "denombrement",
        "formes"
      ],
      "title": "Le nombre d'arbres binaires de recherche possibles",
      "partie": "definition",
      "statement": "Combien d'arbres binaires de recherche différents peut-on former\navec les clés $1$ à $3$ ?",
      "options": [
        {
          "text": "$5$, en distinguant selon la racine",
          "correct": true,
          "feedback": "Bonne réponse : on choisit la racine, puis une forme pour les\nclés plus petites et une pour les plus grandes : deux formes avec $1$ à la racine, une avec $2$, deux avec $3$, soit\n$5$.\n"
        },
        {
          "text": "$6$, un par ordre d'insertion",
          "correct": false,
          "feedback": "Erreur : des ordres d'insertion différents peuvent donner le\nmême arbre.\n"
        },
        {
          "text": "$3$, un par choix de racine",
          "correct": false,
          "feedback": "Erreur : une fois la racine choisie, les sous-arbres ont encore\nplusieurs formes.\n"
        },
        {
          "text": "$4$, un par répartition gauche ou droite",
          "correct": false,
          "feedback": "Erreur : la place d'une clé n'est pas un simple choix gauche\nou droite indépendant des autres.\n"
        }
      ],
      "explanation": "Le nombre $C(n)$ d'arbres binaires de recherche à $n$ clés vérifie\n$C(n) = C(0)C(n-1) + C(1)C(n-2) + \\cdots + C(n-1)C(0)$, selon la\nracine choisie : $1, 2, 5, 14, 42, \\ldots$",
      "variants": [
        {
          "statement": "Combien d'arbres binaires de recherche différents peut-on former\navec les clés $1$ à $3$ ?",
          "options": [
            {
              "text": "$5$, en distinguant selon la racine",
              "correct": true,
              "feedback": "Bonne réponse : on choisit la racine, puis une forme pour les\nclés plus petites et une pour les plus grandes : deux formes avec $1$ à la racine, une avec $2$, deux avec $3$, soit\n$5$.\n"
            },
            {
              "text": "$6$, un par ordre d'insertion",
              "correct": false,
              "feedback": "Erreur : des ordres d'insertion différents peuvent donner le\nmême arbre.\n"
            },
            {
              "text": "$3$, un par choix de racine",
              "correct": false,
              "feedback": "Erreur : une fois la racine choisie, les sous-arbres ont encore\nplusieurs formes.\n"
            },
            {
              "text": "$4$, un par répartition gauche ou droite",
              "correct": false,
              "feedback": "Erreur : la place d'une clé n'est pas un simple choix gauche\nou droite indépendant des autres.\n"
            }
          ],
          "explanation": "Le nombre $C(n)$ d'arbres binaires de recherche à $n$ clés vérifie\n$C(n) = C(0)C(n-1) + C(1)C(n-2) + \\cdots + C(n-1)C(0)$, selon la\nracine choisie : $1, 2, 5, 14, 42, \\ldots$"
        },
        {
          "statement": "Combien d'arbres binaires de recherche différents peut-on former\navec les clés $1$ à $4$ ?",
          "options": [
            {
              "text": "$14$, en distinguant selon la racine",
              "correct": true,
              "feedback": "Bonne réponse : on choisit la racine, puis une forme pour les\nclés plus petites et une pour les plus grandes : $5 + 2 + 2 + 5$ selon la clé choisie comme racine, soit\n$14$.\n"
            },
            {
              "text": "$24$, un par ordre d'insertion",
              "correct": false,
              "feedback": "Erreur : des ordres d'insertion différents peuvent donner le\nmême arbre.\n"
            },
            {
              "text": "$4$, un par choix de racine",
              "correct": false,
              "feedback": "Erreur : une fois la racine choisie, les sous-arbres ont encore\nplusieurs formes.\n"
            },
            {
              "text": "$8$, un par répartition gauche ou droite",
              "correct": false,
              "feedback": "Erreur : la place d'une clé n'est pas un simple choix gauche\nou droite indépendant des autres.\n"
            }
          ],
          "explanation": "Le nombre $C(n)$ d'arbres binaires de recherche à $n$ clés vérifie\n$C(n) = C(0)C(n-1) + C(1)C(n-2) + \\cdots + C(n-1)C(0)$, selon la\nracine choisie : $1, 2, 5, 14, 42, \\ldots$"
        },
        {
          "statement": "Combien d'arbres binaires de recherche différents peut-on former\navec les clés $1$ à $5$ ?",
          "options": [
            {
              "text": "$42$, en distinguant selon la racine",
              "correct": true,
              "feedback": "Bonne réponse : on choisit la racine, puis une forme pour les\nclés plus petites et une pour les plus grandes : $14 + 5 + 4 + 5 + 14$ selon la clé choisie comme racine, soit\n$42$.\n"
            },
            {
              "text": "$120$, un par ordre d'insertion",
              "correct": false,
              "feedback": "Erreur : des ordres d'insertion différents peuvent donner le\nmême arbre.\n"
            },
            {
              "text": "$5$, un par choix de racine",
              "correct": false,
              "feedback": "Erreur : une fois la racine choisie, les sous-arbres ont encore\nplusieurs formes.\n"
            },
            {
              "text": "$16$, un par répartition gauche ou droite",
              "correct": false,
              "feedback": "Erreur : la place d'une clé n'est pas un simple choix gauche\nou droite indépendant des autres.\n"
            }
          ],
          "explanation": "Le nombre $C(n)$ d'arbres binaires de recherche à $n$ clés vérifie\n$C(n) = C(0)C(n-1) + C(1)C(n-2) + \\cdots + C(n-1)C(0)$, selon la\nracine choisie : $1, 2, 5, 14, 42, \\ldots$"
        }
      ]
    },
    {
      "id": "q37",
      "difficulty": 1,
      "skills": [
        "definition",
        "parcours",
        "ordre-decroissant"
      ],
      "title": "Le parcours droite, nœud, gauche",
      "partie": "definition",
      "statement": "Sur un arbre binaire de recherche, on parcourt récursivement le\nsous-arbre droit, puis le nœud, puis le sous-arbre gauche.\nQu'obtient-on ?",
      "options": [
        {
          "text": "Les clés dans l'ordre décroissant",
          "correct": true,
          "feedback": "Bonne réponse : c'est le parcours infixe inversé ; les clés les\nplus grandes, à droite, sortent en premier.\n"
        },
        {
          "text": "Les clés dans l'ordre croissant",
          "correct": false,
          "feedback": "Erreur : l'ordre croissant vient du parcours gauche, nœud,\ndroit.\n"
        },
        {
          "text": "Les clés dans l'ordre d'insertion",
          "correct": false,
          "feedback": "Erreur : aucun parcours ne restitue l'ordre d'insertion.\n"
        },
        {
          "text": "Les feuilles seulement, de droite à gauche",
          "correct": false,
          "feedback": "Erreur : tous les nœuds sont visités, pas seulement les\nfeuilles.\n"
        }
      ],
      "explanation": "Inverser gauche et droite dans le parcours infixe inverse l'ordre\nde sortie des clés."
    },
    {
      "id": "q38",
      "difficulty": 2,
      "skills": [
        "operations",
        "recherche",
        "iteratif",
        "code"
      ],
      "title": "Une recherche écrite avec une boucle",
      "partie": "operations",
      "statement": "Quelle ligne complète cette recherche itérative de `x` dans un\narbre binaire de recherche de nœuds `Noeud` ?\n```python\ndef contient(racine, x):\n    noeud = racine\n    while noeud is not None:\n        if x == noeud.valeur:\n            return True\n        # ligne à compléter\n    return False\n```",
      "options": [
        {
          "text": "`noeud = noeud.gauche if x < noeud.valeur else noeud.droit`",
          "correct": true,
          "feedback": "Bonne réponse : une clé plus petite ne peut être qu'à gauche,\nune plus grande qu'à droite ; on descend d'un niveau à chaque\ntour.\n"
        },
        {
          "text": "`noeud = noeud.droit if x < noeud.valeur else noeud.gauche`",
          "correct": false,
          "feedback": "Erreur : les côtés sont inversés, la recherche manquerait les\nclés présentes.\n"
        },
        {
          "text": "`noeud = noeud.gauche`, la clé étant toujours à gauche",
          "correct": false,
          "feedback": "Erreur : toujours descendre à gauche ne trouve que les clés de\nla branche gauche.\n"
        },
        {
          "text": "`noeud = racine`, pour repartir du haut à chaque tour",
          "correct": false,
          "feedback": "Erreur : revenir à la racine ferait boucler sans fin.\n"
        }
      ],
      "explanation": "La version itérative suit le même chemin que la version récursive,\nen remplaçant l'appel par une mise à jour de `noeud`."
    },
    {
      "id": "q39",
      "difficulty": 3,
      "skills": [
        "operations",
        "suppression",
        "feuille"
      ],
      "title": "Supprimer une feuille",
      "partie": "operations",
      "statement": "Comment supprimer une clé située sur une feuille d'un arbre\nbinaire de recherche, sans casser la propriété d'ordre ?",
      "options": [
        {
          "text": "Remplacer par `None` le lien que son parent tient vers elle",
          "correct": true,
          "feedback": "Bonne réponse : la feuille n'a pas d'enfant, la retirer ne\ndéplace aucune autre clé ; l'ordre des clés restantes est\ninchangé.\n"
        },
        {
          "text": "Remplacer sa valeur par celle de la racine, puis supprimer la racine",
          "correct": false,
          "feedback": "Erreur : la valeur de la racine n'a rien à faire à cet endroit\nde l'arbre.\n"
        },
        {
          "text": "Décaler toutes les clés plus grandes d'un cran vers la gauche",
          "correct": false,
          "feedback": "Erreur : un arbre n'est pas un tableau, rien ne se décale.\n"
        },
        {
          "text": "Mettre sa valeur à `None` en laissant le nœud dans l'arbre",
          "correct": false,
          "feedback": "Erreur : un nœud sans valeur fausserait les comparaisons et les\nparcours.\n"
        }
      ],
      "explanation": "La suppression d'une feuille est le cas simple ; la suppression\nd'un nœud à deux enfants demande de le remplacer par une clé\nvoisine."
    },
    {
      "id": "q40",
      "difficulty": 3,
      "skills": [
        "operations",
        "suppression",
        "successeur"
      ],
      "title": "Supprimer un nœud à deux enfants",
      "partie": "operations",
      "statement": "On veut supprimer une clé dont le nœud a deux enfants. Par quelle\nclé la remplacer pour conserver la propriété d'ordre ?",
      "options": [
        {
          "text": "La plus petite clé de son sous-arbre droit",
          "correct": true,
          "feedback": "Bonne réponse : cette clé est plus grande que tout le\nsous-arbre gauche et plus petite que le reste du sous-arbre\ndroit ; elle prend la place sans rien déranger, et son ancien\nnœud, qui n'a pas d'enfant gauche, s'enlève facilement. La plus\ngrande clé du sous-arbre gauche convient aussi.\n"
        },
        {
          "text": "La clé de la racine, en descendant le reste",
          "correct": false,
          "feedback": "Erreur : la racine n'est en général ni plus grande que le\nsous-arbre gauche ni plus petite que le droit.\n"
        },
        {
          "text": "N'importe quelle feuille de l'arbre, au choix",
          "correct": false,
          "feedback": "Erreur : une feuille quelconque n'a aucune raison d'être\ncomprise entre les deux sous-arbres.\n"
        },
        {
          "text": "La plus grande clé de son sous-arbre droit",
          "correct": false,
          "feedback": "Erreur : elle serait plus grande que des clés restées dans le\nsous-arbre droit.\n"
        }
      ],
      "explanation": "Le remplaçant doit être compris entre tout le sous-arbre gauche et\ntout le sous-arbre droit : seuls le successeur et le prédécesseur\nconviennent."
    },
    {
      "id": "q41",
      "difficulty": 2,
      "skills": [
        "operations",
        "insertion",
        "feuille"
      ],
      "title": "La place d'une clé nouvellement insérée",
      "partie": "operations",
      "statement": "Où se retrouve une clé que l'on vient d'insérer dans un arbre\nbinaire de recherche, par l'algorithme habituel ?",
      "options": [
        {
          "text": "Sur une nouvelle feuille, au bout du chemin de recherche",
          "correct": true,
          "feedback": "Bonne réponse : l'insertion descend comme une recherche jusqu'à\nun sous-arbre vide, et y crée un nœud sans enfant.\n"
        },
        {
          "text": "À la racine, les autres nœuds descendant d'un niveau",
          "correct": false,
          "feedback": "Erreur : la racine ne change jamais lors d'une insertion\nsimple.\n"
        },
        {
          "text": "Entre deux nœuds existants, au milieu du chemin",
          "correct": false,
          "feedback": "Erreur : aucun nœud n'est déplacé ni intercalé.\n"
        },
        {
          "text": "À la place du nœud dont la clé est la plus proche",
          "correct": false,
          "feedback": "Erreur : remplacer un nœud perdrait sa clé.\n"
        }
      ],
      "explanation": "L'insertion ne modifie jamais la structure existante : elle ne\nfait qu'ajouter une feuille."
    }
  ]
}