Introduction à la programmation – Premier semestre L1 Caen

TP17

Les tableaux et les pointeurs en langage C sont une notion qu’il faut aborder avec prudence. Je n’aborde ici que la notion de tableau qui couvre la partie notée.

L’utilisation des tableaux en C est un peu plus restrictive quand Python. Pour déclarer un tableau, il faut connaître le type des valeurs qu’il contiendra (elles seront toutes de ce type), et sa taille. Ainsi, un tableau contenant $10$ entiers sera déclaré : int mon_tab[10];. Pour accéder à une valeur d’un tableau, on retrouve les notations de Python : mon_tab[2] par exemple. Cette notation permet de récupérer la valeur comme la modifier. On peut également initialiser un tableau à sa déclaration en utilisant la notation {} :

int mon_tab[5] = {1,5,3,0,2};

On a alors deux variantes pour simplifier l’écriture. On peut écrire

int mon_tab[] = {1,5,3,0,2};

alors, le tableau crée aura exactement autant d’éléments que ceux qui sont donnés (ici 5). Ou on peut écrire

int mon_tab[5] = {1,5};

alors, les premiers éléments sont définis comme indiqué et les autres reçoivent la valeur 0. (Il faut toujours préciser au moins 1 éléments, même nul.)

On peut passer un tableau en argument à une fonction cependant, comme il n’existe pas de fonction pour obtenir la taille d’un tableau, il faut en plus préciser la taille du tableau si elle n’est pas connu par le programme. On rencontre alors le prototype suivant de fonction :

int ma_fonction(..., int mon_tableau[], int taille, ...) {
    //...
}

Comme en Python, si on modifie un tableau passé en paramètre à une fonction, alors le tableau initial est modifié. Si cela peut paraitre un inconvénient, il permet de palier à une restriction du C : il n’est pas possible de renvoyer un tableau. Ainsi, si on veut renvoyer un tableau, on utilise plutôt un tableau passé en paramètre.

Partie notée – MIASHS Groupe B

Question 1

int compteNotes(int tab[], int n) {
    int compteur = 0;
    int i;
    for (i = 0; i < n; i++) {
        if (tab[i] > -1) {
            compteur += 1;
        }
    }
    return compteur;
}

Question 2

float moyenneNotes(int tab[], int n) {
    float somme = 0;
    int i;
    for (i = 0; i < n; i++) {
        if (tab[i] > -1) {
            somme += tab[i];
        }
    }
    return somme / compteNotes(tab, n);
}

Question 3

void affiche(int tab[], int n) {
    int i;
    for (i = 0; i < n; i++) {
        if (tab[i] > -1) {
            printf("%d ", tab[i]);
        }
    }
    printf("\n");
}

Question 4

void Affiche_Absences(int tab[], int n) {
    int i;
    for (i = 0; i < n; i++) {
        if (tab[i] == -1) {
            printf("%d ", i);
        }
    }
    printf("\n");
}

Question 5

void etoiles(int n) {
    int i;
    for (i = 0; i < n; i++) {
        printf("*");
    }
    printf("\n");
}

Question 6

void histogramme(int *tab, int n, int *histo) {
    int i;
    for (i = 0; i < n; i++) {
        if (tab[i] != -1) {
            histo[tab[i]] += 1;
        }
    }
}

Question 7

int main() {
    int notes[] = {5, 8, 12, 10, 12, 12, -1,12, 13, 12, 7, 10, -1, 19, 14, 19, 13, 12, 12, 0, 13, 11, -1, 0, 10, 12, 13, 20};
    printf("Il y a %d étudiants.\n", compteNotes(notes, 28));
    printf("Moyenne : %f\n", moyenneNotes(notes, 28));
    printf("Rappel des notes : ");
    affiche(notes, 28);
    printf("Indices des absents : ");
    Affiche_Absences(notes, 28);

    int i;
    int histo[21] = {0};
    histogramme(notes, 28, histo);

    for (i = 0; i <= 20; i++) {
        printf("%d\t", i);
        etoiles(histo[i]);
    }
}

TP15

L’objectif de ce TP était la manipulation de dictionnaire Python. Un dictionnaire (python) est une structure de donnée associant à des clés (uniques) des valeurs. La syntaxe d’un dictionnaire python est la suivante : { cle1: valeur, cle2: valeur2, ...}. Ainsi le dictionnaire suivant

un_dictionnaire = {
    "chouette": ["oiseau", 2],
    4: random(),
    ("gui", 1): 'hello'
}

associe à la clé "chouette" la valeur ["oiseau", 2], à la clé 4 la valeur de retour de la fonction random et au tuple ("gui", 1) la valeur 'hello'. Pour récupérer une valeur d’un dictionnaire, on peut utiliser une syntaxe semblable à celle des listes : une_valeur = un_dictionnaire[une_cle], il faut que la variable une_cle contiennent une clé du dictionnaire sinon cela produit une erreur.

>>> une_cle = "chouette"
>>> print(un_dictionnaire[une_cle])
["oiseau", 2]
>>> print(un_dictionnaire[4])
0.0573980638852
>>> print(un_dictionnaire["abcd"])
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
KeyError: 'abcd'

Avec une syntaxe semblable on peut modifier et créer des entrées du dictionnaires.

>>> une_cle = "abcd"
>>> un_dictionnaire[une_cle] = 3
>>> print(un_dictionnaire[une_cle])
3
>>> un_dictionnaire[("gui", 1)] += ' world'
>>> print(un_dictionnaire[("gui", 1)])
hello world

Ces opérations sont simples quand on dispose des clés. Dans le cas général, ce n’est pas toujours le cas et on se retrouve à utiliser des boucles pour parcourir toutes les entrées du dictionnaire. Pour cela, on dispose de trois fonctions keys(), values() et items() qui renvoie des objets python semblable à des listes que l’on peut utiliser dans les boucles for.

un_dictionnaire = {
    "chouette": ["oiseau", 2],
    4: random(),
    ("gui", 1): 'hello'
}
print("Clés:", un_dictionnaire.keys())
print("Valeurs:", un_dictionnaire.values())
print("Paires (clé, valeur):", un_dictionnaire.items())
Clés: dict_keys(['chouette', 4, ('gui', 1)])
Valeurs: dict_values([['oiseau', 2], 0.006778959892546066, 'hello'])
Paires (clé, valeur): dict_items([('chouette', ['oiseau', 2]), (4, 0.006778959892546066), (('gui', 1), 'hello')])

Ainsi, pour parcourir toutes les clés on peut écrire :

for cle in un_dictionnaire.keys():
    print(cle, un_dictionnaire[cle])
    if cle == 4:
        un_dictionnaire[cle] += 2
    # ...

ceci permet de récupérer ou modifier les valeurs associées à chaque clé. Pour parcourir seulement les valeurs sans s’intéresser aux clés, on peut écrire :

for valeur in un_dictionnaire.values():
    print(valeur)
    # ...

La fonction items permet de récupérer les paires (cle, valeur) permettant ainsi de s’éviter la syntaxe dictionnaire[cle] pour récupérer la valeur :

for cle, valeur in un_dictionnaire.items():
    print(cle, valeur)
    # ...

De manière plus concise, on peut aussi parcourir les clés d’un dictionnaire sans utiliser la fonction keys de la manière suivante :

for cle in un_dictionnaire:
    # ...

Il faut noter que les objets renvoyer par ses fonctions se comportent comme des listes, donc on peut aussi vérifier si une clé est dans un dictionnaire avec la notation cle in un_dictionnaire.keys() (ou même cle in un_dictionnaire ) et si une valeur est associé à une clé valeur in un_dictionnaire.values().

Partie notée – MIASHS Groupe B

Dans ce TP, on manipule des dictionnaires représentant le contenu de sacs. Chaque sac est représenté par un dictionnaire associant à chaque type de contenu son poids.

Question 1

Pour calculer le poids d’un sac, on doit sommer le poids de chaque type de nourriture. On a donc seulement besoin des valeurs du dictionnaire en argument. La fonction values() est donc toute indiquée.

def poids_sac(sac):
    resultat = 0
    for poids in sac.values():
        resultat += poids
    return resultat

On pourrait également exploiter la fonction sum qui somme les valeurs dans une liste. Le code devient alors

def poids_sac(sac):
    return sum(sac.values())

Question 2

Cette fois-ci on dispose d’une liste de sacs, donc une liste de dictionnaires. On veut cumuler le poids de chaque sac. On sait calculer le poids d’un sac, donc on peut utiliser la fonction précédente.

def poids_picnic(sacs):
    resultat = 0
    for sac in sacs: # sacs n'est *pas* un dictionnaire
        resultat += poids_sac(sac)
    return resultat

Question 3

On ne veut plus le poids total de nourriture mais le poids total par type de nourriture. Cela revient à calculer le contenu d’un grand sac qui contiendrait tous les autres.

Ici, on peut utiliser la fonction items. Pour chaque sac et pour chaque nourriture dans le sac, on l’ajoute à un gros sac, le résultat. Il faut vérifier si la nourriture est déjà présente dans le sac pour l’ajouter ou définir son poids.

def picnic(sacs):
    resultat = {}
    for sac in sacs:
        for nourriture, poids in sac.items():
            if nourriture not in resultat:
                resultat[nourriture] = poids
            else:
                resultat[nourriture] += poids
    return resultat

Question 4

On veut savoir si un picnic (représenté par une liste de sac) est valide. Les conditions se vérifient par des comparaisons entre les poids de différentes nourritures.

On peut donc calculer la quantité de chaque type de nourriture avec la fonction qui précède, puis utiliser le dictionnaire obtenu pour faire les comparaisons.

def picnic_ok(sacs):
    poids = picnic(sacs)
    if poids['boisson'] < 30 * poids['chips']:
        return False

    if poids['pain'] < poids['fromage'] + poids['charcuterie']:
        return False

    if poids['fruit'] < 0.2*len(sacs):
        return False

    return True

TP12

Partie notée – MIASHS Groupe B

Le sujet de ce TP noté était la manipulation de grille vue en TP lors des deux dernières séances de TP. Une grille d’entiers de $n$ colonnes et $p$ lignes peut être représenté en python par un tableau à $n$ entrées dont les valeurs sont des tableaux de $p$ entiers. Par exemple, la grille à $2$ lignes et $3$ colonnes

4 5 6
1 9 7

est représenté par le tableau de tableaux suivant [[4,5,6],[1,9,7]].

Étant donnée une grille python stocké dans une variable ma_grille, on accède à la 2e valeur de la 1er ligne, en récupérant tout d’abord la 1er ligne ma_ligne = ma_grille[0]. Cette ligne étant également un tableau python, on récupère sa deuxième valeur comme tout tableau avec la notation ma_ligne[1]. Comme ma_grille[0] est un tableau, on n’a pas besoin d’utiliser la variable ma_ligne et directement accéder à l’élément désiré par ma_grille[0][1].

Avant de pouvoir manipuler une grille python, il faut être capable de la créer. Pour cela, on a vu qu’un code de la forme

ma_grille = [[0] * p]*n

n’est pas un code correct car chaque élément du tableau ma_grille fait référence au même tableau. Pour avoir $n$ lignes distinctes, il faut créer $n$ tableaux distincts. On a alors le code

def cree_grille(n, p):
    ma_grille = []
    for n in range(n):
        ma_grille.append([0] * p)
    return ma_grille

Question 1

Pour créer une grille une grille de valeurs aléatoires, on va utiliser la fonction randint. On souhaite obtenir des valeurs aléatoires paires entre $0$ et $9$. Seules les valeurs $0$, $2$, $4$, $6$, $8$ sont donc autorisées. Plutôt que de tirer un entier entre $0$ et $9$ et de le rejeter s’il est impair, on peut directement produire des nombres pairs en tirant des nombres entre $0$ et $4$ et en multipliant la valeur tirée par $2$.

from random import randint

def grille_alea(n, p):
    # On crée une grille de n lignes et p colonnes
    ma_grille = cree_grille(n, p)

    # On affecte ensuite à chaque case une valeur tirée aléatoirement
    for i in range(n):
        for j in range(p):
            ma_grille[i][j] = randint(0,4)*2

    return ma_grille

Question 2

Pour avoir un affichage plus humain d’une grille, plusieurs méthodes sont possibles. En voici deux. L’une en créant une chaine de caractères par ligne, on utilise ici l’accès aux éléments par leurs indices.

def afficher(grille):
    n = len(grille)
    p = len(grille[0])

    for i in range(n):
        # pour chaque ligne de la grille, on crée une chaine de caractères qui
        # contiendra ce que l'on souhaite afficher
        ma_ligne = ""
        for j in range(p):
            ma_ligne += str(grille[i][j]) + " "
        print(ma_ligne)

La seconde en exploitant l’argument end="" de la fonction print, on itère ici directement sur les éléments.

def afficher(grille):
    for ligne in grille:
        for valeur in ligne:
            print(valeur, "", end="")
        print()

Question 3

On désire calculer à partir d’une grille et d’un entier $k$ une nouvelle grille contenant les valeurs de la grille en entrée multipliées par $k$. On va donc parcourir chaque valeur de la grille en entrée, la multiplier par $k$ et affecter le résultat à la case de même position dans la grille à calculer.

def multiplication(grille, k):
    n = len(grille)
    p = len(grille[0])

    # On reprend le code de grille_alea
    ma_grille = cree_grille(n, p)

    # et on complète par la multiplication demandée
    for i in range(n):
        for j in range(p):
            ma_grille[i][j] = grille[i][j] * k

    return ma_grille

Question 4

La transposée d’une grille correspond à l’échange des colonnes et de lignes comme dans un miroir. Ainsi, la grille en introduction a pour transposée.

4 1
5 9
6 7

Lire les valeurs de la transposée colonne par colonne revient alors à lire les valeurs ligne par ligne de l’original.

Cette lecture se traduit directement sur les indices, la valeur en position $(j,i)$ de la transposée est la valeur de la grille initiale en position $(i,j)$.

def transpose(grille):
    n = len(grille)
    p = len(grille[0])

    # On reprend le code de grille_alea en échangeant n et p
    ma_grille = cree_grille(p, n)

    # on copie ensuite les données en échangeant les indices pour la transposée
    for i in range(n):
        for j in range(p):
            ma_grille[j][i] = grille[i][j]

    return grille

Question 5

La diagonale d’une grille carré est la suite des valeurs qui sont en position $(i,i)$. Pour récupérer cette suite, on doit donc créer une liste qui sera de taille $n$ pour une grille carré de côté $n$.

def diagonale(grille):
    n = len(grille)

    # la diagonale a n valeurs
    resultat = [0]*n
    for i in range(n):
        # les indices sur la diagonales sont égaux (i=j)
        resultat[i] = grille[i][i]

    return resultat

TP10

Partie notée – MIASHS Groupe B

Dans ce TP, il faut réaliser 4 fonctions, chacune prenant en argument une liste ou une chaine de caractères et renvoyant un résultat.

Ce résultat ne doit pas être affiché dans le code de la fonction. Il peut cependant être affiché à l’extérieur à des fins de test.

Question 1

On dispose une liste d’entiers et on souhaite savoir si celle-ci est triée. Pour cela, il suffit de vérifier si deux valeurs successives de la liste sont bien dans le bon ordre.

J’ai pris plusieurs fois en TP l’analogie d’un paquet de cartes. Imaginez que vous disposer d’un jeu de carte et vous vous demandez s’il est trié. Vous allez alors prendre les cartes une par une en vérifiant que chaque carte est plus petite que la suivante. Aussi, si vous rencontrez une carte plus grande que sa suivante, vous pouvez affirmer que le paquet n’est pas trié.

Ceci se traduit par le code suivant.

def est_croissante(l):
    # Pour chaque position de carte
    # (sauf la dernière qui n'a pas de suivante)
    for a in range(len(l)-1) :
        # Si elle n'est pas plus petite que la suivante
        if not l[a] <= l[a+1]:
            # alors on sait que la liste n'est pas croissante
            return False
    # Quand on arrive ici, on a bien vérifié que les cartes étaient dans l'ordre croissant
    return True

Question 2

On ne dispose plus d’une liste d’entiers, mais d’une liste de chaines de caractères. On souhaite maintenant obtenir la liste des longueurs de ces chaines.

Il faut donc calculer la longueur de chaque chaine de caractères dans la liste.

Comme il faut renvoyer la liste de ces longueurs, il nous faut également créer une liste pour les y placer.

def longueurs(l):
    # On crée la liste qui contiendra les longueurs
    resultat = []
    # Pour chaque chaine de caractères dans la liste `l`
    for a in l:
        # on calcule sa longueur et on rajoute la stocke
        resultat.append(len(a))
    return resultat

Question 3

Les questions précédentes nous donnent deux fonctions, l’une pour calculer les longueurs de chaines de caractères, et l’autre pour vérifier si une suite d’entiers est croissante.

Donc si on calcule la liste des longueurs des chaines de caractères et qu’on utilise la liste obtenu comme argument de la fonction est_croissante, on sait si la liste des longueurs des chaines de caractères est croissante.

C’est justement ce qu’il nous faut.

def longueurs_croissantes(l):
    return est_croissante(longueurs(l))

Question 4

La dernière question de ce sujet est un peu indépendante des autres. On travaille maintenant sur une seule chaine de caractères.

On veut isoler le premier mot d’une chaine de caractère, c’est à dire tout le début de la chaine jusqu’à la première espace. (On pourrait être plus précis, mais on va se satisfaire de cette définition).

Pour réaliser ceci, il faut une variable qui va contenir le premier mot. Et afin de s’arrêter à la première espace, on doit parcourir chaque caractère en construisant peu à peu le premier mot.

def premiet_mot(s):
    # On part d'une chaine de caractères vide
    mot = ''
    # Puis pour chaque caractère
    for c in s:
        # S'il est différent d'une espace, on l'ajoute à notre premier mot
        if c != ' ':
            mot += c
        # et sinon, on a trouvé notre premier mot, et on le renvoie
        else:
            return mot
    # il ne faut pas oublier le cas où il n'y a aucune espace
    return mot