Parcours séquentiel d'un tableau

Régulièrement en informatique, les données sont organisées en tableau de valeurs.

On peut alors se demander si une valeur est dans le tableau :

In [2]:
liste_prenom = ['Antoine' , 'Bertrand', 'Camille']
In [3]:
print('Camille' in liste_prenom)
True
In [4]:
print('Nicolas' in liste_prenom)
False

On peut aussi vouloir parcourir toutes les valeurs, pour les afficher par exemple :

In [5]:
# Méthode classique : on itère sur les indices
for i in range(len(liste_prenom)):
    print(liste_prenom[i])
Antoine
Bertrand
Camille
In [6]:
# Méthode pur python : on itère directement sur les éléments
for prenom in liste_prenom :
    print(prenom)
Antoine
Bertrand
Camille

On va ci-dessous présenter trois algorithmes :

  • comment retrouver une valeur dans un tableau
  • comment déterminer un extremum dans un tableau
  • comment calculer la moyenne d'un tableau

0. Préparation des données :

Nous allons travailler sur des données gégographiques.

Pour cela importons le fichier "paysMonde.csv" qui contient (pour chaque pays du monde, source : https://www.populationdata.net/) :

  • l'indice du pays
  • le nom du pays
  • la population du pays
  • la superficie du pays (en km²)
  • la densité du pays (en habitant/km²)

(vous pouvez l'ouvrir avec un tableur afin de visualiser les données).

In [7]:
with open("paysMonde.csv") as fichier :
    tableau_complet = fichier.readlines()

print(tableau_complet)
['Rang;Pays;Population;Superficie (km²);Densité (hab./km²)\n', '194;Abkhazie;246313;8653;28.47\n', '195;Açores;243862;2322;105.02\n', '47;Afghanistan;31575018;652864;48.36\n', '24;Afrique du Sud;57725606;1219912;47.32\n', '142;Albanie;2870324;28748;99.84\n', '33;Algérie;43003767;2381741;18.06\n', '17;Allemagne;82886977;357386;231.93\n', '214;Andorre;76522;468;163.51\n', '51;Angola;29131016;1281432;22.73\n', '236;Anguilla;15174;91;166.75\n', '249;Antarctique;1500;14107637;0.00\n', '209;Antigua-et-Barbuda;104084;277;375.75\n', '196;Antilles néerlandaises;230304;960;239.90\n', '42;Arabie saoudite;33413660;2149690;15.54\n', '31;Argentine;44494502;2780400;16.00\n', '141;Arménie;2969942;29743;99.85\n', '203;Artsakh (Haut-Karabakh);147906;11433;12.94\n', '206;Aruba;111673;180;620.41\n', '56;Australie;25105503;7688485;3.27\n', '100;Autriche;8822267;83879;105.18\n', '92;Azerbaïdjan;9967730;86573;115.14\n', '182;Bahamas;399421;13962;28.61\n', '158;Bahreïn;1592087;778;2046.38\n', '8;Bangladesh;173548302;147570;1176.04\n', '188;Barbade;285389;431;662.16\n', '95;Bélarus (Biélorussie);9477135;207605;45.65\n', '83;Belgique;11376070;30688;370.70\n', '183;Belize;398050;22966;17.33\n', '81;Bénin;11496140;114763;100.17\n', '217;Bermudes;61592;53;1162.11\n', '144;Bhoutan;2788599;38394;72.63\n', '84;Bolivie;11362305;1098581;10.34\n', '138;Bosnie-et-Herzégovine;3482041;51209;68.00\n', '148;Botswana;2325082;581726;4.00\n', '7;Brésil;210301591;8515759;24.70\n', '181;Brunei;425383;5765;73.79\n', '108;Bulgarie;7050034;110912;63.56\n', '61;Burkina Faso;20252523;270764;74.80\n', '79;Burundi;11759805;27834;422.50\n', '216;Caïmans;64420;267;241.27\n', '71;Cambodge;16754937;181035;92.55\n', '57;Cameroun;23799022;475650;50.03\n', '39;Canada;37560207;9984670;3.76\n', '151;Canaries;2108121;7447;283.08\n', '177;Cap-Vert;544081;4033;134.91\n', '244;Chagos;4239;56;75.70\n', '64;Chili;19107216;756950;25.24\n', '1;Chine;1394112547;9596961;145.27\n', '164;Chypre;1219051;9251;131.78\n', '28;Colombie;49892184;1141748;43.70\n', '169;Comores;845477;1862;454.07\n', '121;Congo;5279517;341821;15.45\n', '235;Cook;17328;237;73.11\n', '53;Corée du Nord;25617841;123138;208.04\n', '27;Corée du Sud;51425792;100356;512.43\n', '125;Costa Rica;5003402;51100;97.91\n', '55;Côte d’Ivoire;25117809;322462;77.89\n', '133;Croatie;4105493;56594;72.54\n', '85;Cuba;11239445;109884;102.28\n', '202;Curaçao;160012;444;360.39\n', '115;Danemark;5789957;42925;134.89\n', '166;Djibouti;1048999;25030;41.91\n', '215;Dominique;74679;754;99.04\n', '14;Égypte;97833521;1010408;96.83\n', '94;Émirats arabes unis;9541615;83600;114.13\n', '70;Équateur;16803150;256370;65.54\n', '122;Érythrée;5187948;121320;42.76\n', '29;Espagne;46698569;505992;92.29\n', '161;Estonie;1319133;45336;29.10\n', '165;Eswatini (Swaziland);1159250;17355;66.80\n', '3;États-Unis;331883986;9629047;34.47\n', '13;Éthiopie;98802543;1132308;87.26\n', '224;Féroé;51312;1393;36.84\n', '167;Fidji;890196;18274;48.71\n', '118;Finlande;5529477;338452;16.34\n', '21;France;66992699;551695;117.48\n', '155;Gabon;1995659;267667;7.46\n', '149;Gambie;2207816;10689;206.55\n', '135;Géorgie;3729631;57178;65.23\n', '253;Géorgie du Sud-et-les Îles Sandwich du Sud;35;4190;0.01\n', '48;Ghana;30280811;238553;126.94\n', '229;Gibraltar;36974;7;5437.35\n', '86;Grèce;10752660;132049;81.43\n', '204;Grenade;115465;349;330.85\n', '220;Groenland;56025;2166086;0.03\n', '184;Guadeloupe;382704;1628;235.08\n', '199;Guam;179606;541;331.99\n', '67;Guatemala;17337132;108930;159.16\n', '78;Guinée;11883516;245857;48.34\n', '154;Guinée équatoriale;2015334;28051;71.85\n', '159;Guinée-Bissau;1584791;36125;43.87\n', '170;Guyana;829096;214970;3.86\n', '187;Guyane;296711;83846;3.54\n', '82;Haïti;11417730;27065;421.86\n', '96;Honduras;9052661;111275;81.35\n', '104;Hong Kong;7448885;1110;6710.71\n', '93;Hongrie;9778371;93023;105.12\n', '201;Îles Anglo-Normandes – Jersey et Guernesey;167563;194;863.73\n', '232;Îles Vierges britanniques;32944;151;218.17\n', '208;Îles Vierges des États-Unis;108298;348;311.20\n', '2;Inde;1358408567;3287469;413.21\n', '4;Indonésie;268674755;1913579;140.40\n', '38;Irak;38124182;435052;87.63\n', '19;Iran;81920730;1629771;50.27\n', '129;Irlande;4857198;70182;69.21\n', '186;Islande;348450;103125;3.38\n', '98;Israël;9008700;20517;439.08\n', '23;Italie;60494785;302072;200.27\n', '146;Jamaïque;2728864;10991;248.28\n', '11;Japon;126330302;377972;334.23\n', '88;Jordanie;10305560;88794;116.06\n', '65;Kazakhstan;18440161;2724922;6.77\n', '30;Kenya;46050302;591971;77.79\n', '114;Kirghizistan;6256730;199949;31.29\n', '205;Kiribati;114698;726;157.99\n', '157;Kosovo;1798506;10905;164.92\n', '130;Koweït;4727665;17818;265.33\n', '32;Kurdistan;44000000;503000;87.48\n', '106;Laos;7230665;236800;30.53\n', '150;Lesotho;2183687;30355;71.94\n', '156;Lettonie;1934379;64573;29.96\n', '111;Liban;6629166;10389;638.09\n', '123;Libéria;5096007;111370;45.76\n', '112;Libye;6549402;1759540;3.72\n', '228;Liechtenstein;38114;160;238.21\n', '143;Lituanie;2795674;65286;42.82\n', '175;Luxembourg;613894;2586;237.39\n', '172;Macao;663419;31;21539.58\n', '152;Macédoine du Nord;2076129;25713;80.74\n', '52;Madagascar;25647250;587295;43.67\n', '193;Madère;254368;802;317.17\n', '44;Malaisie;32549402;330345;98.53\n', '66;Malawi;17918049;118484;151.23\n', '178;Maldives;533941;131;4075.89\n', '62;Mali;19594221;1246814;15.74\n', '245;Malouines;3617;12173;0.30\n', '180;Malte;446555;320;1376.35\n', '213;Man;82619;579;142.69\n', '223;Mariannes du Nord;51807;464;111.65\n', '40;Maroc;35481848;446550;79.46\n', '221;Marshall;55663;182;305.84\n', '185;Martinique;364354;1128;323.01\n', '162;Maurice;1265637;2007;630.61\n', '134;Mauritanie;3984110;1030700;3.87\n', '192;Mayotte;270372;375;720.99\n', '10;Mexique;127318112;1964375;64.78\n', '210;Micronésie;103196;725;142.34\n', '136;Moldavie;3547539;30794;115.20\n', '227;Monaco;38300;2;18960.40\n', '139;Mongolie;3229638;1564116;2.06\n', '174;Monténégro;622359;13812;45.06\n', '243;Montserrat;5343;103;51.87\n', '50;Mozambique;29632474;782574;37.87\n', '26;Myanmar (Birmanie);53343778;676577;78.84\n', '147;Namibie;2352592;824116;2.85\n', '237;Nauru;12696;21;596.06\n', '49;Népal;29704501;147181;201.82\n', '113;Nicaragua;6460229;130376;49.55\n', '60;Niger;21546595;1266491;17.01\n', '5;Nigéria;212871345;923768;230.44\n', '246;Nioué;2545;261;9.75\n', '247;Norfolk;1778;36;49.39\n', '120;Norvège;5312343;385180;13.79\n', '190;Nouvelle-Calédonie;282013;18576;15.18\n', '127;Nouvelle-Zélande;4913171;268107;18.33\n', '131;Oman;4669227;309550;15.08\n', '218;Ossétie du Sud-Alanie;57652;3900;14.78\n', '36;Ouganda;39612378;241551;163.99\n', '43;Ouzbékistan;32653885;448970;72.73\n', '6;Pakistan;212761108;796096;267.25\n', '234;Palaos;17820;416;42.84\n', '124;Palestine;5091819;6020;845.82\n', '132;Panama;4160016;74177;56.08\n', '97;Papouasie-Nouvelle-Guinée;9008718;462840;19.46\n', '107;Paraguay;7054473;406752;17.34\n', '68;Pays-Bas;17182462;41542;413.62\n', '233;Pays-Bas caribéens;24548;322;76.24\n', '45;Pérou;32162184;1285216;25.02\n', '12;Philippines;107558661;300439;358.00\n', '252;Pitcairn;50;47;1.06\n', '37;Pologne;38413144;312679;122.85\n', '191;Polynésie française;275918;3792;72.76\n', '140;Porto Rico;3195153;9104;350.96\n', '89;Portugal;10291027;92226;111.58\n', '128;Pount;4905246;212510;23.08\n', '145;Qatar;2743932;11651;235.51\n', '116;République centrafricaine;5745135;622984;9.22\n', '16;République démocratique du Congo;92724919;2345410;39.53\n', '90;République dominicaine;10266149;48311;212.50\n', '168;Réunion;866506;2512;344.95\n', '63;Roumanie;19524125;238391;81.90\n', '22;Royaume-Uni;66465641;242545;274.03\n', '9;Russie;146781095;17125402;8.57\n', '77;Rwanda;12089721;26338;459.02\n', '173;Sahara occidental;654052;266000;2.46\n', '239;Saint-Barthélemy;9793;21;466.33\n', '219;Saint-Christophe-et-Niévès;56345;272;207.15\n', '231;Saint-Marin;33419;61;547.85\n', '230;Saint-Martin (France);35746;53;674.45\n', '226;Saint-Martin (Pays-Bas);42878;34;1261.12\n', '241;Saint-Pierre-et-Miquelon;6008;242;24.83\n', '207;Saint-Vincent-et-les-Grenadines;110049;384;286.59\n', '242;Sainte-Hélène, Ascension et Tristan da Cunha;5705;415;13.75\n', '200;Sainte-Lucie;178696;603;296.34\n', '171;Salomon;667044;28896;23.08\n', '110;Salvador;6641842;21041;315.66\n', '198;Samoa;199243;2830;70.40\n', '222;Samoa américaines;53790;198;271.67\n', '197;Sao Tomé-et-Principe;201770;1001;201.57\n', '72;Sénégal;16209125;196712;82.40\n', '109;Serbie;7001444;77594;90.23\n', '212;Seychelles;97023;459;211.38\n', '103;Sierra Leone;7794974;71740;108.66\n', '117;Singapour;5638679;719;7842.39\n', '119;Slovaquie;5450421;49034;111.16\n', '153;Slovénie;2070050;20271;102.12\n', '75;Somalie;13611470;637657;21.35\n', '126;Somaliland;4979218;176119;28.27\n', '35;Soudan;41435412;1886068;21.97\n', '76;Soudan du Sud;12864588;644329;19.97\n', '59;Sri Lanka;21670721;65610;330.30\n', '91;Suède;10196177;407311;25.03\n', '101;Suisse;8542323;41285;206.91\n', '176;Suriname;598190;163821;3.65\n', '54;Syrie;25297296;185180;136.61\n', '99;Tadjikistan;8931496;142627;62.62\n', '58;Taïwan;23584865;36197;651.57\n', '25;Tanzanie;54199163;945088;57.35\n', '73;Tchad;15162044;1284200;11.81\n', '87;Tchéquie;10649800;78867;135.03\n', '251;Terres australes et antarctiques françaises (TAAF);196;439672;0.00\n', '20;Thaïlande;68863629;513115;134.21\n', '163;Timor oriental;1261407;14954;84.35\n', '105;Togo;7352781;56600;129.91\n', '248;Tokelau;1556;10;155.60\n', '211;Tonga;98659;749;131.72\n', '179;Transnistrie;503640;4163;120.98\n', '160;Trinité-et-Tobago;1359193;5155;263.66\n', '80;Tunisie;11582075;162155;71.43\n', '102;Turkménistan;8481200;491210;17.27\n', '225;Turques-et-Caïques;43013;948;45.37\n', '18;Turquie;82003882;783562;104.66\n', '240;Tuvalu;9605;26;374.76\n', '34;Ukraine;42220824;576468;73.24\n', '137;Uruguay;3505985;175016;20.03\n', '189;Vanuatu;285359;12281;23.24\n', '250;Vatican;804;1;1827.27\n', '46;Venezuela;31828110;916445;34.73\n', '15;Viêt Nam;96395051;331231;291.02\n', '238;Wallis-et-Futuna;11562;142;81.42\n', '41;Yémen;34232322;527968;64.84\n', '69;Zambie;16887720;770243;21.93\n', '74;Zimbabwé;14025965;390757;35.89\n']

C'est compliqué... Arrangeons cela :

In [8]:
tableau_valeurs = []
# On parcourt toutes les lignes du tableau
for ligne in tableau_complet :
    # On coupe chaque ligne au niveau des ";""
    tableau_valeurs.append(ligne.split(";"))

# On convertit les valeurs en entier ou float
# A partir de la ligne 1 car la 0 est les entêtes
for ligne in tableau_valeurs[1:] :
    ligne[0] = int(ligne[0])
    ligne[2] = int(ligne[2])
    ligne[3] = float(ligne[3])
    ligne[4] = float(ligne[4])

# On créée les sous-tables
noms = []
populations = []
superficies = []
densites = []

for ligne in tableau_valeurs[1:] :
    noms.append(ligne[1])
    populations.append(ligne[2])
    superficies.append(ligne[3])
    densites.append(ligne[4])
In [9]:
# On n'affiche que les 10 premiers
print(noms[:10])
['Abkhazie', 'Açores', 'Afghanistan', 'Afrique du Sud', 'Albanie', 'Algérie', 'Allemagne', 'Andorre', 'Angola', 'Anguilla']

I. Recherche le valeurs :

I.1. Algorithme et code :

On se donne un tableau de type quelconque et on cherche si une valeur donnée est dedans.

L'algorithme est simple :

  • Pour i allant de 0 à longueur(table) - 1 :
    • si table[i] vaut valeur_cherchée :
      • Retourne Vrai
  • Retourne Faux

En Python :

In [11]:
def cherche_valeur(liste, valeur) :
    """
    Cherche la valeur indiquée dans la liste proposée
    liste est une série de valeurs numériques triées
    valeur est une valeur numérique à chercher
    Renvoie True si la valeur est présente, False sinon
    """
    
    for element in liste :
        if element == valeur :
            return True
        
    return False

Est-ce que le pays "France" est dans la liste des noms :

In [12]:
cherche_valeur(noms,'France')
Out[12]:
True

Est-ce que le pays "Cancanie" est dans la liste des noms :

In [13]:
cherche_valeur(noms,'Cancanie')
Out[13]:
False

Cela a l'air de fonctionner sur des chaînes de caractères... Testons sur des entiers :

In [14]:
# On cherche la population du Cambodge
cherche_valeur(populations,16754937)
Out[14]:
True
In [15]:
# On cherche une population n'existant pas 
cherche_valeur(populations,1)
Out[15]:
False

Et sur les flottants ?

In [16]:
# On cherche la densité de l'Australie
cherche_valeur(densites,3.27)
Out[16]:
True

Et si on se trompe de type ?

In [17]:
cherche_valeur(noms, 12)
Out[17]:
False

I.2. Correction :

Rappelons qu'étudier la correction d'un algorithme nécessité d'étudier :

  • sa terminaison : l'algorithme se termine-t-il ?
  • sa correction partielle : l'algorithme calcule-t-il la bonne valeur ?

La terminaison est facile ici dans la mesure où notre algorithme est construit autour d'une boucle Pour parcourant l'ensemble des valeurs du tableau.

On peut prendre comme variant de boucle $longueur(tableau) - i$ où $i$ est le nombre de tours de boucles réalisé. Ce variant est bien un entier positif strictement décroissant.

Pour la correction partielle, on peut prendre comme invariant de boucle :

$$Après \: la \: boucle \: de \: rang \: k, \: la \: variable \: 'resultat' \: est \: 'Vraie' \: si \: la \: valeur \: est \: dans \: les \: k \: premièrs \: éléments \: du \: tableau$$

On considère ici une variable $resultat$ qui contient est fausse par défaut et qui bascule à vrai dès que la valeur a été trouvée.

Prouvons que cet invariant est toujours vrai :

  1. Avant d'entrer dans la boucle, on a étudié aucun élément donc $resultat$ est fausse. La propriété est initialisée
  2. On suppose qu'il existe un rang $k$ pour lequel la propriété est vraie (hypothèse de récurrence)
  3. Lors de l'itération $k+1$, l'algorithme teste si l'élément d'indice $k+1$ est égal à la valeur cherchée et bascule $resultat$ à $Vrai$ si c'est le cas (en fait il renvoie directement True). Sinon, il laisse la valeur à $Faux$ Donc après cette itération, $resultat$ contient bien la valeur attendue (héréditié).

On a donc prouvé la correction partielle.

I.3. Complexité :

Combien d'opération fait notre algorithme dans le pire des cas (si la valeur cherchée est en fin de tableau) ?

Appelons $n$ la taille du tableau.

L'algorithme parcourt tous les éléments : cela fait $n$ itérations.

Pour chacune d'entre elles, il teste l'égalité entre l'élément et la valeur cherchée : $1$ opération.

On a donc en tout $n$ opérations : la complexité est linéaire $\mathcal{O}(n)$.

On peut s'en rendre compte en mesurant le temps de calcul de la fonction :

In [18]:
# Données de taille 100
liste = list(range(100))
valeur = 99

%timeit cherche_valeur(liste, valeur)
2.07 µs ± 64.2 ns per loop (mean ± std. dev. of 7 runs, 100000 loops each)
In [19]:
# Données de taille 100*100 => Temps 100 fois plus long ?
liste = list(range(100*100))
valeur = 100*100-1

%timeit cherche_valeur(liste, valeur)
190 µs ± 1.7 µs per loop (mean ± std. dev. of 7 runs, 1000 loops each)

II. Recherche d'extremum :

II.1. Algorithme et code :

On se donne désormais un tableau d'éléments que l'on peut classer et l'on cherche un extremum (la minumum ou le maximum).

On pourrait classer les textes en utilisant l'ordre alphabétique mais on va s'en tenir aux tableaux de nombres (populations, superficies et denistes).

L'algorithme est simple (on cherche le minimum) :

  • Le minimum est l'élélment 0
  • Pour i allant de 1 à longueur(table) - 1 :
    • si table[i] < minimum :
      • minimum = table[i]
  • Retourne minimum

Pour le maximum, on a juste à renverser le symbole d'ordre < dans le test.

En Python :

In [20]:
def cherche_minimum(liste) :
    """
    Cherche le minimum dans la liste proposée
    liste est une série de valeurs numériques
    Renvoie la valeur du minimum
    """
    
    minimum = liste[0]
    
    for element in liste[1:] :
        if element < minimum :
            minimum = element
        
    return minimum
In [21]:
def cherche_maximum(liste) :
    """
    Cherche le maximum dans la liste proposée
    liste est une série de valeurs numériques
    Renvoie la valeur du maximum
    """
    
    minimum = liste[0]
    
    for element in liste[1:] :
        if element > minimum :
            minimum = element
        
    return minimum

Quelle est la population minimale ?

In [22]:
cherche_minimum(populations)
Out[22]:
35

Quelle est la densité maximale ?

In [23]:
cherche_maximum(densites)
Out[23]:
21539.58

C'est bien mais un peu frustrant : on aimerait bien retrouver le nom du pays ayant la population minimale ou la densité maximale. Pour cela il faudrait récupérer la valeur de l'extremum et l'indice de cette valeur :

In [24]:
def cherche_indice_minimum(liste) :
    """
    Cherche le minimum et son indice dans la liste proposée
    liste est une série de valeurs numériques
    Renvoie l'indice et la valeur du minimum dans un tuple
    """
    
    indice_min = 0
    
    for i in range(1, len(liste)) :
        if liste[i] < liste[indice_min] :
            indice_min = i
        
    return indice_min, liste[indice_min]
In [25]:
def cherche_indice_maximum(liste) :
    """
    Cherche le maximum et son indice dans la liste proposée
    liste est une série de valeurs numériques
    Renvoie l'indice et la valeur du maximum dans un tuple
    """
    
    indice_max = 0
    
    for i in range(1, len(liste)) :
        if liste[i] > liste[indice_max] :
            indice_max = i
        
    return indice_max, liste[indice_max]

Quel est le pays le moins peuplé ?

In [26]:
indice, pop = cherche_indice_minimum(populations)

print(noms[indice])
Géorgie du Sud-et-les Îles Sandwich du Sud

Quel est le pays le plus densément peuplé ?

In [27]:
indice, dens = cherche_indice_maximum(densites)

print(noms[indice])
Macao

II.2. Correction :

On s'intéresse à la première version de l'algorithme (sans les indices).

Comme on est face à une boucle Pour, la terminaison est identique à celle de la première partie.

Pour la correction partielle, on peut prendre comme invariant de boucle :

$$Après \: la \: boucle \: de \: rang \: k, \: la \: variable \: 'minimum' \: contient \: la \: valeur \: minimale \: des \: k+1 \: premièrs \: éléments \: du \: tableau$$

Prouvons que cet invariant est toujours vrai :

  1. Avant d'entrer dans la boucle ($k=0)$, $minimum$ contient la valeur du premier élément. La propriété est initialisée
  2. On suppose qu'il existe un rang $k$ pour lequel la propriété est vraie (hypothèse de récurrence)
  3. Lors de l'itération $k+1$, l'algorithme teste si l'élément d'indice $k+1$ est inférieur à la valeur cherchée et le stocke dans $minimum$ si c'est le cas. Sinon, il laisse $minimum$ à sa valeur antérieure. Donc après cette itération, $minimum$ contient bien le plus petit élément des $k+2$ premières valeurs (de $0$ à $k+1$) (héréditié).

On a donc prouvé la correction partielle.

II.3. Complexité :

Combien d'opération fait notre algorithme dans le pire des cas (l'extremum est en fin de tableau) ?

Appelons $n$ la taille du tableau.

L'algorithme parcourt tous les éléments : cela fait $n$ itérations.

Pour chacune d'entre elles, il compare l'élément en cours et l'extremum actuel : $1$ opération.

On a donc en tout $n$ opérations : la complexité est linéaire $\mathcal{O}(n)$.

On peut s'en rendre compte en mesurant le temps de calcul de la fonction :

In [28]:
# Données de taille 100
liste = list(range(100))

%timeit cherche_maximum(liste)
2.91 µs ± 39.7 ns per loop (mean ± std. dev. of 7 runs, 100000 loops each)
In [29]:
# Données de taille 100*100 => Temps 100 fois plus long ?
liste = list(range(100*100))

%timeit cherche_maximum(liste)
313 µs ± 11.5 µs per loop (mean ± std. dev. of 7 runs, 1000 loops each)

III. Calcul de moyenne :

III.1. Algorithme et code :

On se donne désormais un tableau de nombres et l'on souhaite calculer sa moyenne.

L'algorithme est :

  • somme prend la valeur 0
  • Pour tous les elements de table :
    • somme prend la valeur somme + element
  • Retourne somme / longeur(table)

En Python :

In [30]:
def moyenne(liste) :
    """
    Calcule la moyenne de la liste proposée
    liste est une série de valeurs numériques
    Renvoie la moyenne
    """
    
    somme = 0
    
    for element in liste :
        somme += element
    
    return somme / len(liste)

Quelle est la population moyenne ?

In [31]:
moyenne(populations)
Out[31]:
30463019.57312253

Quelle est la superficie moyenne ?

In [32]:
moyenne(superficies)
Out[32]:
599357.3201581028

III.2. Correction :

Comme on est face à une boucle Pour, la terminaison est identique à celle de la première partie.

Pour la correction partielle, on peut prendre comme invariant de boucle :

$$Après \: la \: boucle \: de \: rang \: k, \: la \: variable \: 'somme' \: contient \: la \: somme \: des \: k \: premièrs \: éléments \: du \: tableau$$

Prouvons que cet invariant est toujours vrai :

  1. Avant d'entrer dans la boucle ($k=0)$, $somme$ contient $0$ qui est bien la somme des $0$ premiers éléments. La propriété est initialisée
  2. On suppose qu'il existe un rang $k$ pour lequel la propriété est vraie (hypothèse de récurrence)
  3. Lors de l'itération $k+1$, l'algorithme ajoute l'élément d'indice $k$ à $somme$. Donc $somme$ contient bien la somme des $k+1$ premières valeurs (de $0$ à $k$) (héréditié).

On a donc prouvé la correction partielle.

III.3. Complexité :

Combien d'opération fait notre algorithme dans le pire des cas (l'extremum est en fin de tableau) ?

Appelons $n$ la taille du tableau.

L'algorithme parcourt tous les éléments : cela fait $n$ itérations.

Pour chacune d'entre elles, il ajoute l'élément en cours à la somme : $1$ opération.

Une fois sortie de la boucle, il divise somme par len(table) : $1$ opération.

On a donc en tout $n + 1$ opérations : la complexité est linéaire $\mathcal{O}(n)$.

On peut s'en rendre compte en mesurant le temps de calcul de la fonction :

In [33]:
# Données de taille 100
liste = list(range(100))

%timeit moyenne(liste)
3.39 µs ± 153 ns per loop (mean ± std. dev. of 7 runs, 100000 loops each)
In [34]:
# Données de taille 100*100 => Temps 100 fois plus long ?
liste = list(range(100*100))

%timeit moyenne(liste)
333 µs ± 16.7 µs per loop (mean ± std. dev. of 7 runs, 1000 loops each)