Aller au contenu

Génération d'arbres binaires de recherche

Génération

Notre objectif est de fabriquer (générer) toutes les formes d'arbres binaires de recherche. Il y en a une infinité... Il faut limiter notre étude. On peut filtrer par taille, certes, mais les étiquettes peuvent être quelconques. Si on considère un lot de \(n\) étiquettes distinctes dans un ABR, on obtiendra toujours le même parcours infixe : la liste triée des étiquettes, il est donc pertinent de ne considérer que le rang des étiquettes et savoir où les placer.

Autrement dit, pour trouver toutes les formes possibles d'ABR à \(n\) nœuds, on peut se contenter de trouver tous les ABR dont les étiquettes sont les entiers de \(1\) à \(n\).

Modélisation

Dans cet exercice, on modélisera les arbres binaires de recherche avec des tuples, de la façon suivante :

  • l'ABR vide sera modélisé par (), le tuple vide.
  • un ABR non vide sera modélisé par (gauche, label, droite), un tuple à trois éléments représentant respectivement le sous-arbre à gauche, l'étiquette et le sous-arbre à droite. L'étiquette sera un entier, et les sous-arbres représentés avec des tuples de manière récursive.

Premiers cas

Il n'y a qu'un seul ABR à \(0\) nœud : l'ABR vide.

🐍 Script Python
ABR_0 = [()]

Il n'y a qu'un seul ABR à \(1\) nœud étiqueté \(1\): l'ABR avec juste le nœud \(1\) inséré.

🐍 Script Python
ABR_1 = [((), 1, ())]

Il y a deux ABR à \(2\) nœuds étiquetés \(1\) et \(2\):

  • un ABR avec \(1\) comme racine, et donc \(2\) à droite.
  • un ABR avec \(2\) comme racine, et donc \(1\) à gauche.
🐍 Script Python
ABR_2 = [
    ((), 1, ((), 2, ())),
    (((), 1, ()), 2, ())
]

Il y a 5 ABR avec trois nœuds étiquetés de \(1\) à \(3\).

  • Avec \(1\) comme racine, les deux autres nœuds \(2\) et \(3\) sont à droite, et il y a deux façons de les placer. D'abord le \(2\), ou d'abord le \(3\).
  • Avec \(2\) comme racine, il n'y a qu'une seule possibilité : le \(1\) à gauche et le \(3\) à droite.
  • Avec \(3\) comme racine, les deux autres nœuds \(1\) et \(2\) sont à gauche, et il y a deux façons de les placer. D'abord le \(1\), ou d'abord le \(2\).

Les 5 ABR étiquetés de 1 à 3

graph TB
    A(1)
    A --> A0( )
    A --> A1(2)
    A1 --> A10( )
    A1 --> A11(3)
    A11 --> A110( )
    A11 --> A111( )

    B(1)
    B --> B0( )
    B --> B1(3)
    B1 --> B10(2)
    B1 --> B11( )
    B10 --> B100( )
    B10 --> B101( )

    H( ) --- C(2)
    C --> C0(1)
    C --> C1(3)
    C0 --> C00( )
    C0 --> C01( )
    C1 --> C10( )
    C1 --> C11( )

    D(3)
    D --> D0(1)
    D --> D1( )
    D0 --> D00( )
    D0 --> D01(2)
    D01 --> D010( )
    D01 --> D011( )

    E(3)
    E --> E0(2)
    E --> E1( )
    E0 --> E00(1)
    E0 --> E01( )
    E00 --> E000( )
    E00 --> E001( )

    linkStyle 12 stroke-width:0px;
    style H opacity:0;

Exercice

Le dictionnaire dico_abr qui, à une taille n donnée, associe la liste des ABR étiquetés de 1 à n commence par l'entrée 0: [()] : la liste qui n'a qu'un seul élément, l'ABR vide.

Compléter le script avec la fonction génère_abr qui prend n un entier et qui modifie le dictionnaire dico_abr avec toutes les clés entiers naturels k inférieurs ou égaux à n et dont la valeur associée est la liste (peu importe l'ordre) des ABR de taille k étiquetés de 1 à k modélisés avec le tuple.

###(Dés-)Active le code après la ligne # Tests (insensible à la casse)
(Ctrl+I)
Entrer ou sortir du mode "deux colonnes"
(Alt+: ; Ctrl pour inverser les colonnes)
Entrer ou sortir du mode "plein écran"
(Esc)
Tronquer ou non le feedback dans les terminaux (sortie standard & stacktrace / relancer le code pour appliquer)
Si activé, le texte copié dans le terminal est joint sur une seule ligne avant d'être copié dans le presse-papier
Évaluations restantes : /
.128013]x,59/f.78rnb _o=ylaepcwgu)vd4613kméhtsP(S0+à2èC[-i:050D0v0M0u0Z0t0N0o0x0t0u0N0N0r010M0Z0w010406050N0A0J0J0u0l0s040Q0q0t0A0^0q0m050g0 1113150}0w04051l1e1o0g1l0}0D0Z0C0-0/0;0?0L0Z0z0L0t1C0L0M0{050(0n0t0v1x0:0=011B1D1F1D0M1L1N1J0M0l1m0M0L1P1z010h0*0v0m0u0J0v010-180N0w0u0m0?0U1J1`1|1*1R1-1N1:1=0{0a0o0O0l0q0w0q0N0Z1b0m0o0$1^0l0l0v0x2j1e210m1m0g1(2w1#1%1$1K0D230?1F0m1/2g1J1u1w0.1Q2G0Z2I0m0q2M1J0w2p1m2u2w2!0~1{2k2O1+2T0l120t0{0o0G2t2(0|2%222*1R2,2.2:0U2?1|2^2u2F012}0u2/040o0H312v0}342{0?37390o0E3d332(353j2:0e3n3f3p3h360q2-382:0F3u2_2)1y2|3z2~3a0j3E3g3H3i3J3B3a0k3N3w3P3y3A3k0f3V2`3X3r040G0R3$3G2P3Y3K0G2=1f2@3v3%3/3)0G303@323_3.2+3R390G3c3 3e3F3q440{0G3m483o3`433Z4d3t4g414b4k3*3D4n4a3x3|3M4t3O3{4c3*3U4y3W4A4q0G3#4E4i3I4q0U3,4g1p2Y1e2M2z0D1%2E3x0x2U1?1m4U1n4S2$4Q4!0$2Z4F2+0{1u4!0p0u0n0l3n0o4u3X0q0{0r4|4~3{0n4=0Z2r3n541+0`040P0B3u4o3x0I4=0v0h5a4z1+0y2:5o4:2|0h4=0K0x380v5t4L0?5d0P5C422|0{4_4{4Q5p1R5d0d535O3i5l0t0(5H355d0B0!3u0o5(4}5T015k040Z5n4g5*5u3i5604265Y3x5F5{3(5K4`5~3/5!5S5?0150040r525;5b1R0J0Z0{4P2$5+5d5$4n5)6o5=5D5,0{2p0M0A0l1d6c6k0{5f5%5)6d5U040z0u0A0x0L5B5N665Q656r0m6t0u0x2R6N6j6P0{5R6z666T040D2d2i6Y2@6q5I0?686b2!6:3q605M2!066o6F6s046u6w6y6^705}6O6S5x5z1N625c6B7e5J6H6J6L6.32776#6R6;365V5X797r5!6$765+6)0l6V6X7q35680S7F4v7t0u7h5E7p6%7a6*5y5A7N01786Z7R6+0q6-7V6Q7Q7r6)0$5W7M7v5Z0{0B5g4n5i3X5-0$5:7Y7r5r3a7V0m5w6H0K0m0V2p4^617/5|7g8b5 04752@7o045#6D5(700N1 04010W0q0J0w0t0V0M0v0d0o2h0o0n0v0N7#0m8B1N2l582j1:0Z2p8M4@5L0o2f6w0o0M0q1a1O0.0K2l1O0R0o0T0o6T8m6_7K6*580q896|8i6A040X7V6f6h7%0{0b7J4 5195630{0X5f946n6E5+5-0h3z984;040I9k1R0q7 2R9o5@6U0m0z7m2v8j5G8e3/903*92047y6/706)8h328;96047I7)359E3?7}7:8k6m6}6p9f665-5/9t7s9m9*9q0{2T0M9-9r9M2v9O3{578T8a9W8c049Z3^9#9#9K9{8^5L9G8~9C9l9nab5P939-979S9 0X9d9!a36 5+0x0G0{032b130^1O0D0K1F5z8z8:ao709h9jaj8f7C6W2I9=0{9saJ559v9x9G9B9~3X9U9G9I9Na59,aR1+7H9*aZae7O9YaEao9$6raH8`a$7A0{6I6K6MaO5.9@80a{8?9|a_9z8|aaaX9`727DaNa)9p0{0Ya,6g9Fa.7W93a140a=bs9_1+a^9*7+6,8z4^0A0cb0aQ7z6(a68_a9810{adbG6r68bjbg6GaL7Ebn5d0bbq3ebtb#bu7i7!7$bS67aibO7*7b7UbW8dbb9lb)bA6JbDb=9Hbx6UaM9y4/6r649eb$a=a%4?a79}8{6!8}bLa(b@af04amcdbP0{0icg0u0w0w1/0DaVaWcmb/7ja~c28ja#9^a%bUbfcia/cEb3bH6*bzcC8|7=3E0g4-0v2w2XcW4T1v4V2z2C2x4_1N2w4U0}0g0$0(0*0N04.