{
  "chapter": {
    "id": "tris",
    "level": "premiere",
    "theme": "Algorithmique",
    "title": "Tris par sélection et par insertion",
    "description": "Algorithmes de tri étudiés en Première NSI conformément\nau programme officiel : tri par sélection et tri par\ninsertion. Principes, implémentations Python, invariants\nde boucle, terminaison, coût quadratique au pire,\nstabilité, comparaison.",
    "parties": [
      {
        "id": "selection",
        "title": "Tri par sélection"
      },
      {
        "id": "insertion",
        "title": "Tri par insertion"
      },
      {
        "id": "proprietes",
        "title": "Propriétés et comparaison"
      }
    ],
    "prerequisites": [],
    "references": []
  },
  "questions": [
    {
      "id": "q01",
      "difficulty": 1,
      "skills": [
        "definition"
      ],
      "title": "Qu'est-ce qu'un tri ?",
      "partie": "proprietes",
      "statement": "Que signifie « **trier** une liste » en informatique ?",
      "options": [
        {
          "text": "Réorganiser ses éléments selon un ordre défini",
          "correct": true,
          "feedback": "Bonne réponse : un tri produit une\n**permutation** de la liste d'origine\nrespectant un ordre (croissant, décroissant,\nalphabétique, etc.).\n"
        },
        {
          "text": "Supprimer les doublons",
          "correct": false,
          "feedback": "Erreur : trier ne supprime pas les doublons.\nPour cela, il faut une étape séparée, par\nexemple un parcours qui ne recopie dans une\nnouvelle liste que les valeurs pas encore\nvues.\n"
        },
        {
          "text": "Convertir les éléments en chaînes",
          "correct": false,
          "feedback": "Erreur : aucun changement de type.\n"
        },
        {
          "text": "La découper en plusieurs morceaux de tailles égales",
          "correct": false,
          "feedback": "Erreur : c'est le découpage, pas le tri.\n"
        }
      ],
      "explanation": "Trier permet ensuite des opérations efficaces\n(recherche dichotomique, médiane, fusion).\nAu programme de Première : tri par **sélection**\net tri par **insertion**."
    },
    {
      "id": "q02",
      "difficulty": 1,
      "skills": [
        "tri-selection-principe"
      ],
      "title": "Tri par sélection : principe",
      "partie": "selection",
      "statement": "Quel est le principe du **tri par sélection** ?",
      "options": [
        {
          "text": "Couper la liste en deux et trier chaque moitié",
          "correct": false,
          "feedback": "Erreur : couper la liste en deux n'est pas sélectionner un\nminimum. Le tri par sélection ne découpe rien : il cherche le plus\npetit élément de la partie non triée.\n"
        },
        {
          "text": "Insérer chaque élément à sa place dans la partie déjà triée",
          "correct": false,
          "feedback": "Erreur : c'est le tri par **insertion**.\n"
        },
        {
          "text": "Sélectionner le minimum non trié et le placer en tête du reste",
          "correct": true,
          "feedback": "Bonne réponse : à chaque étape, on cherche\nle minimum du sous-tableau non trié et on\nl'échange avec le premier élément de cette\npartie.\n"
        },
        {
          "text": "Comparer systématiquement chaque paire d'éléments voisins adjacents",
          "correct": false,
          "feedback": "Erreur : comparer des voisins deux à deux n'est pas chercher le\nminimum de tout le reste de la liste.\n"
        }
      ],
      "explanation": "Sélection : « je cherche le min du non trié, je\nle mets en tête de la partie non triée, je\nrecommence sur le reste ». Simple et systématique."
    },
    {
      "id": "q03",
      "difficulty": 1,
      "skills": [
        "tri-insertion-principe"
      ],
      "title": "Tri par insertion : principe",
      "partie": "insertion",
      "statement": "Quel est le principe du **tri par insertion** ?",
      "options": [
        {
          "text": "Insérer chaque élément à sa place dans la partie déjà triée",
          "correct": true,
          "feedback": "Bonne réponse : on parcourt la liste de\ngauche à droite ; pour chaque élément, on\nle décale vers la gauche tant qu'il est plus\npetit que son voisin de gauche.\n"
        },
        {
          "text": "Compter le nombre d'occurrences",
          "correct": false,
          "feedback": "Erreur : compter les occurrences d'une valeur ne réordonne pas la\nliste. Le tri par insertion place chaque élément à sa place dans\nla partie déjà triée.\n"
        },
        {
          "text": "Sélectionner le minimum et le placer en tête",
          "correct": false,
          "feedback": "Erreur : c'est le tri par **sélection**.\n"
        },
        {
          "text": "Inverser complètement l'ordre de tous les éléments de la liste",
          "correct": false,
          "feedback": "Erreur : aucune relation avec un tri.\n"
        }
      ],
      "explanation": "C'est exactement comme on trie une main de\ncartes : on prend une carte, on l'insère à sa\nplace dans le paquet déjà trié."
    },
    {
      "id": "q04",
      "difficulty": 1,
      "skills": [
        "echange"
      ],
      "title": "Échange Python",
      "partie": "selection",
      "statement": "Quelle est la façon la plus simple d'**échanger deux éléments** d'une liste en Python ?",
      "options": [
        {
          "text": "`tmp = liste[i]; liste[i] = liste[j]; liste[j] = tmp`",
          "correct": false,
          "feedback": "Code correct mais verbeux. Python offre\nplus simple.\n"
        },
        {
          "text": "`liste.swap(i, j)`",
          "correct": false,
          "feedback": "Erreur : la méthode `.swap` n'existe pas\nsur les listes Python.\n"
        },
        {
          "text": "`liste[i] = liste[j]`",
          "correct": false,
          "feedback": "Erreur : on perd la valeur originale en\n`liste[i]`.\n"
        },
        {
          "text": "`liste[i], liste[j] = liste[j], liste[i]`",
          "correct": true,
          "feedback": "Bonne réponse : affectation simultanée,\nsyntaxe pythonique. Python crée un tuple\ntemporaire `(liste[j], liste[i])` puis\ndéballe.\n"
        }
      ],
      "explanation": "L'affectation simultanée est utilisée dans les\ntris classiques. Compacte et lisible."
    },
    {
      "id": "q05",
      "difficulty": 1,
      "skills": [
        "complexite"
      ],
      "title": "Coût au pire cas",
      "partie": "proprietes",
      "statement": "Quel est le **coût** au pire cas du tri par\nsélection et du tri par insertion sur une liste\nde longueur n ?",
      "options": [
        {
          "text": "Logarithmique",
          "correct": false,
          "feedback": "Erreur : aucun tri ne peut être logarithmique, il faut au moins\nexaminer les n éléments une fois.\n"
        },
        {
          "text": "Constant (indépendant de n)",
          "correct": false,
          "feedback": "Erreur : aucun algorithme ne trie en temps\nconstant.\n"
        },
        {
          "text": "Quadratique (proportionnel à n²)",
          "correct": true,
          "feedback": "Bonne réponse : les deux tris sont\n**quadratiques** au pire à cause d'une\n**double boucle** sur la liste. Pour\nn = 1000, on fait ~ 10⁶ opérations.\n"
        },
        {
          "text": "Linéaire (proportionnel à n)",
          "correct": false,
          "feedback": "Erreur : trop optimiste. La double boucle\nimpose plus.\n"
        }
      ],
      "explanation": "Le coût quadratique vient de la double boucle : pour chacun des n\néléments, on parcourt une partie de la liste. Doubler la taille de\nla liste multiplie donc le temps de calcul par quatre environ."
    },
    {
      "id": "q06",
      "difficulty": 1,
      "skills": [
        "tri-en-place"
      ],
      "title": "Tri en place",
      "partie": "proprietes",
      "statement": "Que signifie « tri **en place** » ?",
      "options": [
        {
          "text": "Le tri se fait sur place dans le disque dur",
          "correct": false,
          "feedback": "Erreur : aucune relation avec le stockage\nphysique.\n"
        },
        {
          "text": "Le tri remplace les valeurs par leurs indices",
          "correct": false,
          "feedback": "Erreur : le tri ne modifie que l'ordre, pas\nles valeurs.\n"
        },
        {
          "text": "Le tri ne fonctionne que sur des listes courtes",
          "correct": false,
          "feedback": "Erreur : aucune restriction de taille.\n"
        },
        {
          "text": "Le tri ne crée pas de nouvelle liste : il modifie la liste d'origine",
          "correct": true,
          "feedback": "Bonne réponse : un tri en place utilise une\nquantité de mémoire **constante**\n(indépendante de n), juste quelques\nvariables temporaires. Sélection et\ninsertion sont des tris en place.\n"
        }
      ],
      "explanation": "Un tri **non en place** crée une copie triée\n(par exemple `sorted(liste)` en Python). Avec\n`liste.sort()`, on trie en place."
    },
    {
      "id": "q07",
      "difficulty": 1,
      "skills": [
        "meilleur-cas-insertion"
      ],
      "title": "Tri par insertion : meilleur cas",
      "partie": "insertion",
      "statement": "Quel est le meilleur cas pour le **tri par insertion** ?",
      "options": [
        {
          "text": "Liste déjà triée",
          "correct": true,
          "feedback": "Bonne réponse : si la liste est déjà triée,\nchaque élément est déjà à sa place ; on ne\nfait que vérifier (un seul test par\nélément). Coût linéaire (n - 1\ncomparaisons).\n"
        },
        {
          "text": "Liste de longueur impaire",
          "correct": false,
          "feedback": "Erreur : la parité de la longueur n'a\naucune influence.\n"
        },
        {
          "text": "Liste mélangée aléatoirement",
          "correct": false,
          "feedback": "Erreur : c'est le cas moyen, de coût\nquadratique (chaque élément remonte en\nmoyenne la moitié de la partie triée).\n"
        },
        {
          "text": "Liste triée à l'envers",
          "correct": false,
          "feedback": "Erreur : c'est au contraire le **pire cas**\npour insertion (chaque élément remonte tout\nà fait à gauche).\n"
        }
      ],
      "explanation": "Cette propriété fait du tri par insertion un\nbon choix pour les listes **presque triées**\n(par exemple un fichier journal triable au fil\nde l'eau)."
    },
    {
      "id": "q08",
      "difficulty": 1,
      "skills": [
        "tri-selection",
        "trace"
      ],
      "title": "Trace tri par sélection",
      "partie": "selection",
      "statement": "On trie `[4, 1, 3]` par tri par sélection\n(croissant). Que vaut la liste après la\n**première** passe ?",
      "options": [
        {
          "text": "`[1, 3, 4]`",
          "correct": false,
          "feedback": "Erreur : c'est le résultat **final**, pas\naprès une passe.\n"
        },
        {
          "text": "`[1, 4, 3]`",
          "correct": true,
          "feedback": "Bonne réponse : on cherche le min de la\nliste entière (= 1, indice 1), on l'échange\navec `liste[0]`. Résultat : `[1, 4, 3]`.\n"
        },
        {
          "text": "`[3, 1, 4]`",
          "correct": false,
          "feedback": "Erreur : aucune permutation cohérente avec\nla sélection.\n"
        },
        {
          "text": "`[4, 1, 3]`",
          "correct": false,
          "feedback": "Erreur : la liste a bien été modifiée à la\npremière passe.\n"
        }
      ],
      "explanation": "Tri sélection passe par passe : passe 1 fixe\nl'élément en position 0 ; passe 2 fixe celui en\nposition 1 ; etc.",
      "variants": [
        {
          "statement": "On trie `[4, 1, 3]` par tri par sélection\n(croissant). Que vaut la liste après la\n**première** passe ?",
          "options": [
            {
              "text": "`[1, 3, 4]`",
              "correct": false,
              "feedback": "Erreur : c'est le résultat **final**, pas\naprès une passe.\n"
            },
            {
              "text": "`[1, 4, 3]`",
              "correct": true,
              "feedback": "Bonne réponse : on cherche le min de la\nliste entière (= 1, indice 1), on l'échange\navec `liste[0]`. Résultat : `[1, 4, 3]`.\n"
            },
            {
              "text": "`[3, 1, 4]`",
              "correct": false,
              "feedback": "Erreur : aucune permutation cohérente avec\nla sélection.\n"
            },
            {
              "text": "`[4, 1, 3]`",
              "correct": false,
              "feedback": "Erreur : la liste a bien été modifiée à la\npremière passe.\n"
            }
          ],
          "explanation": "Tri sélection passe par passe : passe 1 fixe\nl'élément en position 0 ; passe 2 fixe celui en\nposition 1 ; etc."
        },
        {
          "statement": "On trie `[7, 2, 5, 3]` par tri par sélection\n(croissant). Que vaut la liste après la\n**première** passe ?",
          "options": [
            {
              "text": "`[2, 3, 5, 7]`",
              "correct": false,
              "feedback": "Erreur : c'est le résultat **final**, pas\naprès une passe.\n"
            },
            {
              "text": "`[2, 7, 5, 3]`",
              "correct": true,
              "feedback": "Bonne réponse : on cherche le min de la\nliste entière (= 2, indice 1), on l'échange\navec `liste[0]`. Résultat : `[2, 7, 5, 3]`.\n"
            },
            {
              "text": "`[3, 5, 2, 7]`",
              "correct": false,
              "feedback": "Erreur : aucune permutation cohérente avec\nla sélection.\n"
            },
            {
              "text": "`[7, 2, 5, 3]`",
              "correct": false,
              "feedback": "Erreur : la liste a bien été modifiée à la\npremière passe.\n"
            }
          ],
          "explanation": "Tri sélection passe par passe : passe 1 fixe\nl'élément en position 0 ; passe 2 fixe celui en\nposition 1 ; etc."
        },
        {
          "statement": "On trie `[9, 4, 6]` par tri par sélection\n(croissant). Que vaut la liste après la\n**première** passe ?",
          "options": [
            {
              "text": "`[4, 6, 9]`",
              "correct": false,
              "feedback": "Erreur : c'est le résultat **final**, pas\naprès une passe.\n"
            },
            {
              "text": "`[4, 9, 6]`",
              "correct": true,
              "feedback": "Bonne réponse : on cherche le min de la\nliste entière (= 4, indice 1), on l'échange\navec `liste[0]`. Résultat : `[4, 9, 6]`.\n"
            },
            {
              "text": "`[6, 4, 9]`",
              "correct": false,
              "feedback": "Erreur : aucune permutation cohérente avec\nla sélection.\n"
            },
            {
              "text": "`[9, 4, 6]`",
              "correct": false,
              "feedback": "Erreur : la liste a bien été modifiée à la\npremière passe.\n"
            }
          ],
          "explanation": "Tri sélection passe par passe : passe 1 fixe\nl'élément en position 0 ; passe 2 fixe celui en\nposition 1 ; etc."
        }
      ]
    },
    {
      "id": "q09",
      "difficulty": 1,
      "skills": [
        "pire-cas-insertion"
      ],
      "title": "Tri par insertion : pire cas",
      "partie": "insertion",
      "statement": "Quel est le **pire cas** pour le tri par\ninsertion ?",
      "options": [
        {
          "text": "Liste triée à l'envers (décroissant)",
          "correct": true,
          "feedback": "Bonne réponse : chaque nouvel élément doit\nêtre déplacé jusqu'au début de la partie\ndéjà traitée, soit n(n-1)/2 décalages au\ntotal. Coût quadratique.\n"
        },
        {
          "text": "Liste déjà triée",
          "correct": false,
          "feedback": "Erreur : c'est le **meilleur** cas (linéaire).\n"
        },
        {
          "text": "Liste comportant de nombreuses valeurs en double",
          "correct": false,
          "feedback": "Pas spécifique : le coût dépend de l'ordre,\npas des doublons.\n"
        },
        {
          "text": "Liste entièrement vide, sans aucun élément à traiter",
          "correct": false,
          "feedback": "Pas un pire cas : coût constant (la boucle\nne s'exécute pas).\n"
        }
      ],
      "explanation": "Symétrie typique : « ordre inverse » est\nsouvent le pire cas pour les tris naïfs ;\n« déjà trié » est souvent le meilleur cas pour\nl'insertion."
    },
    {
      "id": "q11",
      "difficulty": 2,
      "skills": [
        "tri-selection-code"
      ],
      "title": "Code tri par sélection",
      "partie": "selection",
      "statement": "Quel code implémente correctement le **tri par sélection** croissant ?",
      "options": [
        {
          "text": "```python\nfor i in range(len(liste)):\n    j_min = i\n    for j in range(i + 1, len(liste) - 1):\n        if liste[j] < liste[j_min]:\n            j_min = j\n    liste[i], liste[j_min] = liste[j_min], liste[i]\n```\n",
          "correct": false,
          "feedback": "Erreur : `len(liste) - 1` exclut le dernier\nélément de la recherche du minimum. S'il est\nle plus petit, il n'est jamais déplacé :\n`[2, 3, 1]` reste `[2, 3, 1]`.\n"
        },
        {
          "text": "```python\nfor i in range(len(liste)):\n    j_min = i\n    for j in range(i + 1, len(liste)):\n        if liste[j] > liste[j_min]:\n            j_min = j\n    liste[i], liste[j_min] = liste[j_min], liste[i]\n```\n",
          "correct": false,
          "feedback": "Erreur : la comparaison est inversée\n(`>` au lieu de `<`) : la boucle interne\ncherche le **maximum**, ce code trie donc\nen ordre **décroissant**.\n"
        },
        {
          "text": "```python\nfor i in range(len(liste)):\n    j_min = i\n    for j in range(i + 1, len(liste)):\n        if liste[j] < liste[j_min]:\n            j_min = j\n    liste[i], liste[j_min] = liste[j_min], liste[i]\n```\n",
          "correct": true,
          "feedback": "Bonne réponse : double boucle ; la boucle\ninterne cherche l'indice du min ; échange\navec `liste[i]` à la fin.\n"
        },
        {
          "text": "```python\nfor i in range(len(liste) - 1):\n    if liste[i] > liste[i + 1]:\n        liste[i], liste[i + 1] = liste[i + 1], liste[i]\n```\n",
          "correct": false,
          "feedback": "Erreur : une seule passe, ne trie pas\ncomplètement.\n"
        }
      ],
      "explanation": "Schéma classique : `j_min` mémorise l'indice\ndu minimum, échange à la fin pour minimiser\nles écritures."
    },
    {
      "id": "q12",
      "difficulty": 2,
      "skills": [
        "tri-insertion-code"
      ],
      "title": "Code tri par insertion",
      "partie": "insertion",
      "statement": "Quel code implémente correctement le **tri par insertion** croissant ?",
      "options": [
        {
          "text": "```python\nfor i in range(len(liste)):\n    liste.append(min(liste))\n```\n",
          "correct": false,
          "feedback": "Erreur : on ajoute des éléments au lieu de\nréorganiser.\n"
        },
        {
          "text": "```python\nfor i in range(1, len(liste)):\n    j = i\n    while j > 0 and liste[j - 1] > liste[j]:\n        liste[j - 1], liste[j] = liste[j], liste[j - 1]\n        j -= 1\n```\n",
          "correct": true,
          "feedback": "Bonne réponse : pour chaque élément à\npartir du second, on le décale vers la\ngauche tant qu'il est plus petit que son\nvoisin gauche.\n"
        },
        {
          "text": "```python\nfor i in range(1, len(liste)):\n    j = i\n    while j > 0 and liste[j - 1] > liste[j]:\n        liste[j - 1], liste[j] = liste[j], liste[j - 1]\n```\n",
          "correct": false,
          "feedback": "Erreur : il manque le `j -= 1` dans le\n`while` : l'élément n'est remonté que\nd'une seule position, et le tri échoue\ndès qu'un élément doit remonter de plus\nd'une case (tester sur `[3, 4, 1]`).\n"
        },
        {
          "text": "```python\nfor i in range(len(liste)):\n    for j in range(i):\n        if liste[i] < liste[j]:\n            liste[i] = liste[j]\n```\n",
          "correct": false,
          "feedback": "Erreur : `liste[i] = liste[j]` écrase la\nvaleur sans la sauvegarder. La liste est\ncorrompue.\n"
        }
      ],
      "explanation": "Variante équivalente : sauvegarder\n`valeur = liste[i]`, décaler à droite les\néléments plus grands, insérer la valeur. Plus\néconome en échanges."
    },
    {
      "id": "q13",
      "difficulty": 2,
      "skills": [
        "presque-trie"
      ],
      "title": "Liste presque triée",
      "partie": "insertion",
      "statement": "Entre le **tri par insertion** et le **tri par sélection**, lequel est le plus rapide sur une\nliste « presque triée » (peu d'éléments mal\nplacés) ?",
      "options": [
        {
          "text": "Les deux sont équivalents",
          "correct": false,
          "feedback": "Erreur : leur comportement diffère\nprécisément dans le cas favorable.\nL'insertion s'adapte aux données déjà\ntriées, la sélection non.\n"
        },
        {
          "text": "Le tri par sélection, car il effectue moins d'échanges",
          "correct": false,
          "feedback": "Erreur : la sélection fait certes peu\nd'échanges, mais son nombre de\n**comparaisons** reste quadratique quel\nque soit l'état de la liste. Sur une\nliste presque triée, l'insertion (coût\nquasi linéaire) l'emporte largement.\n"
        },
        {
          "text": "Impossible à prévoir sans connaître les valeurs",
          "correct": false,
          "feedback": "Erreur : pas besoin des valeurs, on\nraisonne sur les algorithmes : l'insertion\ns'arrête dès que l'élément est à sa place,\nla sélection balaie toujours tout le reste\nde la liste.\n"
        },
        {
          "text": "Tri par insertion",
          "correct": true,
          "feedback": "Bonne réponse : sur une liste presque\ntriée, le tri par insertion est en coût\nlinéaire (peu de décalages). C'est pour\ncela qu'on le préfère sur les petites\nlistes ou les listes presque triées.\n"
        }
      ],
      "explanation": "Cette propriété explique qu'on préfère le tri par insertion sur les\npetites listes ou sur les listes presque triées."
    },
    {
      "id": "q14",
      "difficulty": 2,
      "skills": [
        "invariant-selection"
      ],
      "title": "Invariant tri par sélection",
      "partie": "selection",
      "statement": "Quel **invariant** vérifie le tri par sélection\naprès l'itération `i` de la boucle externe ?",
      "options": [
        {
          "text": "La liste reste totalement inchangée par rapport au départ",
          "correct": false,
          "feedback": "Erreur : on a fait des échanges.\n"
        },
        {
          "text": "Les `i` premiers éléments sont les plus grands",
          "correct": false,
          "feedback": "Erreur : c'est l'inverse pour un tri\ncroissant.\n"
        },
        {
          "text": "Les `i` premiers éléments sont triés et inférieurs aux suivants",
          "correct": true,
          "feedback": "Bonne réponse : c'est l'invariant clé. À la\nfin (i = n), les n premiers (= toute la\nliste) sont triés.\n"
        },
        {
          "text": "La liste est entièrement triée",
          "correct": false,
          "feedback": "Trop fort : seules les `i` premières\npositions sont triées.\n"
        }
      ],
      "explanation": "Cet invariant rend la correction du tri par\nsélection évidente. Il combine deux conditions :\n« triés » + « plus petits que les autres »."
    },
    {
      "id": "q15",
      "difficulty": 2,
      "skills": [
        "terminaison-tri"
      ],
      "title": "Terminaison",
      "partie": "proprietes",
      "statement": "Pourquoi les tris par sélection et par\ninsertion **terminent** toujours ?",
      "options": [
        {
          "text": "Parce que chaque boucle possède un variant qui décroît strictement",
          "correct": true,
          "feedback": "Bonne réponse : un `for` sur un `range`\nfini termine automatiquement (variant\nimplicite). Pour le `while` du tri par\ninsertion, `j` décroît strictement à\nchaque tour et reste minoré par $0$, donc\nla boucle s'arrête en au plus `j`\nitérations.\n"
        },
        {
          "text": "Parce que Python limite les boucles à 1000 itérations",
          "correct": false,
          "feedback": "Erreur : Python n'impose aucune telle limite.\n"
        },
        {
          "text": "Parce qu'aucun de ces deux tris n'utilise de boucle while non bornée",
          "correct": false,
          "feedback": "Erreur : le tri par insertion utilise un\nwhile.\n"
        },
        {
          "text": "Parce que les listes Python sont toujours de taille finie",
          "correct": false,
          "feedback": "Vrai mais pas une justification suffisante :\nune boucle `while` peut tourner sans fin sur\nune liste finie ; il faut prouver que les\nboucles s'arrêtent.\n"
        }
      ],
      "explanation": "Justification rigoureuse : pour chaque boucle,\nidentifier ce qui change strictement à chaque\nitération (variant) et la borne qui sera\natteinte."
    },
    {
      "id": "q16",
      "difficulty": 2,
      "skills": [
        "tri-insertion",
        "trace"
      ],
      "title": "Trace tri par insertion",
      "partie": "insertion",
      "statement": "On trie `[3, 1, 4, 1, 5]` par tri par\ninsertion croissant. Quel est l'état de la\nliste **après l'itération i = 3** ?",
      "options": [
        {
          "text": "`[3, 1, 4, 1, 5]`",
          "correct": false,
          "feedback": "Erreur : c'est la liste d'origine non\nmodifiée.\n"
        },
        {
          "text": "`[1, 1, 3, 4, 5]`",
          "correct": true,
          "feedback": "Bonne réponse. Trace : i=1 → `[1, 3, 4, 1, 5]` ;\ni=2 → `[1, 3, 4, 1, 5]` (le 4 ne bouge pas) ;\ni=3 → on insère le 1 (indice 3) à sa place\n: `[1, 1, 3, 4, 5]`.\n"
        },
        {
          "text": "`[1, 3, 4, 1, 5]`",
          "correct": false,
          "feedback": "Erreur : c'est l'état après i = 2\n(l'élément d'indice 2 a rejoint sa\nplace dans la partie triée).\n"
        },
        {
          "text": "`[1, 3, 1, 4, 5]`",
          "correct": false,
          "feedback": "Erreur : le 1 doit aller jusqu'à l'indice\n1, pas à l'indice 2.\n"
        }
      ],
      "explanation": "Méthode : à chaque itération i, l'élément\n`liste[i]` rejoint à sa bonne place la partie\ndéjà triée, formée des éléments d'indices\n$0$ à $i - 1$.",
      "variants": [
        {
          "statement": "On trie `[3, 1, 4, 1, 5]` par tri par\ninsertion croissant. Quel est l'état de la\nliste **après l'itération i = 3** ?",
          "options": [
            {
              "text": "`[3, 1, 4, 1, 5]`",
              "correct": false,
              "feedback": "Erreur : c'est la liste d'origine non\nmodifiée.\n"
            },
            {
              "text": "`[1, 1, 3, 4, 5]`",
              "correct": true,
              "feedback": "Bonne réponse. Trace : i=1 → `[1, 3, 4, 1, 5]` ;\ni=2 → `[1, 3, 4, 1, 5]` (le 4 ne bouge pas) ;\ni=3 → on insère le 1 (indice 3) à sa place\n: `[1, 1, 3, 4, 5]`.\n"
            },
            {
              "text": "`[1, 3, 4, 1, 5]`",
              "correct": false,
              "feedback": "Erreur : c'est l'état après i = 2\n(l'élément d'indice 2 a rejoint sa\nplace dans la partie triée).\n"
            },
            {
              "text": "`[1, 3, 1, 4, 5]`",
              "correct": false,
              "feedback": "Erreur : le 1 doit aller jusqu'à l'indice\n1, pas à l'indice 2.\n"
            }
          ],
          "explanation": "Méthode : à chaque itération i, l'élément\n`liste[i]` rejoint à sa bonne place la partie\ndéjà triée, formée des éléments d'indices\n$0$ à $i - 1$."
        },
        {
          "statement": "On trie `[5, 2, 6, 1, 4]` par tri par\ninsertion croissant. Quel est l'état de la\nliste **après l'itération i = 3** ?",
          "options": [
            {
              "text": "`[5, 2, 6, 1, 4]`",
              "correct": false,
              "feedback": "Erreur : c'est la liste d'origine non\nmodifiée.\n"
            },
            {
              "text": "`[1, 2, 5, 6, 4]`",
              "correct": true,
              "feedback": "Bonne réponse. Trace : i=1 → `[2, 5, 6, 1, 4]` ;\ni=2 → `[2, 5, 6, 1, 4]` (le 6 ne bouge pas) ;\ni=3 → on insère le 1 (indice 3) à sa place\n: `[1, 2, 5, 6, 4]`.\n"
            },
            {
              "text": "`[2, 5, 6, 1, 4]`",
              "correct": false,
              "feedback": "Erreur : c'est l'état après i = 2\n(l'élément d'indice 2 a rejoint sa\nplace dans la partie triée).\n"
            },
            {
              "text": "`[2, 1, 5, 6, 4]`",
              "correct": false,
              "feedback": "Erreur : le 1 doit aller jusqu'à l'indice\n0, pas à l'indice 1.\n"
            }
          ],
          "explanation": "Méthode : à chaque itération i, l'élément\n`liste[i]` rejoint à sa bonne place la partie\ndéjà triée, formée des éléments d'indices\n$0$ à $i - 1$."
        },
        {
          "statement": "On trie `[6, 3, 5, 2, 8]` par tri par\ninsertion croissant. Quel est l'état de la\nliste **après l'itération i = 3** ?",
          "options": [
            {
              "text": "`[6, 3, 5, 2, 8]`",
              "correct": false,
              "feedback": "Erreur : c'est la liste d'origine non\nmodifiée.\n"
            },
            {
              "text": "`[2, 3, 5, 6, 8]`",
              "correct": true,
              "feedback": "Bonne réponse. Trace : i=1 → `[3, 6, 5, 2, 8]` ;\ni=2 → `[3, 5, 6, 2, 8]` (le 5 passe devant le 6) ;\ni=3 → on insère le 2 (indice 3) à sa place\n: `[2, 3, 5, 6, 8]`.\n"
            },
            {
              "text": "`[3, 5, 6, 2, 8]`",
              "correct": false,
              "feedback": "Erreur : c'est l'état après i = 2\n(l'élément d'indice 2 a rejoint sa\nplace dans la partie triée).\n"
            },
            {
              "text": "`[3, 2, 5, 6, 8]`",
              "correct": false,
              "feedback": "Erreur : le 2 doit aller jusqu'à l'indice\n0, pas à l'indice 1.\n"
            }
          ],
          "explanation": "Méthode : à chaque itération i, l'élément\n`liste[i]` rejoint à sa bonne place la partie\ndéjà triée, formée des éléments d'indices\n$0$ à $i - 1$."
        }
      ]
    },
    {
      "id": "q17",
      "difficulty": 2,
      "skills": [
        "echanges-selection"
      ],
      "title": "Nombre d'échanges sélection",
      "partie": "selection",
      "statement": "Combien d'échanges (au maximum) effectue le\ntri par sélection sur une liste de longueur n ?",
      "options": [
        {
          "text": "`log n`",
          "correct": false,
          "feedback": "Erreur : pas de mécanisme dichotomique.\n"
        },
        {
          "text": "`n - 1`",
          "correct": true,
          "feedback": "Bonne réponse : un échange par itération\nde la boucle externe. Quel que soit l'ordre\ninitial, on fait au plus n - 1 échanges\n(parfois on évite l'échange si j_min = i,\nmais pour le pire cas, c'est n - 1).\n"
        },
        {
          "text": "`n × (n - 1) / 2`",
          "correct": false,
          "feedback": "Erreur : c'est l'ordre de grandeur des\n**comparaisons**, pas des échanges.\n"
        },
        {
          "text": "`n`",
          "correct": false,
          "feedback": "Erreur : la dernière itération est inutile.\n"
        }
      ],
      "explanation": "Caractéristique remarquable du tri par\nsélection : très peu d'échanges, indépendamment\nde l'ordre initial. Avantageux quand les\nécritures sont coûteuses (mémoire flash)."
    },
    {
      "id": "q18",
      "difficulty": 2,
      "skills": [
        "comparaison-selection-insertion"
      ],
      "title": "Sélection vs insertion",
      "partie": "proprietes",
      "statement": "Sur une liste **déjà triée** de 1000 éléments,\nquel tri est le plus rapide ?",
      "options": [
        {
          "text": "Aucun ne fonctionne",
          "correct": false,
          "feedback": "Les deux algorithmes sont\nparfaitement corrects ; ils\nfiniront par trier la liste.\nLa question portait sur leur\nperformance comparée, et le\ntri par insertion est très\nrapide sur une liste presque\ntriée.\n"
        },
        {
          "text": "Le tri par sélection",
          "correct": false,
          "feedback": "Erreur : il fait quand même le coût\nquadratique (comparaisons), même si peu\nd'échanges.\n"
        },
        {
          "text": "Les deux sont équivalents",
          "correct": false,
          "feedback": "Erreur : différence d'ordre de grandeur sur\nce cas.\n"
        },
        {
          "text": "Le tri par insertion",
          "correct": true,
          "feedback": "Bonne réponse : sur une liste déjà triée,\nl'insertion est en coût linéaire (~ n\ncomparaisons, aucun décalage). La sélection\nreste quadratique.\n"
        }
      ],
      "explanation": "Choix selon le cas pratique : sélection si\nles écritures sont coûteuses (peu d'échanges),\ninsertion si les données arrivent presque\ntriées."
    },
    {
      "id": "q19",
      "difficulty": 2,
      "skills": [
        "tri-prealable"
      ],
      "title": "Trier puis chercher",
      "partie": "proprietes",
      "statement": "On veut faire **plusieurs recherches**\nd'éléments dans une liste. Pourquoi peut-il\nêtre intéressant de la **trier** d'abord ?",
      "options": [
        {
          "text": "Pour économiser une quantité importante de mémoire vive",
          "correct": false,
          "feedback": "Erreur : trier ne change pas la mémoire.\n"
        },
        {
          "text": "Aucun, le tri coûte plus cher que toutes les recherches",
          "correct": false,
          "feedback": "Au contraire, dès que l'on\nfait plusieurs recherches,\ntrier une fois pour toutes\ndevient très rentable, car\nchaque recherche passe d'un\ncoût linéaire à un coût\nlogarithmique.\n"
        },
        {
          "text": "Pour utiliser ensuite la recherche dichotomique plutôt que linéaire",
          "correct": true,
          "feedback": "Bonne réponse : le tri, quadratique avec la sélection ou\nl'insertion, est un investissement amorti par de nombreuses\nrecherches dichotomiques rapides.\n"
        },
        {
          "text": "Pour rendre chaque recherche linéaire deux fois plus rapide",
          "correct": false,
          "feedback": "Erreur : trier ne change pas le coût d'une\nrecherche linéaire, qui reste\nproportionnel à la taille. Le bénéfice du\ntri préalable est de rendre la\n**dichotomie** applicable.\n"
        }
      ],
      "explanation": "Investissement initial (tri) vs économie sur\nles recherches futures. Pour une seule\nrecherche, le tri n'est pas rentable."
    },
    {
      "id": "q21",
      "difficulty": 3,
      "skills": [
        "bug-borne"
      ],
      "title": "Bug d'indice",
      "partie": "proprietes",
      "statement": "```python\nfor i in range(1, len(liste) + 1):\n    j = i\n    while j > 0 and liste[j - 1] > liste[j]:\n        liste[j - 1], liste[j] = liste[j], liste[j - 1]\n        j -= 1\n```\nPourquoi ce code (tentative de tri par\ninsertion) est-il **bogué** ?",
      "options": [
        {
          "text": "Sa complexité est trop élevée pour un tri par insertion",
          "correct": false,
          "feedback": "Erreur : la complexité (quadratique) est\ncelle attendue pour un tri par insertion ;\nle problème est ailleurs, dans une borne\nde boucle.\n"
        },
        {
          "text": "La dernière itération accède à `liste[len(liste)]`, qui n'existe pas",
          "correct": true,
          "feedback": "Bonne réponse : c'est une erreur de borne d'une unité. La borne\nexterne est `len(liste) + 1` au lieu de `len(liste)` : au dernier\ntour, `i = len(liste)` puis `j = i`, et l'accès `liste[j]` lève une\n`IndexError`. La forme correcte est `range(1, len(liste))`.\n"
        },
        {
          "text": "La fonction `range` n'accepte pas deux paramètres",
          "correct": false,
          "feedback": "Erreur : la syntaxe `range(début, fin)` est\nparfaitement valide.\n"
        },
        {
          "text": "Il n'y a aucun bug, ce code trie correctement la liste",
          "correct": false,
          "feedback": "Le code contient bien une\nerreur de borne : la boucle\nva jusqu'à `len(liste)`\ninclus, ce qui provoque un\naccès hors tableau lors de\nla dernière itération.\n"
        }
      ],
      "explanation": "Les erreurs de borne d'une unité sont très fréquentes. Il faut\ntoujours tester avec des listes simples (`[]`, `[1]`, `[1, 2]`)\npour les détecter."
    },
    {
      "id": "q22",
      "difficulty": 3,
      "skills": [
        "analyse-comparaisons"
      ],
      "title": "Nombre de comparaisons",
      "partie": "proprietes",
      "statement": "Combien de comparaisons effectue le tri par\n**sélection** sur une liste de longueur n,\nquel que soit l'ordre initial ?",
      "options": [
        {
          "text": "Environ n²/2 comparaisons (toujours)",
          "correct": true,
          "feedback": "Bonne réponse : la boucle externe fait n\nitérations, l'interne fait en moyenne n/2.\nTotal : n × n/2 = n²/2 comparaisons. **Le tri par sélection ne tire aucun parti**\nd'un ordre favorable : il fait toujours le\nmême travail.\n"
        },
        {
          "text": "Environ log n",
          "correct": false,
          "feedback": "Erreur : pas de dichotomie.\n"
        },
        {
          "text": "Environ n comparaisons",
          "correct": false,
          "feedback": "Erreur : la double boucle impose\nquadratique.\n"
        },
        {
          "text": "Aucune si la liste est déjà triée",
          "correct": false,
          "feedback": "Erreur : la sélection ne « voit » pas que la\nliste est triée. Elle parcourt quand même\ntout.\n"
        }
      ],
      "explanation": "Différence majeure : insertion s'adapte (cas\nfavorable linéaire), sélection ne s'adapte\npas. Pour de petites listes presque triées,\npréférer l'insertion."
    },
    {
      "id": "q24",
      "difficulty": 3,
      "skills": [
        "choix-tri"
      ],
      "title": "Choisir un tri",
      "partie": "proprietes",
      "statement": "Pour trier une liste de **5 éléments** dans un\nmicrocontrôleur où l'on doit **minimiser l'écriture en mémoire flash** (les écritures\nsont lentes), quel tri choisir parmi\nsélection et insertion ?",
      "options": [
        {
          "text": "Les deux, qui font autant d'échanges au pire",
          "correct": false,
          "feedback": "Erreur : au pire, le tri par sélection fait $n - 1 = 4$ échanges\nalors que le tri par insertion peut en faire\n$\\frac{n(n-1)}{2} = 10$. Ils ne se valent pas sur ce critère.\n"
        },
        {
          "text": "Tri par insertion",
          "correct": false,
          "feedback": "Erreur : peut faire jusqu'à n(n-1)/2 = 10\néchanges au pire.\n"
        },
        {
          "text": "Tri par sélection",
          "correct": true,
          "feedback": "Bonne réponse : il fait au plus n - 1 = 4\néchanges, indépendamment de l'ordre\ninitial. Optimal pour minimiser les\nécritures.\n"
        },
        {
          "text": "Aucun des deux, car chacun réécrit toute la liste à chaque passe",
          "correct": false,
          "feedback": "Erreur : aucun des deux ne réécrit toute la liste à chaque passe.\nLa sélection fait un seul échange par passe, ce qui limite les\nécritures à $n - 1 = 4$ échanges.\n"
        }
      ],
      "explanation": "Le choix d'un algorithme dépend du **contexte matériel** et des **contraintes** (mémoire,\nénergie, écritures, temps). Pas d'algorithme\nuniversel."
    },
    {
      "id": "q25",
      "difficulty": 3,
      "skills": [
        "synthese"
      ],
      "title": "Synthèse",
      "partie": "proprietes",
      "statement": "Parmi les affirmations suivantes sur les tris\nau programme (sélection, insertion), laquelle\nest **fausse** ?",
      "options": [
        {
          "text": "Le coût au pire des deux est quadratique.",
          "correct": false,
          "feedback": "Vrai : caractéristique commune.\n"
        },
        {
          "text": "Les deux tris peuvent être implémentés en place (sans liste auxiliaire).",
          "correct": false,
          "feedback": "Vrai : caractéristique commune.\n"
        },
        {
          "text": "Le tri par sélection est en coût linéaire sur une liste déjà triée.",
          "correct": true,
          "feedback": "Faux (donc bonne réponse) : même sur une liste déjà triée, le tri\npar sélection parcourt toute la partie non triée à chaque passe\npour chercher le minimum. Il fait toujours $\\frac{n(n-1)}{2}$\ncomparaisons, son coût reste quadratique.\n"
        },
        {
          "text": "Le tri par insertion est en coût linéaire sur une liste déjà triée.",
          "correct": false,
          "feedback": "Vrai : sa propriété remarquable\n(meilleur cas).\n"
        }
      ],
      "explanation": "À retenir : la sélection fait peu d'échanges (au plus $n - 1$) mais\ntoujours autant de comparaisons, quel que soit l'ordre initial.\nL'insertion s'adapte au cas favorable (coût linéaire sur une liste\ntriée) mais peut faire beaucoup d'échanges au pire."
    },
    {
      "id": "q26",
      "difficulty": 2,
      "skills": [
        "insertion-decalage"
      ],
      "title": "Tri par insertion par décalage",
      "partie": "insertion",
      "statement": "Une variante classique du tri par insertion ne\nfait **pas** d'échanges deux à deux mais un\n**décalage** suivi d'une insertion. Quel code\nmet cette idée en œuvre correctement ?",
      "options": [
        {
          "text": "```python\nfor i in range(1, len(liste)):\n    valeur = liste[i]\n    j = i\n    while j > 0 and liste[j - 1] > valeur:\n        liste[j] = liste[j - 1]\n        j -= 1\n```\n",
          "correct": false,
          "feedback": "Erreur : il manque la dernière étape\n`liste[j] = valeur`. La valeur sauvegardée\nn'est jamais réinsérée, et la position\nlibérée garde sa valeur précédente déjà\ndécalée. La liste est corrompue.\n"
        },
        {
          "text": "```python\nfor i in range(1, len(liste)):\n    valeur = liste[i]\n    for j in range(i, 0, -1):\n        liste[j] = valeur\n```\n",
          "correct": false,
          "feedback": "Erreur : on remplit toutes les positions de\n`j = i` jusqu'à `j = 1` avec la même\nvaleur. La liste finit par contenir des\ncopies multiples du même élément.\n"
        },
        {
          "text": "```python\nfor i in range(1, len(liste)):\n    valeur = liste[i]\n    j = i\n    while j > 0 and liste[j - 1] > valeur:\n        liste[j] = liste[j - 1]\n        j -= 1\n    liste[j] = valeur\n```\n",
          "correct": true,
          "feedback": "Bonne réponse : on sauvegarde la valeur\ncourante, on décale vers la droite tous les\néléments plus grands à gauche, puis on\ninsère la valeur à la position libérée. Une\nseule écriture par décalage (au lieu de deux\ndans la version par échanges), donc plus\nrapide en pratique.\n"
        },
        {
          "text": "```python\nfor i in range(1, len(liste)):\n    j = i\n    while j > 0 and liste[j - 1] > liste[j]:\n        liste[j] = liste[j - 1]\n        j -= 1\n```\n",
          "correct": false,
          "feedback": "Erreur : on n'a pas sauvegardé la valeur\nd'origine de `liste[i]` avant de la\nremplacer par `liste[j - 1]`. Dès la\npremière itération, cette valeur est\nperdue, donc l'insertion finale est\nimpossible.\n"
        }
      ],
      "explanation": "Cette variante est en général plus rapide en pratique : un décalage\ndemande une seule écriture, contre deux pour un échange."
    },
    {
      "id": "q27",
      "difficulty": 2,
      "skills": [
        "tri-selection",
        "comparaisons"
      ],
      "title": "Comparaisons précises sur exemple",
      "partie": "proprietes",
      "statement": "Combien de comparaisons (entre éléments)\neffectue le tri par **sélection** sur la liste\n`[5, 3, 8, 1]` (n = 4) ?",
      "options": [
        {
          "text": "4",
          "correct": false,
          "feedback": "Erreur : c'est le nombre d'éléments. La\ndouble boucle fait beaucoup plus de\ncomparaisons.\n"
        },
        {
          "text": "16",
          "correct": false,
          "feedback": "Erreur : ce serait `n²`, mais le tri par\nsélection fait `n(n - 1) / 2`\ncomparaisons, pas `n²`. La boucle interne\nne repart pas de zéro à chaque passe.\n"
        },
        {
          "text": "3",
          "correct": false,
          "feedback": "Erreur : ce serait le nombre d'**itérations**\nde la boucle externe (n - 1), pas le total\ndes comparaisons internes.\n"
        },
        {
          "text": "6",
          "correct": true,
          "feedback": "Bonne réponse : la formule générale est\n`(n - 1) + (n - 2) + ... + 1 = n(n - 1) / 2`,\nsoit ici `4 × 3 / 2 = 6`. Détail : passe 1 → 3 comparaisons ; passe 2 → 2 comparaisons ; passe 3 → 1 comparaison. Total : 6.\n"
        }
      ],
      "explanation": "Formule à retenir : `n(n - 1) / 2`\ncomparaisons pour le tri par sélection, **quel que soit l'ordre initial**. C'est l'ordre de\ngrandeur quadratique. Pour n = 1000 :\n499 500 comparaisons.",
      "variants": [
        {
          "statement": "Combien de comparaisons (entre éléments)\neffectue le tri par **sélection** sur la liste\n`[5, 3, 8, 1]` (n = 4) ?",
          "options": [
            {
              "text": "4",
              "correct": false,
              "feedback": "Erreur : c'est le nombre d'éléments. La\ndouble boucle fait beaucoup plus de\ncomparaisons.\n"
            },
            {
              "text": "16",
              "correct": false,
              "feedback": "Erreur : ce serait `n²`, mais le tri par\nsélection fait `n(n - 1) / 2`\ncomparaisons, pas `n²`. La boucle interne\nne repart pas de zéro à chaque passe.\n"
            },
            {
              "text": "3",
              "correct": false,
              "feedback": "Erreur : ce serait le nombre d'**itérations**\nde la boucle externe (n - 1), pas le total\ndes comparaisons internes.\n"
            },
            {
              "text": "6",
              "correct": true,
              "feedback": "Bonne réponse : la formule générale est\n`(n - 1) + (n - 2) + ... + 1 = n(n - 1) / 2`,\nsoit ici `4 × 3 / 2 = 6`. Détail : passe 1 → 3 comparaisons ; passe 2 → 2 comparaisons ; passe 3 → 1 comparaison. Total : 6.\n"
            }
          ],
          "explanation": "Formule à retenir : `n(n - 1) / 2`\ncomparaisons pour le tri par sélection, **quel que soit l'ordre initial**. C'est l'ordre de\ngrandeur quadratique. Pour n = 1000 :\n499 500 comparaisons."
        },
        {
          "statement": "Combien de comparaisons (entre éléments)\neffectue le tri par **sélection** sur la liste\n`[9, 2, 7, 4, 6]` (n = 5) ?",
          "options": [
            {
              "text": "5",
              "correct": false,
              "feedback": "Erreur : c'est le nombre d'éléments. La\ndouble boucle fait beaucoup plus de\ncomparaisons.\n"
            },
            {
              "text": "25",
              "correct": false,
              "feedback": "Erreur : ce serait `n²`, mais le tri par\nsélection fait `n(n - 1) / 2`\ncomparaisons, pas `n²`. La boucle interne\nne repart pas de zéro à chaque passe.\n"
            },
            {
              "text": "4",
              "correct": false,
              "feedback": "Erreur : ce serait le nombre d'**itérations**\nde la boucle externe (n - 1), pas le total\ndes comparaisons internes.\n"
            },
            {
              "text": "10",
              "correct": true,
              "feedback": "Bonne réponse : la formule générale est\n`(n - 1) + (n - 2) + ... + 1 = n(n - 1) / 2`,\nsoit ici `5 × 4 / 2 = 10`. Détail : passe 1 → 4 comparaisons ; passe 2 → 3 comparaisons ; passe 3 → 2 comparaisons ; passe 4 → 1 comparaison. Total : 10.\n"
            }
          ],
          "explanation": "Formule à retenir : `n(n - 1) / 2`\ncomparaisons pour le tri par sélection, **quel que soit l'ordre initial**. C'est l'ordre de\ngrandeur quadratique. Pour n = 1000 :\n499 500 comparaisons."
        },
        {
          "statement": "Combien de comparaisons (entre éléments)\neffectue le tri par **sélection** sur la liste\n`[3, 8, 1, 9, 2, 5]` (n = 6) ?",
          "options": [
            {
              "text": "6",
              "correct": false,
              "feedback": "Erreur : c'est le nombre d'éléments. La\ndouble boucle fait beaucoup plus de\ncomparaisons.\n"
            },
            {
              "text": "36",
              "correct": false,
              "feedback": "Erreur : ce serait `n²`, mais le tri par\nsélection fait `n(n - 1) / 2`\ncomparaisons, pas `n²`. La boucle interne\nne repart pas de zéro à chaque passe.\n"
            },
            {
              "text": "5",
              "correct": false,
              "feedback": "Erreur : ce serait le nombre d'**itérations**\nde la boucle externe (n - 1), pas le total\ndes comparaisons internes.\n"
            },
            {
              "text": "15",
              "correct": true,
              "feedback": "Bonne réponse : la formule générale est\n`(n - 1) + (n - 2) + ... + 1 = n(n - 1) / 2`,\nsoit ici `6 × 5 / 2 = 15`. Détail : passe 1 → 5 comparaisons ; passe 2 → 4 comparaisons ; passe 3 → 3 comparaisons ; passe 4 → 2 comparaisons ; passe 5 → 1 comparaison. Total : 15.\n"
            }
          ],
          "explanation": "Formule à retenir : `n(n - 1) / 2`\ncomparaisons pour le tri par sélection, **quel que soit l'ordre initial**. C'est l'ordre de\ngrandeur quadratique. Pour n = 1000 :\n499 500 comparaisons."
        }
      ]
    },
    {
      "id": "q29",
      "difficulty": 2,
      "skills": [
        "tri-selection",
        "trace",
        "passes"
      ],
      "title": "Trace pas-à-pas du tri par sélection",
      "partie": "selection",
      "statement": "On trie la liste `[3, 1, 4, 2]` par tri par\nsélection croissant. Quels sont les états\nsuccessifs de la liste **après chaque itération de la boucle externe** (chaque\n« passe ») ?",
      "options": [
        {
          "text": "Après passe $1$ : `[1, 3, 4, 2]`. Après\npasse $2$ : `[1, 2, 4, 3]`. Après passe\n$3$ : `[1, 2, 3, 4]`\n",
          "correct": true,
          "feedback": "Bonne réponse : à chaque passe, on\ncherche le minimum à partir de la\nposition courante et on l'échange avec\nl'élément en cette position. Passe $1$\n(position $0$) : minimum de\n`[3, 1, 4, 2]` est $1$ en position\n$1$, on échange → `[1, 3, 4, 2]`.\nPasse $2$ (position $1$) : minimum de\n`[3, 4, 2]` est $2$ en position $3$,\non échange `liste[1]` avec `liste[3]`\n→ `[1, 2, 4, 3]`. Passe $3$ (position\n$2$) : minimum de `[4, 3]` est $3$,\non échange → `[1, 2, 3, 4]`. Une éventuelle\npasse $4$, sur le dernier élément seul, ne\nchange rien.\n"
        },
        {
          "text": "Après passe $1$ : `[3, 1, 4, 2]`\n(inchangée). Après passe $2$ :\n`[1, 3, 4, 2]`. Après passe $3$ :\n`[1, 2, 4, 3]`\n",
          "correct": false,
          "feedback": "Erreur : la première passe modifie\nbien la liste en plaçant le minimum\n$1$ en position $0$. Une passe ne\nlaisse la liste inchangée que si\nl'élément en position courante est\ndéjà le minimum du sous-tableau, ce\nqui n'est pas le cas ici (la position\n$0$ contient $3$, pas $1$).\n"
        },
        {
          "text": "Après passe $1$ : `[1, 3, 4, 2]`. Après\npasse $2$ : `[1, 3, 2, 4]`. Après passe\n$3$ : `[1, 2, 3, 4]`\n",
          "correct": false,
          "feedback": "Erreur à la passe $2$ : à partir de la\nposition $1$, on cherche le minimum\nparmi `[3, 4, 2]`, qui est $2$ en\nposition $3$. On échange donc\n`liste[1]` (qui vaut $3$) avec\n`liste[3]` (qui vaut $2$), ce qui\ndonne `[1, 2, 4, 3]` et non\n`[1, 3, 2, 4]`.\n"
        },
        {
          "text": "Après passe $1$ : `[1, 2, 3, 4]`. Les\npasses suivantes ne changent rien\n",
          "correct": false,
          "feedback": "Erreur : le tri par sélection ne place\nqu'**un seul** élément à sa position\nfinale par passe (le minimum du\nsous-tableau restant). Il faut donc\nplusieurs passes successives, et la\nliste n'est triée qu'à la fin.\n"
        }
      ],
      "explanation": "Pour tracer le tri par sélection, on tient\nà jour à chaque passe : (1) la position\ncourante `pos`, (2) l'indice du minimum parmi\nles éléments d'indices `pos` à `n - 1`, (3)\nl'échange éventuel. La liste se trie de gauche\nà droite, un élément à la fois. Pour `n = 4`\néléments, $3$ passes suffisent : une quatrième\npasse, sur un seul élément, serait inutile.",
      "variants": [
        {
          "statement": "On trie la liste `[3, 1, 4, 2]` par tri par\nsélection croissant. Quels sont les états\nsuccessifs de la liste **après chaque itération de la boucle externe** (chaque\n« passe ») ?",
          "options": [
            {
              "text": "Après passe $1$ : `[1, 3, 4, 2]`. Après\npasse $2$ : `[1, 2, 4, 3]`. Après passe\n$3$ : `[1, 2, 3, 4]`\n",
              "correct": true,
              "feedback": "Bonne réponse : à chaque passe, on\ncherche le minimum à partir de la\nposition courante et on l'échange avec\nl'élément en cette position. Passe $1$\n(position $0$) : minimum de\n`[3, 1, 4, 2]` est $1$ en position\n$1$, on échange → `[1, 3, 4, 2]`.\nPasse $2$ (position $1$) : minimum de\n`[3, 4, 2]` est $2$ en position $3$,\non échange `liste[1]` avec `liste[3]`\n→ `[1, 2, 4, 3]`. Passe $3$ (position\n$2$) : minimum de `[4, 3]` est $3$,\non échange → `[1, 2, 3, 4]`. Une éventuelle\npasse $4$, sur le dernier élément seul, ne\nchange rien.\n"
            },
            {
              "text": "Après passe $1$ : `[3, 1, 4, 2]`\n(inchangée). Après passe $2$ :\n`[1, 3, 4, 2]`. Après passe $3$ :\n`[1, 2, 4, 3]`\n",
              "correct": false,
              "feedback": "Erreur : la première passe modifie\nbien la liste en plaçant le minimum\n$1$ en position $0$. Une passe ne\nlaisse la liste inchangée que si\nl'élément en position courante est\ndéjà le minimum du sous-tableau, ce\nqui n'est pas le cas ici (la position\n$0$ contient $3$, pas $1$).\n"
            },
            {
              "text": "Après passe $1$ : `[1, 3, 4, 2]`. Après\npasse $2$ : `[1, 3, 2, 4]`. Après passe\n$3$ : `[1, 2, 3, 4]`\n",
              "correct": false,
              "feedback": "Erreur à la passe $2$ : à partir de la\nposition $1$, on cherche le minimum\nparmi `[3, 4, 2]`, qui est $2$ en\nposition $3$. On échange donc\n`liste[1]` (qui vaut $3$) avec\n`liste[3]` (qui vaut $2$), ce qui\ndonne `[1, 2, 4, 3]` et non\n`[1, 3, 2, 4]`.\n"
            },
            {
              "text": "Après passe $1$ : `[1, 2, 3, 4]`. Les\npasses suivantes ne changent rien\n",
              "correct": false,
              "feedback": "Erreur : le tri par sélection ne place\nqu'**un seul** élément à sa position\nfinale par passe (le minimum du\nsous-tableau restant). Il faut donc\nplusieurs passes successives, et la\nliste n'est triée qu'à la fin.\n"
            }
          ],
          "explanation": "Pour tracer le tri par sélection, on tient\nà jour à chaque passe : (1) la position\ncourante `pos`, (2) l'indice du minimum parmi\nles éléments d'indices `pos` à `n - 1`, (3)\nl'échange éventuel. La liste se trie de gauche\nà droite, un élément à la fois. Pour `n = 4`\néléments, $3$ passes suffisent : une quatrième\npasse, sur un seul élément, serait inutile."
        },
        {
          "statement": "On trie la liste `[5, 2, 8, 1]` par tri par\nsélection croissant. Quels sont les états\nsuccessifs de la liste **après chaque itération de la boucle externe** (chaque\n« passe ») ?",
          "options": [
            {
              "text": "Après passe $1$ : `[1, 2, 8, 5]`. Après\npasse $2$ : `[1, 2, 8, 5]`. Après passe\n$3$ : `[1, 2, 5, 8]`\n",
              "correct": true,
              "feedback": "Bonne réponse : à chaque passe, on\ncherche le minimum à partir de la\nposition courante et on l'échange avec\nl'élément en cette position. Passe $1$\n(position $0$) : minimum de\n`[5, 2, 8, 1]` est $1$ en position\n$3$, on échange → `[1, 2, 8, 5]`.\nPasse $2$ (position $1$) : minimum de\n`[2, 8, 5]` est $2$ en position $1$,\non échange `liste[1]` avec `liste[1]`\n→ `[1, 2, 8, 5]`. Passe $3$ (position\n$2$) : minimum de `[8, 5]` est $5$,\non échange → `[1, 2, 5, 8]`. Une éventuelle\npasse $4$, sur le dernier élément seul, ne\nchange rien.\n"
            },
            {
              "text": "Après passe $1$ : `[5, 2, 8, 1]`\n(inchangée). Après passe $2$ :\n`[1, 2, 8, 5]`. Après passe $3$ :\n`[1, 2, 8, 5]`\n",
              "correct": false,
              "feedback": "Erreur : la première passe modifie\nbien la liste en plaçant le minimum\n$1$ en position $0$. Une passe ne\nlaisse la liste inchangée que si\nl'élément en position courante est\ndéjà le minimum du sous-tableau, ce\nqui n'est pas le cas ici (la position\n$0$ contient $5$, pas $1$).\n"
            },
            {
              "text": "Après passe $1$ : `[1, 2, 8, 5]`. Après\npasse $2$ : `[1, 2, 5, 8]`. Après passe\n$3$ : `[1, 2, 5, 8]`\n",
              "correct": false,
              "feedback": "Erreur à la passe $2$ : à partir de la\nposition $1$, on cherche le minimum\nparmi `[2, 8, 5]`, qui est $2$ en\nposition $1$. On échange donc\n`liste[1]` (qui vaut $2$) avec\n`liste[1]` (qui vaut $2$), ce qui\ndonne `[1, 2, 8, 5]` et non\n`[1, 2, 5, 8]`.\n"
            },
            {
              "text": "Après passe $1$ : `[1, 2, 5, 8]`. Les\npasses suivantes ne changent rien\n",
              "correct": false,
              "feedback": "Erreur : le tri par sélection ne place\nqu'**un seul** élément à sa position\nfinale par passe (le minimum du\nsous-tableau restant). Il faut donc\nplusieurs passes successives, et la\nliste n'est triée qu'à la fin.\n"
            }
          ],
          "explanation": "Pour tracer le tri par sélection, on tient\nà jour à chaque passe : (1) la position\ncourante `pos`, (2) l'indice du minimum parmi\nles éléments d'indices `pos` à `n - 1`, (3)\nl'échange éventuel. La liste se trie de gauche\nà droite, un élément à la fois. Pour `n = 4`\néléments, $3$ passes suffisent : une quatrième\npasse, sur un seul élément, serait inutile."
        },
        {
          "statement": "On trie la liste `[6, 4, 2, 5]` par tri par\nsélection croissant. Quels sont les états\nsuccessifs de la liste **après chaque itération de la boucle externe** (chaque\n« passe ») ?",
          "options": [
            {
              "text": "Après passe $1$ : `[2, 4, 6, 5]`. Après\npasse $2$ : `[2, 4, 6, 5]`. Après passe\n$3$ : `[2, 4, 5, 6]`\n",
              "correct": true,
              "feedback": "Bonne réponse : à chaque passe, on\ncherche le minimum à partir de la\nposition courante et on l'échange avec\nl'élément en cette position. Passe $1$\n(position $0$) : minimum de\n`[6, 4, 2, 5]` est $2$ en position\n$2$, on échange → `[2, 4, 6, 5]`.\nPasse $2$ (position $1$) : minimum de\n`[4, 6, 5]` est $4$ en position $1$,\non échange `liste[1]` avec `liste[1]`\n→ `[2, 4, 6, 5]`. Passe $3$ (position\n$2$) : minimum de `[6, 5]` est $5$,\non échange → `[2, 4, 5, 6]`. Une éventuelle\npasse $4$, sur le dernier élément seul, ne\nchange rien.\n"
            },
            {
              "text": "Après passe $1$ : `[6, 4, 2, 5]`\n(inchangée). Après passe $2$ :\n`[2, 4, 6, 5]`. Après passe $3$ :\n`[2, 4, 6, 5]`\n",
              "correct": false,
              "feedback": "Erreur : la première passe modifie\nbien la liste en plaçant le minimum\n$2$ en position $0$. Une passe ne\nlaisse la liste inchangée que si\nl'élément en position courante est\ndéjà le minimum du sous-tableau, ce\nqui n'est pas le cas ici (la position\n$0$ contient $6$, pas $2$).\n"
            },
            {
              "text": "Après passe $1$ : `[2, 4, 6, 5]`. Après\npasse $2$ : `[2, 4, 5, 6]`. Après passe\n$3$ : `[2, 4, 5, 6]`\n",
              "correct": false,
              "feedback": "Erreur à la passe $2$ : à partir de la\nposition $1$, on cherche le minimum\nparmi `[4, 6, 5]`, qui est $4$ en\nposition $1$. On échange donc\n`liste[1]` (qui vaut $4$) avec\n`liste[1]` (qui vaut $4$), ce qui\ndonne `[2, 4, 6, 5]` et non\n`[2, 4, 5, 6]`.\n"
            },
            {
              "text": "Après passe $1$ : `[2, 4, 5, 6]`. Les\npasses suivantes ne changent rien\n",
              "correct": false,
              "feedback": "Erreur : le tri par sélection ne place\nqu'**un seul** élément à sa position\nfinale par passe (le minimum du\nsous-tableau restant). Il faut donc\nplusieurs passes successives, et la\nliste n'est triée qu'à la fin.\n"
            }
          ],
          "explanation": "Pour tracer le tri par sélection, on tient\nà jour à chaque passe : (1) la position\ncourante `pos`, (2) l'indice du minimum parmi\nles éléments d'indices `pos` à `n - 1`, (3)\nl'échange éventuel. La liste se trie de gauche\nà droite, un élément à la fois. Pour `n = 4`\néléments, $3$ passes suffisent : une quatrième\npasse, sur un seul élément, serait inutile."
        }
      ]
    },
    {
      "id": "q30",
      "difficulty": 2,
      "skills": [
        "tri-insertion",
        "trace",
        "passes"
      ],
      "title": "Trace pas-à-pas du tri par insertion",
      "partie": "insertion",
      "statement": "On trie la même liste `[3, 1, 4, 2]` par\ntri par insertion croissant. Quels sont\nles états successifs **après chaque itération de la boucle externe** ?",
      "options": [
        {
          "text": "Après $i = 1$ : `[1, 3, 4, 2]`. Après\n$i = 2$ : `[1, 3, 4, 2]` (inchangée).\nAprès $i = 3$ : `[1, 2, 3, 4]`\n",
          "correct": true,
          "feedback": "Bonne réponse : à chaque itération $i$,\non prend `liste[i]` et on l'insère à sa\nplace dans la portion déjà triée, formée\ndes éléments d'indices $0$ à $i - 1$.\nPour $i = 1$, le $1$ se place avant le $3$.\nPour $i = 2$, le 4 est déjà à sa place (rien à faire).\nPour $i = 3$, le 2 remonte jusqu'à se placer entre 1 et 3, ce qui décale aussi le 3 et le 4 d'un cran.\n"
        },
        {
          "text": "Après $i = 1$ : `[3, 1, 4, 2]`\n(inchangée). Après $i = 2$ :\n`[1, 3, 4, 2]`. Après $i = 3$ :\n`[1, 3, 4, 2]`\n",
          "correct": false,
          "feedback": "Erreur : la première itération\n($i = 1$) insère le $1$ à sa place\ndans la portion `[3]`, ce qui le\nplace avant le $3$. La liste devient\ndonc `[1, 3, 4, 2]` après cette\nitération, pas inchangée.\n"
        },
        {
          "text": "Après $i = 1$ : `[1, 3, 4, 2]`. Après\n$i = 2$ : `[1, 2, 3, 4]`. Après\n$i = 3$ : `[1, 2, 3, 4]`\n",
          "correct": false,
          "feedback": "Erreur : à $i = 2$, on insère le $4$,\npas le $2$. La liste devient `[1, 3, 4, 2]`,\npas `[1, 2, 3, 4]`. C'est à $i = 3$, en\ninsérant le $2$, qu'on obtient le\ntri final.\n"
        },
        {
          "text": "Identique au tri par sélection :\n`[1, 3, 4, 2]` puis `[1, 2, 4, 3]` puis `[1, 2, 3, 4]`\n",
          "correct": false,
          "feedback": "Erreur : les deux algorithmes ne\nproduisent pas les mêmes états\nintermédiaires. Au tri par sélection,\nchaque passe place le minimum du\nreste ; au tri par insertion, chaque\npasse insère l'élément suivant à sa\nplace dans la partie triée. Les\ncomportements intermédiaires diffèrent.\n"
        }
      ],
      "explanation": "Différence remarquable avec le tri par\nsélection : une itération du tri par\ninsertion peut ne presque rien faire quand\nl'élément est déjà bien placé.\nC'est typique : si la liste est presque\ntriée, l'insertion devient quasi linéaire,\ntandis que la sélection fait toujours le\nmême travail quadratique. Cette propriété\nd'**adaptabilité** rend l'insertion\npréférable sur des données quasi-triées.",
      "variants": [
        {
          "statement": "On trie la même liste `[3, 1, 4, 2]` par\ntri par insertion croissant. Quels sont\nles états successifs **après chaque itération de la boucle externe** ?",
          "options": [
            {
              "text": "Après $i = 1$ : `[1, 3, 4, 2]`. Après\n$i = 2$ : `[1, 3, 4, 2]` (inchangée).\nAprès $i = 3$ : `[1, 2, 3, 4]`\n",
              "correct": true,
              "feedback": "Bonne réponse : à chaque itération $i$,\non prend `liste[i]` et on l'insère à sa\nplace dans la portion déjà triée, formée\ndes éléments d'indices $0$ à $i - 1$.\nPour $i = 1$, le $1$ se place avant le $3$.\nPour $i = 2$, le 4 est déjà à sa place (rien à faire).\nPour $i = 3$, le 2 remonte jusqu'à se placer entre 1 et 3, ce qui décale aussi le 3 et le 4 d'un cran.\n"
            },
            {
              "text": "Après $i = 1$ : `[3, 1, 4, 2]`\n(inchangée). Après $i = 2$ :\n`[1, 3, 4, 2]`. Après $i = 3$ :\n`[1, 3, 4, 2]`\n",
              "correct": false,
              "feedback": "Erreur : la première itération\n($i = 1$) insère le $1$ à sa place\ndans la portion `[3]`, ce qui le\nplace avant le $3$. La liste devient\ndonc `[1, 3, 4, 2]` après cette\nitération, pas inchangée.\n"
            },
            {
              "text": "Après $i = 1$ : `[1, 3, 4, 2]`. Après\n$i = 2$ : `[1, 2, 3, 4]`. Après\n$i = 3$ : `[1, 2, 3, 4]`\n",
              "correct": false,
              "feedback": "Erreur : à $i = 2$, on insère le $4$,\npas le $2$. La liste devient `[1, 3, 4, 2]`,\npas `[1, 2, 3, 4]`. C'est à $i = 3$, en\ninsérant le $2$, qu'on obtient le\ntri final.\n"
            },
            {
              "text": "Identique au tri par sélection :\n`[1, 3, 4, 2]` puis `[1, 2, 4, 3]` puis `[1, 2, 3, 4]`\n",
              "correct": false,
              "feedback": "Erreur : les deux algorithmes ne\nproduisent pas les mêmes états\nintermédiaires. Au tri par sélection,\nchaque passe place le minimum du\nreste ; au tri par insertion, chaque\npasse insère l'élément suivant à sa\nplace dans la partie triée. Les\ncomportements intermédiaires diffèrent.\n"
            }
          ],
          "explanation": "Différence remarquable avec le tri par\nsélection : une itération du tri par\ninsertion peut ne presque rien faire quand\nl'élément est déjà bien placé.\nC'est typique : si la liste est presque\ntriée, l'insertion devient quasi linéaire,\ntandis que la sélection fait toujours le\nmême travail quadratique. Cette propriété\nd'**adaptabilité** rend l'insertion\npréférable sur des données quasi-triées."
        },
        {
          "statement": "On trie la même liste `[5, 2, 8, 1]` par\ntri par insertion croissant. Quels sont\nles états successifs **après chaque itération de la boucle externe** ?",
          "options": [
            {
              "text": "Après $i = 1$ : `[2, 5, 8, 1]`. Après\n$i = 2$ : `[2, 5, 8, 1]` (inchangée).\nAprès $i = 3$ : `[1, 2, 5, 8]`\n",
              "correct": true,
              "feedback": "Bonne réponse : à chaque itération $i$,\non prend `liste[i]` et on l'insère à sa\nplace dans la portion déjà triée, formée\ndes éléments d'indices $0$ à $i - 1$.\nPour $i = 1$, le $2$ se place avant le $5$.\nPour $i = 2$, le 8 est déjà à sa place (rien à faire).\nPour $i = 3$, le 1 remonte jusqu'au début, ce qui décale le 2, le 5 et le 8 d'un cran.\n"
            },
            {
              "text": "Après $i = 1$ : `[5, 2, 8, 1]`\n(inchangée). Après $i = 2$ :\n`[2, 5, 8, 1]`. Après $i = 3$ :\n`[2, 5, 8, 1]`\n",
              "correct": false,
              "feedback": "Erreur : la première itération\n($i = 1$) insère le $2$ à sa place\ndans la portion `[5]`, ce qui le\nplace avant le $5$. La liste devient\ndonc `[2, 5, 8, 1]` après cette\nitération, pas inchangée.\n"
            },
            {
              "text": "Après $i = 1$ : `[2, 5, 8, 1]`. Après\n$i = 2$ : `[1, 2, 5, 8]`. Après\n$i = 3$ : `[1, 2, 5, 8]`\n",
              "correct": false,
              "feedback": "Erreur : à $i = 2$, on insère le $8$,\npas le $1$. La liste devient `[2, 5, 8, 1]`,\npas `[1, 2, 5, 8]`. C'est à $i = 3$, en\ninsérant le $1$, qu'on obtient le\ntri final.\n"
            },
            {
              "text": "Identique au tri par sélection :\n`[1, 2, 8, 5]` puis `[1, 2, 8, 5]` puis `[1, 2, 5, 8]`\n",
              "correct": false,
              "feedback": "Erreur : les deux algorithmes ne\nproduisent pas les mêmes états\nintermédiaires. Au tri par sélection,\nchaque passe place le minimum du\nreste ; au tri par insertion, chaque\npasse insère l'élément suivant à sa\nplace dans la partie triée. Les\ncomportements intermédiaires diffèrent.\n"
            }
          ],
          "explanation": "Différence remarquable avec le tri par\nsélection : une itération du tri par\ninsertion peut ne presque rien faire quand\nl'élément est déjà bien placé.\nC'est typique : si la liste est presque\ntriée, l'insertion devient quasi linéaire,\ntandis que la sélection fait toujours le\nmême travail quadratique. Cette propriété\nd'**adaptabilité** rend l'insertion\npréférable sur des données quasi-triées."
        },
        {
          "statement": "On trie la même liste `[6, 4, 2, 5]` par\ntri par insertion croissant. Quels sont\nles états successifs **après chaque itération de la boucle externe** ?",
          "options": [
            {
              "text": "Après $i = 1$ : `[4, 6, 2, 5]`. Après\n$i = 2$ : `[2, 4, 6, 5]`.\nAprès $i = 3$ : `[2, 4, 5, 6]`\n",
              "correct": true,
              "feedback": "Bonne réponse : à chaque itération $i$,\non prend `liste[i]` et on l'insère à sa\nplace dans la portion déjà triée, formée\ndes éléments d'indices $0$ à $i - 1$.\nPour $i = 1$, le $4$ se place avant le $6$.\nPour $i = 2$, le 2 remonte jusqu'au début.\nPour $i = 3$, le 5 se place entre 4 et 6, ce qui décale le 6 d'un cran.\n"
            },
            {
              "text": "Après $i = 1$ : `[6, 4, 2, 5]`\n(inchangée). Après $i = 2$ :\n`[4, 6, 2, 5]`. Après $i = 3$ :\n`[2, 4, 6, 5]`\n",
              "correct": false,
              "feedback": "Erreur : la première itération\n($i = 1$) insère le $4$ à sa place\ndans la portion `[6]`, ce qui le\nplace avant le $6$. La liste devient\ndonc `[4, 6, 2, 5]` après cette\nitération, pas inchangée.\n"
            },
            {
              "text": "Après $i = 1$ : `[4, 6, 2, 5]`. Après\n$i = 2$ : `[2, 4, 5, 6]`. Après\n$i = 3$ : `[2, 4, 5, 6]`\n",
              "correct": false,
              "feedback": "Erreur : à $i = 2$, on insère le $2$,\npas le $5$. La liste devient `[2, 4, 6, 5]`,\npas `[2, 4, 5, 6]`. C'est à $i = 3$, en\ninsérant le $5$, qu'on obtient le\ntri final.\n"
            },
            {
              "text": "Identique au tri par sélection :\n`[2, 4, 6, 5]` puis `[2, 4, 6, 5]` puis `[2, 4, 5, 6]`\n",
              "correct": false,
              "feedback": "Erreur : les deux algorithmes ne\nproduisent pas les mêmes états\nintermédiaires. Au tri par sélection,\nchaque passe place le minimum du\nreste ; au tri par insertion, chaque\npasse insère l'élément suivant à sa\nplace dans la partie triée. Les\ncomportements intermédiaires diffèrent.\n"
            }
          ],
          "explanation": "Différence remarquable avec le tri par\nsélection : une itération du tri par\ninsertion peut ne presque rien faire quand\nl'élément est déjà bien placé.\nC'est typique : si la liste est presque\ntriée, l'insertion devient quasi linéaire,\ntandis que la sélection fait toujours le\nmême travail quadratique. Cette propriété\nd'**adaptabilité** rend l'insertion\npréférable sur des données quasi-triées."
        }
      ]
    },
    {
      "id": "q31",
      "difficulty": 2,
      "skills": [
        "tri-decroissant"
      ],
      "title": "Trier en ordre décroissant",
      "partie": "proprietes",
      "statement": "Quelle **modification du code** d'un tri par\ninsertion croissant le transforme en tri\n**décroissant**, sans étape supplémentaire ni\nrestriction sur le type des éléments ?",
      "options": [
        {
          "text": "Appliquer le tri croissant puis inverser la liste obtenue avec une boucle",
          "correct": false,
          "feedback": "Cette approche fonctionne et ne coûte qu'un parcours\nsupplémentaire, mais ce n'est pas une modification du tri : c'est\nune étape ajoutée après coup, que l'énoncé exclut. Modifier la\ncomparaison interne est plus simple et tout aussi efficace.\n"
        },
        {
          "text": "Trier la liste à l'envers d'abord, puis\nappliquer le tri croissant\n",
          "correct": false,
          "feedback": "Erreur : « trier à l'envers d'abord » n'a pas de sens si on n'a pas\nencore de tri, et cette démarche ajoute une étape au lieu de\nmodifier le tri.\n"
        },
        {
          "text": "Multiplier toutes les valeurs par\n$-1$, trier, puis multiplier à\nnouveau par $-1$\n",
          "correct": false,
          "feedback": "Cette astuce fonctionne pour des\nnombres, mais pas pour des chaînes ou\ndes objets quelconques. Et elle est\ninutilement compliquée par rapport à\nl'inversion de la comparaison.\n"
        },
        {
          "text": "Inverser le sens de la comparaison\nde la boucle interne (`<` au lieu\nde `>`)\n",
          "correct": true,
          "feedback": "Bonne réponse : la comparaison entre\ndeux éléments adjacents décide si on\nles permute. En écrivant\n`liste[j - 1] < liste[j]` au lieu de\n`liste[j - 1] > liste[j]`, on trie\ndans l'ordre opposé. C'est la\nmodification la plus simple et la\nplus localisée. Pour le tri par\nsélection, on cherche le **maximum**\nau lieu du minimum à chaque passe.\n"
        }
      ],
      "explanation": "Cette logique se généralise : pour un tri avec un critère\narbitraire (par âge, par nom, par taille, etc.), on n'a qu'à\nmodifier la **comparaison**. Python permet cela via le paramètre\n`key=` de `sorted` : avec une fonction clé nommée\n`def age(eleve): return eleve[1]`, `sorted(eleves, key=age)` trie\ndes couples `(nom, age)` par âge croissant."
    },
    {
      "id": "q32",
      "difficulty": 2,
      "skills": [
        "doublons-tri"
      ],
      "title": "Comportement avec doublons",
      "partie": "proprietes",
      "statement": "Que se passe-t-il quand on trie une liste\ncontenant des **doublons**, par exemple\n`[3, 1, 3, 2, 3]` ?",
      "options": [
        {
          "text": "Le tri renvoie `[1, 2, 3, 3, 3]`,\ntous les doublons étant conservés\n",
          "correct": true,
          "feedback": "Bonne réponse : les algorithmes de tri fonctionnent parfaitement\navec des doublons. Ils réordonnent les éléments sans en retirer ni\nen ajouter : les trois `3` se retrouvent côte à côte en fin de\nliste.\n"
        },
        {
          "text": "Les doublons sont supprimés et le\ntri renvoie `[1, 2, 3]`\n",
          "correct": false,
          "feedback": "Erreur : le tri ne supprime pas les\ndoublons. Il les conserve tous, dans\nl'ordre. Pour supprimer les doublons,\nil faut une étape distincte (par\nexemple un parcours qui n'ajoute chaque\nvaleur à une nouvelle liste que si elle\nn'y est pas déjà).\n"
        },
        {
          "text": "Les comparaisons d'éléments égaux\nfont boucler l'algorithme sans fin\n",
          "correct": false,
          "feedback": "Erreur : aucun risque de boucle\ninfinie. Les comparaisons restent\ndéterministes, les indices avancent\nnormalement.\n"
        },
        {
          "text": "Le tri lève une exception, les\néléments égaux étant incomparables\n",
          "correct": false,
          "feedback": "Erreur : deux valeurs égales sont\nparfaitement comparables. Les\nalgorithmes de tri sont conçus pour\nfonctionner avec n'importe quelle\nsuite de valeurs comparables,\ndoublons compris.\n"
        }
      ],
      "explanation": "Un tri ne change que l'ordre des éléments : la liste triée contient\nexactement les mêmes valeurs, avec le même nombre d'exemplaires.\nSupprimer les doublons est un autre traitement, qui demande un\nparcours dédié."
    },
    {
      "id": "q33",
      "difficulty": 2,
      "skills": [
        "selection",
        "trace",
        "premier-passage"
      ],
      "title": "Après le premier passage du tri par sélection",
      "partie": "selection",
      "statement": "Le tri par sélection cherche le minimum de la liste et l'échange\navec le premier élément, puis recommence sur le reste. Que devient\nla liste `[5, 2, 9, 1, 7]` après le premier passage ?",
      "options": [
        {
          "text": "`[1, 2, 9, 5, 7]`",
          "correct": true,
          "feedback": "Bonne réponse : le minimum est échangé avec l'élément en\nposition 0 ; le reste de la liste n'est pas réordonné.\n"
        },
        {
          "text": "`[1, 2, 5, 9, 7]`",
          "correct": false,
          "feedback": "Erreur : un seul échange a lieu par passage, le reste de la\nliste garde son ordre.\n"
        },
        {
          "text": "`[2, 5, 9, 1, 7]`",
          "correct": false,
          "feedback": "Erreur : c'est le minimum qui est placé en tête, pas un autre\nélément.\n"
        },
        {
          "text": "`[1, 2, 5, 7, 9]`",
          "correct": false,
          "feedback": "Erreur : la liste entièrement triée n'est obtenue qu'après tous\nles passages.\n"
        }
      ],
      "explanation": "Chaque passage du tri par sélection place un élément à sa position\ndéfinitive, par un seul échange.",
      "variants": [
        {
          "statement": "Le tri par sélection cherche le minimum de la liste et l'échange\navec le premier élément, puis recommence sur le reste. Que devient\nla liste `[5, 2, 9, 1, 7]` après le premier passage ?",
          "options": [
            {
              "text": "`[1, 2, 9, 5, 7]`",
              "correct": true,
              "feedback": "Bonne réponse : le minimum est échangé avec l'élément en\nposition 0 ; le reste de la liste n'est pas réordonné.\n"
            },
            {
              "text": "`[1, 2, 5, 9, 7]`",
              "correct": false,
              "feedback": "Erreur : un seul échange a lieu par passage, le reste de la\nliste garde son ordre.\n"
            },
            {
              "text": "`[2, 5, 9, 1, 7]`",
              "correct": false,
              "feedback": "Erreur : c'est le minimum qui est placé en tête, pas un autre\nélément.\n"
            },
            {
              "text": "`[1, 2, 5, 7, 9]`",
              "correct": false,
              "feedback": "Erreur : la liste entièrement triée n'est obtenue qu'après tous\nles passages.\n"
            }
          ],
          "explanation": "Chaque passage du tri par sélection place un élément à sa position\ndéfinitive, par un seul échange."
        },
        {
          "statement": "Le tri par sélection cherche le minimum de la liste et l'échange\navec le premier élément, puis recommence sur le reste. Que devient\nla liste `[4, 8, 3, 6]` après le premier passage ?",
          "options": [
            {
              "text": "`[3, 8, 4, 6]`",
              "correct": true,
              "feedback": "Bonne réponse : le minimum est échangé avec l'élément en\nposition 0 ; le reste de la liste n'est pas réordonné.\n"
            },
            {
              "text": "`[3, 4, 8, 6]`",
              "correct": false,
              "feedback": "Erreur : un seul échange a lieu par passage, le reste de la\nliste garde son ordre.\n"
            },
            {
              "text": "`[4, 8, 3, 6]`",
              "correct": false,
              "feedback": "Erreur : c'est le minimum qui est placé en tête, pas un autre\nélément.\n"
            },
            {
              "text": "`[3, 4, 6, 8]`",
              "correct": false,
              "feedback": "Erreur : la liste entièrement triée n'est obtenue qu'après tous\nles passages.\n"
            }
          ],
          "explanation": "Chaque passage du tri par sélection place un élément à sa position\ndéfinitive, par un seul échange."
        },
        {
          "statement": "Le tri par sélection cherche le minimum de la liste et l'échange\navec le premier élément, puis recommence sur le reste. Que devient\nla liste `[7, 1, 5, 2]` après le premier passage ?",
          "options": [
            {
              "text": "`[1, 7, 5, 2]`",
              "correct": true,
              "feedback": "Bonne réponse : le minimum est échangé avec l'élément en\nposition 0 ; le reste de la liste n'est pas réordonné.\n"
            },
            {
              "text": "`[1, 2, 5, 7]`",
              "correct": false,
              "feedback": "Erreur : un seul échange a lieu par passage, le reste de la\nliste garde son ordre.\n"
            },
            {
              "text": "`[1, 7, 2, 5]`",
              "correct": false,
              "feedback": "Erreur : c'est le minimum qui est placé en tête, pas un autre\nélément.\n"
            },
            {
              "text": "`[1, 5, 7, 2]`",
              "correct": false,
              "feedback": "Erreur : la liste entièrement triée n'est obtenue qu'après tous\nles passages.\n"
            }
          ],
          "explanation": "Chaque passage du tri par sélection place un élément à sa position\ndéfinitive, par un seul échange."
        }
      ]
    },
    {
      "id": "q34",
      "difficulty": 3,
      "skills": [
        "selection",
        "comparaisons",
        "liste-triee"
      ],
      "title": "Le tri par sélection sur une liste déjà triée",
      "partie": "selection",
      "statement": "On applique le tri par sélection à une liste de $n$ éléments déjà\ntriée. Que peut-on dire du nombre de comparaisons effectuées ?",
      "options": [
        {
          "text": "Le même que pour toute liste de $n$ éléments",
          "correct": true,
          "feedback": "Bonne réponse : le tri par sélection cherche le minimum du reste\nà chaque passage, quel que soit l'ordre initial. Il ne tire\naucun parti d'une liste déjà triée.\n"
        },
        {
          "text": "Il tombe à $n - 1$, chaque élément étant déjà à sa place",
          "correct": false,
          "feedback": "Erreur : c'est le tri par insertion qui se contente de $n - 1$\ncomparaisons sur une liste triée.\n"
        },
        {
          "text": "Il est nul, aucun échange n'étant nécessaire",
          "correct": false,
          "feedback": "Erreur : les échanges sont inutiles, mais les comparaisons pour\ntrouver chaque minimum ont bien lieu.\n"
        },
        {
          "text": "Il double, la liste devant être vérifiée deux fois",
          "correct": false,
          "feedback": "Erreur : rien n'est vérifié deux fois ; le coût est simplement\ninchangé.\n"
        }
      ],
      "explanation": "Le tri par sélection a un coût indépendant des données ; le tri\npar insertion, lui, profite d'une liste presque triée."
    },
    {
      "id": "q35",
      "difficulty": 1,
      "skills": [
        "selection",
        "invariant",
        "partie-triee"
      ],
      "title": "La partie déjà triée",
      "partie": "selection",
      "statement": "Après $k$ passages du tri par sélection sur une liste, quelle partie\nde la liste est garantie triée ?",
      "options": [
        {
          "text": "Les $k$ premiers éléments, à leur position définitive",
          "correct": true,
          "feedback": "Bonne réponse : chaque passage place le minimum du reste juste\naprès la partie triée. Les $k$ premiers éléments sont les $k$\nplus petits, dans l'ordre.\n"
        },
        {
          "text": "Les $k$ derniers éléments, les plus grands",
          "correct": false,
          "feedback": "Erreur : le tri par sélection construit la partie triée par la\ngauche.\n"
        },
        {
          "text": "Toute la liste, dès le premier passage terminé",
          "correct": false,
          "feedback": "Erreur : un passage ne place qu'un seul élément.\n"
        },
        {
          "text": "Aucune partie, le tri ne s'achevant qu'au dernier passage",
          "correct": false,
          "feedback": "Erreur : la partie gauche est triée et définitive dès les\npremiers passages, c'est l'invariant du tri.\n"
        }
      ],
      "explanation": "L'invariant du tri par sélection : à chaque instant, la partie\ngauche est triée et contient les plus petits éléments."
    },
    {
      "id": "q36",
      "difficulty": 2,
      "skills": [
        "insertion",
        "trace"
      ],
      "title": "Après l'insertion du troisième élément",
      "partie": "insertion",
      "statement": "Le tri par insertion insère chaque élément, de gauche à droite, à\nsa place dans la partie déjà triée qui le précède. Que devient la\nliste `[4, 7, 2, 9]` juste après l'insertion de son troisième élément ?",
      "options": [
        {
          "text": "`[2, 4, 7, 9]`",
          "correct": true,
          "feedback": "Bonne réponse : les deux premiers éléments forment la partie\ntriée ; le troisième y est inséré à sa place, et le dernier\nélément n'a pas encore été traité.\n"
        },
        {
          "text": "`[2, 4, 7, 9, 2]`",
          "correct": false,
          "feedback": "Erreur : le quatrième élément n'est inséré qu'au passage\nsuivant.\n"
        },
        {
          "text": "`[4, 2, 7, 9]`",
          "correct": false,
          "feedback": "Erreur : l'élément est inséré à sa place dans la partie triée,\npas simplement échangé avec son voisin.\n"
        },
        {
          "text": "`[2, 7, 4, 9]`",
          "correct": false,
          "feedback": "Erreur : la partie triée doit rester triée après l'insertion.\n"
        }
      ],
      "explanation": "À chaque étape du tri par insertion, la partie gauche reste triée\net grandit d'un élément.",
      "variants": [
        {
          "statement": "Le tri par insertion insère chaque élément, de gauche à droite, à\nsa place dans la partie déjà triée qui le précède. Que devient la\nliste `[4, 7, 2, 9]` juste après l'insertion de son troisième élément ?",
          "options": [
            {
              "text": "`[2, 4, 7, 9]`",
              "correct": true,
              "feedback": "Bonne réponse : les deux premiers éléments forment la partie\ntriée ; le troisième y est inséré à sa place, et le dernier\nélément n'a pas encore été traité.\n"
            },
            {
              "text": "`[2, 4, 7, 9, 2]`",
              "correct": false,
              "feedback": "Erreur : le quatrième élément n'est inséré qu'au passage\nsuivant.\n"
            },
            {
              "text": "`[4, 2, 7, 9]`",
              "correct": false,
              "feedback": "Erreur : l'élément est inséré à sa place dans la partie triée,\npas simplement échangé avec son voisin.\n"
            },
            {
              "text": "`[2, 7, 4, 9]`",
              "correct": false,
              "feedback": "Erreur : la partie triée doit rester triée après l'insertion.\n"
            }
          ],
          "explanation": "À chaque étape du tri par insertion, la partie gauche reste triée\net grandit d'un élément."
        },
        {
          "statement": "Le tri par insertion insère chaque élément, de gauche à droite, à\nsa place dans la partie déjà triée qui le précède. Que devient la\nliste `[6, 8, 5, 1]` juste après l'insertion de son troisième élément ?",
          "options": [
            {
              "text": "`[5, 6, 8, 1]`",
              "correct": true,
              "feedback": "Bonne réponse : les deux premiers éléments forment la partie\ntriée ; le troisième y est inséré à sa place, et le dernier\nélément n'a pas encore été traité.\n"
            },
            {
              "text": "`[1, 5, 6, 8]`",
              "correct": false,
              "feedback": "Erreur : le quatrième élément n'est inséré qu'au passage\nsuivant.\n"
            },
            {
              "text": "`[6, 5, 8, 1]`",
              "correct": false,
              "feedback": "Erreur : l'élément est inséré à sa place dans la partie triée,\npas simplement échangé avec son voisin.\n"
            },
            {
              "text": "`[5, 8, 6, 1]`",
              "correct": false,
              "feedback": "Erreur : la partie triée doit rester triée après l'insertion.\n"
            }
          ],
          "explanation": "À chaque étape du tri par insertion, la partie gauche reste triée\net grandit d'un élément."
        },
        {
          "statement": "Le tri par insertion insère chaque élément, de gauche à droite, à\nsa place dans la partie déjà triée qui le précède. Que devient la\nliste `[3, 9, 6, 2]` juste après l'insertion de son troisième élément ?",
          "options": [
            {
              "text": "`[3, 6, 9, 2]`",
              "correct": true,
              "feedback": "Bonne réponse : les deux premiers éléments forment la partie\ntriée ; le troisième y est inséré à sa place, et le dernier\nélément n'a pas encore été traité.\n"
            },
            {
              "text": "`[2, 3, 6, 9]`",
              "correct": false,
              "feedback": "Erreur : le quatrième élément n'est inséré qu'au passage\nsuivant.\n"
            },
            {
              "text": "`[3, 9, 6, 2]`",
              "correct": false,
              "feedback": "Erreur : l'élément est inséré à sa place dans la partie triée,\npas simplement échangé avec son voisin.\n"
            },
            {
              "text": "`[6, 3, 9, 2]`",
              "correct": false,
              "feedback": "Erreur : la partie triée doit rester triée après l'insertion.\n"
            }
          ],
          "explanation": "À chaque étape du tri par insertion, la partie gauche reste triée\net grandit d'un élément."
        }
      ]
    },
    {
      "id": "q37",
      "difficulty": 3,
      "skills": [
        "insertion",
        "decalages",
        "calcul"
      ],
      "title": "Le nombre de décalages d'une insertion",
      "partie": "insertion",
      "statement": "La partie triée vaut `[5, 8, 9]` et l'élément à insérer vaut `6`.\nLe tri par insertion décale vers la droite chaque élément plus\ngrand que `6`, puis le place. Combien de décalages sont\neffectués ?",
      "options": [
        {
          "text": "`2`",
          "correct": true,
          "feedback": "Bonne réponse : seuls les éléments strictement plus grands que\n6 sont décalés d'un cran, et 6 prend la position 1.\n"
        },
        {
          "text": "`1`",
          "correct": false,
          "feedback": "Erreur : 1 est la position finale de 6, pas le nombre\nd'éléments déplacés.\n"
        },
        {
          "text": "`3`",
          "correct": false,
          "feedback": "Erreur : 3 est le nombre d'éléments de la partie triée ;\nseuls ceux qui dépassent 6 sont décalés.\n"
        },
        {
          "text": "`4`",
          "correct": false,
          "feedback": "Erreur : 4 est la taille de la partie triée après\nl'insertion, pas le nombre d'éléments déplacés.\n"
        }
      ],
      "explanation": "Le coût d'une insertion est le nombre d'éléments plus grands que la\nvaleur insérée : nul si elle est la plus grande, maximal si elle\nest la plus petite.",
      "variants": [
        {
          "statement": "La partie triée vaut `[5, 8, 9]` et l'élément à insérer vaut `6`.\nLe tri par insertion décale vers la droite chaque élément plus\ngrand que `6`, puis le place. Combien de décalages sont\neffectués ?",
          "options": [
            {
              "text": "`2`",
              "correct": true,
              "feedback": "Bonne réponse : seuls les éléments strictement plus grands que\n6 sont décalés d'un cran, et 6 prend la position 1.\n"
            },
            {
              "text": "`1`",
              "correct": false,
              "feedback": "Erreur : 1 est la position finale de 6, pas le nombre\nd'éléments déplacés.\n"
            },
            {
              "text": "`3`",
              "correct": false,
              "feedback": "Erreur : 3 est le nombre d'éléments de la partie triée ;\nseuls ceux qui dépassent 6 sont décalés.\n"
            },
            {
              "text": "`4`",
              "correct": false,
              "feedback": "Erreur : 4 est la taille de la partie triée après\nl'insertion, pas le nombre d'éléments déplacés.\n"
            }
          ],
          "explanation": "Le coût d'une insertion est le nombre d'éléments plus grands que la\nvaleur insérée : nul si elle est la plus grande, maximal si elle\nest la plus petite."
        },
        {
          "statement": "La partie triée vaut `[2, 4, 6, 8]` et l'élément à insérer vaut `3`.\nLe tri par insertion décale vers la droite chaque élément plus\ngrand que `3`, puis le place. Combien de décalages sont\neffectués ?",
          "options": [
            {
              "text": "`3`",
              "correct": true,
              "feedback": "Bonne réponse : seuls les éléments strictement plus grands que\n3 sont décalés d'un cran, et 3 prend la position 1.\n"
            },
            {
              "text": "`1`",
              "correct": false,
              "feedback": "Erreur : 1 est la position finale de 3, pas le nombre\nd'éléments déplacés.\n"
            },
            {
              "text": "`4`",
              "correct": false,
              "feedback": "Erreur : 4 est le nombre d'éléments de la partie triée ;\nseuls ceux qui dépassent 3 sont décalés.\n"
            },
            {
              "text": "`5`",
              "correct": false,
              "feedback": "Erreur : 5 est la taille de la partie triée après\nl'insertion, pas le nombre d'éléments déplacés.\n"
            }
          ],
          "explanation": "Le coût d'une insertion est le nombre d'éléments plus grands que la\nvaleur insérée : nul si elle est la plus grande, maximal si elle\nest la plus petite."
        },
        {
          "statement": "La partie triée vaut `[1, 7, 9, 12, 15]` et l'élément à insérer vaut `2`.\nLe tri par insertion décale vers la droite chaque élément plus\ngrand que `2`, puis le place. Combien de décalages sont\neffectués ?",
          "options": [
            {
              "text": "`4`",
              "correct": true,
              "feedback": "Bonne réponse : seuls les éléments strictement plus grands que\n2 sont décalés d'un cran, et 2 prend la position 1.\n"
            },
            {
              "text": "`1`",
              "correct": false,
              "feedback": "Erreur : 1 est la position finale de 2, pas le nombre\nd'éléments déplacés.\n"
            },
            {
              "text": "`5`",
              "correct": false,
              "feedback": "Erreur : 5 est le nombre d'éléments de la partie triée ;\nseuls ceux qui dépassent 2 sont décalés.\n"
            },
            {
              "text": "`6`",
              "correct": false,
              "feedback": "Erreur : 6 est la taille de la partie triée après\nl'insertion, pas le nombre d'éléments déplacés.\n"
            }
          ],
          "explanation": "Le coût d'une insertion est le nombre d'éléments plus grands que la\nvaleur insérée : nul si elle est la plus grande, maximal si elle\nest la plus petite."
        }
      ]
    },
    {
      "id": "q38",
      "difficulty": 1,
      "skills": [
        "insertion",
        "analogie"
      ],
      "title": "Classer une main de cartes",
      "partie": "insertion",
      "statement": "Un joueur prend ses cartes une par une et glisse chacune à sa place\nparmi celles qu'il tient déjà, rangées dans l'ordre. Quel tri\nreproduit-il ?",
      "options": [
        {
          "text": "Le tri par insertion",
          "correct": true,
          "feedback": "Bonne réponse : la main déjà rangée est la partie triée, et\nchaque nouvelle carte y est insérée à sa place.\n"
        },
        {
          "text": "Le tri par sélection",
          "correct": false,
          "feedback": "Erreur : le tri par sélection chercherait d'abord la plus petite\ncarte de toutes, puis la suivante.\n"
        },
        {
          "text": "La recherche dichotomique",
          "correct": false,
          "feedback": "Erreur : la dichotomie cherche une valeur, elle ne range pas.\n"
        },
        {
          "text": "Aucun tri, l'ordre venant de la distribution",
          "correct": false,
          "feedback": "Erreur : les cartes arrivent dans un ordre quelconque ; c'est\nle joueur qui les trie.\n"
        }
      ],
      "explanation": "Le tri par insertion est celui que l'on pratique naturellement avec\ndes cartes ou des copies à classer."
    },
    {
      "id": "q39",
      "difficulty": 2,
      "skills": [
        "tri",
        "chaines",
        "ordre"
      ],
      "title": "Trier des chaînes de caractères",
      "partie": "proprietes",
      "statement": "Que renvoie `sorted([\"pomme\", \"Banane\", \"cerise\"])` ?",
      "options": [
        {
          "text": "`['Banane', 'cerise', 'pomme']`",
          "correct": true,
          "feedback": "Bonne réponse : les chaînes se comparent par les codes de leurs\ncaractères, et toutes les majuscules précèdent les minuscules.\n`'B'` passe donc avant `'c'`.\n"
        },
        {
          "text": "`['Banane', 'pomme', 'cerise']`",
          "correct": false,
          "feedback": "Erreur : entre `'cerise'` et `'pomme'`, `'c'` précède `'p'`.\n"
        },
        {
          "text": "`['cerise', 'pomme', 'Banane']`",
          "correct": false,
          "feedback": "Erreur : la majuscule `'B'` a un code plus petit que les\nminuscules, elle vient en premier.\n"
        },
        {
          "text": "`['pomme', 'Banane', 'cerise']`",
          "correct": false,
          "feedback": "Erreur : `sorted` renvoie une liste triée, pas l'ordre initial.\n"
        }
      ],
      "explanation": "Trier des chaînes suit l'ordre des codes de caractères : pour un\nordre alphabétique insensible à la casse, on trie sur les\nminuscules."
    },
    {
      "id": "q40",
      "difficulty": 3,
      "skills": [
        "cout",
        "quadratique",
        "calcul"
      ],
      "title": "Deux fois plus d'éléments à trier",
      "partie": "proprietes",
      "statement": "Un tri par insertion met $1$ s pour trier dix mille d'éléments dans le\npire cas. Combien de temps met-il, toujours dans le pire cas, pour\nvingt mille d'éléments ?",
      "options": [
        {
          "text": "Environ $4$ s",
          "correct": true,
          "feedback": "Bonne réponse : le coût est quadratique. Doubler la taille\nmultiplie le nombre de comparaisons par quatre, donc le temps\naussi.\n"
        },
        {
          "text": "Environ $2$ s",
          "correct": false,
          "feedback": "Erreur : un temps doublé correspondrait à un coût linéaire ; le\ntri par insertion est quadratique.\n"
        },
        {
          "text": "Environ $8$ s",
          "correct": false,
          "feedback": "Erreur : un facteur huit correspondrait à un coût cubique.\n"
        },
        {
          "text": "Toujours $1$ s",
          "correct": false,
          "feedback": "Erreur : le temps dépend fortement de la taille de la liste.\n"
        }
      ],
      "explanation": "Pour un coût en $n^2$, multiplier $n$ par $2$ multiplie le temps par\n$4$ : c'est ce qui rend ces tris inutilisables sur de très grandes\nlistes.",
      "variants": [
        {
          "statement": "Un tri par insertion met $1$ s pour trier dix mille d'éléments dans le\npire cas. Combien de temps met-il, toujours dans le pire cas, pour\nvingt mille d'éléments ?",
          "options": [
            {
              "text": "Environ $4$ s",
              "correct": true,
              "feedback": "Bonne réponse : le coût est quadratique. Doubler la taille\nmultiplie le nombre de comparaisons par quatre, donc le temps\naussi.\n"
            },
            {
              "text": "Environ $2$ s",
              "correct": false,
              "feedback": "Erreur : un temps doublé correspondrait à un coût linéaire ; le\ntri par insertion est quadratique.\n"
            },
            {
              "text": "Environ $8$ s",
              "correct": false,
              "feedback": "Erreur : un facteur huit correspondrait à un coût cubique.\n"
            },
            {
              "text": "Toujours $1$ s",
              "correct": false,
              "feedback": "Erreur : le temps dépend fortement de la taille de la liste.\n"
            }
          ],
          "explanation": "Pour un coût en $n^2$, multiplier $n$ par $2$ multiplie le temps par\n$4$ : c'est ce qui rend ces tris inutilisables sur de très grandes\nlistes."
        },
        {
          "statement": "Un tri par insertion met $3$ s pour trier mille d'éléments dans le\npire cas. Combien de temps met-il, toujours dans le pire cas, pour\ndeux mille d'éléments ?",
          "options": [
            {
              "text": "Environ $12$ s",
              "correct": true,
              "feedback": "Bonne réponse : le coût est quadratique. Doubler la taille\nmultiplie le nombre de comparaisons par quatre, donc le temps\naussi.\n"
            },
            {
              "text": "Environ $6$ s",
              "correct": false,
              "feedback": "Erreur : un temps doublé correspondrait à un coût linéaire ; le\ntri par insertion est quadratique.\n"
            },
            {
              "text": "Environ $24$ s",
              "correct": false,
              "feedback": "Erreur : un facteur huit correspondrait à un coût cubique.\n"
            },
            {
              "text": "Toujours $3$ s",
              "correct": false,
              "feedback": "Erreur : le temps dépend fortement de la taille de la liste.\n"
            }
          ],
          "explanation": "Pour un coût en $n^2$, multiplier $n$ par $2$ multiplie le temps par\n$4$ : c'est ce qui rend ces tris inutilisables sur de très grandes\nlistes."
        },
        {
          "statement": "Un tri par insertion met $0{,}5$ s pour trier cinq mille d'éléments dans le\npire cas. Combien de temps met-il, toujours dans le pire cas, pour\ndix mille d'éléments ?",
          "options": [
            {
              "text": "Environ $2$ s",
              "correct": true,
              "feedback": "Bonne réponse : le coût est quadratique. Doubler la taille\nmultiplie le nombre de comparaisons par quatre, donc le temps\naussi.\n"
            },
            {
              "text": "Environ $1$ s",
              "correct": false,
              "feedback": "Erreur : un temps doublé correspondrait à un coût linéaire ; le\ntri par insertion est quadratique.\n"
            },
            {
              "text": "Environ $4$ s",
              "correct": false,
              "feedback": "Erreur : un facteur huit correspondrait à un coût cubique.\n"
            },
            {
              "text": "Toujours $0{,}5$ s",
              "correct": false,
              "feedback": "Erreur : le temps dépend fortement de la taille de la liste.\n"
            }
          ],
          "explanation": "Pour un coût en $n^2$, multiplier $n$ par $2$ multiplie le temps par\n$4$ : c'est ce qui rend ces tris inutilisables sur de très grandes\nlistes."
        }
      ]
    }
  ]
}