| Séance d'exercices 12, Programmation I |
| Sciences et Technologies du Vivant, Semestre 1 |
Les exercices marqués d'une étoile (*) sont des exercices supplémentaires de révision.
Dans cet exercice, vous allez écrire un programme vous permettant de caractériser et de représenter graphiquement un polygone.
Point
contenant deux entiers, afin de représenter un point et ses deux
coordonnées.
Couleur
permettant de représenter une couleur.
Polygone. Un polygone
peut être représenté par un ensemble de points et une
couleur (vous vous servirez des structures Point et
Couleur, définies plus haut). Un champ ferme
servira à indiquer si le polygone est fermé ou s'il
s'agit d'une ligne polygonale (ouvert).
affiche_polygone, dont le but
sera d'afficher un polygone dans une fenêtre graphique. Pour
cela, vous utiliserez la libraire swindow dont vous
vous êtes déjà servi lors de la leçon 10. La fonction
prendra un pointeur sur SimpleWindow ainsi qu'un pointeur
sur Polygone:
void affiche_polygone(SimpleWindow * window, Polygone * polygone)
Comme ici window est un pointeur, il faudra utiliser
l'opérateur -> plutôt que . pour accéder aux
champs et fonctions de window. Par exemple,
window->draw_line(...). On rappelle que
SimpleWindow est une classe C++, et les classes sont
une extension des structures. Comme pour les structures, on
utilise donc -> sur un pointeur au lieu du point (.).
Polygone nommé losange dans
main et remplissez ses champs, de manière à ce qu'il
représente correctement un losange. Initialisez ensuite une
nouvelle fenêtre. Vous pouvez utiliser le code suivant à cet
usage:
SimpleWindow window("Polygone", 300, 300);
window.map();
window.color(1, 1, 1);
window.fill();
Dessinez ensuite le losange dans la fenêtre à l'aide de la
commande affiche_polygone et faites afficher la fenêtre.
Ajoutez le code suivant à la fin de votre programme
cout << "Appuyez sur une touche pour continuer..." << endl; char a = getchar();
afin que le programme ne se termine pas tout de suite et que vous ayez le temps d'admirer votre losange.
On souhaite réaliser des statistiques sur les résultats d'un
sondage, pour lequel plusieurs personnes ont été interrogées
sur 3 questions notées
,
et
. Pour chacune des
personnes, on connaît son âge, son genre (M ou F), son salaire
annuel, et sa réponse (oui ou non) à chacune des trois
questions.
On décide de représenter la réponse d'une personne par la structure suivante:
struct Reponse {
int age;
char genre;
float salaire;
bool repA, repB, repC;
};
Reponse de 20
éléments dans la fonction main. Vous le nommerez
sondage. L'intérêt de déclarer un tableau de
pointeurs sur Reponse (Reponse *sondage[20])
plutôt qu'un tableau de Reponses
(Reponse sondage[20]) est que seuls les éléments
utilisés du tableau occupent de la mémoire.
Ceci est illustré par la figure 1.
![]() |
Comme le tableau contient des pointeurs, il faut éviter
de lire ou d'écrire dans un pointeur qui n'a pas été
initialisé. Pour ce faire, on attribue généralement la
valeur NULL (constante valant 0) à un pointeur, pour
indiquer qu'il ne pointe sur 'rien'. Après avoir déclaré
votre tableau sondage, ajoutez le code suivant pour
indiquer que le tableau est pour l'instant vide.
for (int i=0; i<20; i++) sondage[i] = NULL;
alloue_reponse qui alloue et initalise
une structure Reponse. La fonction aura l'en-tête suivante:
Reponse *alloue_reponse(int age, char genre, float salaire,
bool repA, bool repB, bool repC)
Elle devra allouer de la mémoire pour une nouvelle structure
Reponse et initialiser ses champs aux valeurs passées
en paramètres. Finalement, elle retournera un pointeur sur la
nouvelle structure.
Après avoir écrit votre fonction, entrez le code suivant
dans main pour initialiser un tableau avec 5 réponses
au sondage:
sondage[0] = alloue_reponse(35, 'M', 65000, false, true, false); sondage[1] = alloue_reponse(40, 'F', 80000, false, true, true); sondage[2] = alloue_reponse(52, 'F', 110000, true, true, true); sondage[3] = alloue_reponse(22, 'M', 50000, false, false, false); sondage[4] = alloue_reponse(45, 'F', 95000, true, true, false);
reponse_plus_haut_salaire qui prend
en paramètre un tableau de Reponse * ainsi que sa
taille, et qui renvoie la réponse (une valeur de type
Reponse *) de la personne ayant le plus haut
salaire. Prenez soin d'éviter les segmentation fault en
ne lisant que les pointeurs qui ont été correctement
initialisés.
Pour cette fonction et les suivantes, vérifiez votre code en
utilisant votre fonction dans main, en lui passant le
tableau sondage en paramètre, et en affichant le
résultat.
nombre_hommes_plus_de_trente_ans_AB
qui renvoie le nombre d'hommes de plus de trente ans qui ont
répondu oui aux questions Reponse * ainsi que sa taille.
moyenne_salaires_femmes_moins_de_100000, qui renvoie le
salaire moyen des femmes qui gagnent moins de 100'000 CHF. Si
aucune femme ne gagne moins de 100'000 CHF, la fonction devra
renvoyer Reponse * ainsi que sa taille.
au_moins_une_reponse_oui, qui
renvoie true si au moins une personne a répondu
oui aux trois questions, false sinon. La fonction
prend en paramètre un tableau de Reponse * ainsi que sa
taille.
Reponse * pointées par les
éléments du tableau ont été allouées dynamiquement
(avec new), il faut les supprimer manuellement. Faites-le
à l'aide de l'instruction delete, à la fin du
programme.
Dans cet exercice, vous allez réaliser une petite animation dans
une fenêtre graphique, à l'aide de la librairie
swindow. Une animation n'est rien d'autre qu'une successions
d'images (voir Figure 2) Une image, en
informatique, est un ensemble de points (nommés pixels)
répartis dans le plan. Pour stocker une animation, vous avez donc
besoin d'un tableau à 3 dimensions: 2 dimensions pour les axes
et
du plan et une troisième dimension pour le temps.
![]() |
animation.cpp dans lequel vous
déclarerez la librairie swindow. Déclarez trois
constantes globales (i.e. en dehors de main)
représentant la taille de votre animation:
const int largeur = 200;
const int hauteur = 100;
const int duree = 100;
Au début de votre
programme, déclarez un tableau de booléens à 3
dimensions que vous appellerez animation. La taille du
tableau sera de
.
efface en utilisant l'en-tête
ci-dessous:
void efface(bool tab[largeur][hauteur][duree])
Comme son nom l'indique, la fonction devra effacer le tableau passé en paramètre, c.-à-d. mettre toutes ses valeurs à false.
dessine_rectangle qui prend comme
paramètres un tableau à 3 dimensions de booléens
(bool t[largeur][hauteur][duree]), la taille du rectangle
selon les deux axes, sa position aussi selon les deux axes et le
numero de l'image dans laquelle il faut dessiner le rectangle
(i.e. le temps). Dessiner le rectangle revient à mettre à
true les pixels du tableau où se trouve le
rectangle. Prenez garde à ne pas excéder les dimensions du
tableau. Une bonne méthode est d'utiliser l'opérateur
modulo (%). De cette manière, si le rectangle
disparaît dans un bord de l'image, il réapparaitra de
l'autre côté.
anime_rectangle. Vous lui passerez
le tableau de booléens de l'animation, les coordonnées de
départ du rectangle, sa taille ainsi que sa vitesse (voir
Figure 3). Cette fonction devra dessiner le
carré dans toutes les images de l'animation. Elle utilisera la
valeur des vitesses pour savoir comment déplacer le rectangle
dans les images. La vitesse sera donnée en nombre de pixels à
parcourir entre deux images successives.
![]() |
affiche_animation. Cette fonction recevra un pointeur sur
SimpleWindow ainsi que le tableau de l'animation. Le but
de cette fonction est d'afficher l'animation dans la fenêtre
graphique. Elle devra fonctionner comme suit:
color de SimpleWindow);
draw_point;
show);
usleep. La
constante à passer à usleep dépend de la
puissance de votre ordinateur. Commencez avec 10'000 et
ajustez en fonction de la vitesse d'animation que vous
désirez obtenir.
main de
manière à tester votre animation.
Écrivez une fonction prenant pour paramètres deux tableaux
d'entiers A et B de même taille, ainsi que leur
taille. Cette fonction devra allouer un nouveau tableau R
dont la taille sera le double de celle de A ou
B. R sera ensuite construit de la façon suivante:
R sera le
premier élément de A,
R sera le premier élément de B,
R sera le deuxième élément de A,
La fonction renverra un pointeur sur le premier élément de
R.
Écrivez une fonction prenant un tableau T d'entiers et sa
taille en paramètres. La fonction devra allouer un nouveau tableau
T2. T2 sera construit de la façon suivante: Les
éléments de T d'indice pair seront placés dans
T2 à l'indice donné par l'élément suivant de
T. Exemple:
T[0] sera plaçé dans T2 à l'indice T[1],
T[2] sera plaçé dans T2 à l'indice T[3],
La fonction devra renvoyer un pointeur sur le premier élément de
T2. On remarquera que la taille de T doit être paire.
Si ce n'est pas le cas, la fonction devra renvoyer le pointeur 0 pour
indiquer une erreur.
Exemple:
T:
| 4 | 2 | 8 | 0 | 7 | 1 |
T2:
| 8 | 7 | 4 |
Écrivez une fonction
void damier(int largeur, int hauteur)
qui affiche un damier:
damier(4, 3);
# # # #
# # #
# # # #
# # #
# # # #
dont la taille (largeur et hauteur) sera passée en paramètre.
Écrivez une fonction qui affiche un triangle isocèle ``creux'' à
l'aide des caractères /, \ et _:
/\
/ \
/ \
/ \
/________\
Le nombre de lignes sera passé en paramètre. Attention, pour
afficher le caractère \, il faut le répéter deux
fois. Exemple: cout << "\\"; affiche un seul |.
Écrivez un programme qui trouve les 20 premiers nombres entiers dont la somme des chiffres est égale au produit de ces mêmes chiffres. Vous devez trouver 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 22, 123, 132, 213, 231, 312, 321, 1124, 1142 et 1214.
La suite de Fibonnacci est la solution au problème suivant: supposons qu'un couple (un mâle, une femelle) de lapins immatures soit mis dans un champ, que la maturité sexuelle du lapin soit atteinte après un mois qui est aussi la durée de gestation, que chaque portée comporte toujours un mâle et une femelle et que les lapins ne meurent pas. Combien y aura-t-il de lapins dans le champ après un an?
Écrivez un programme qui affiche les premiers termes de la suite de
Fibonacci. Cette suite qu'on notera
peut se calculer ainsi:
,
, et
. Essayez les deux
possiblités: avec et sans récursivité. Quelle version est la plus
rapide ?
Vérifiez que le quotient de 2 nombres consécutifs de la suite de
Fibonacci converge vers le nombre d'or
, qui
vaut environ 1.61803...
Un nombre parfait est un nombre (entier) égal à la somme de ses
diviseurs (ce nombre n'étant pas compté parmi ses diviseurs; en
revanche 1 en fait partie). Par exemple,
et
sont parfaits. Écrivez un programme qui trouve les
premiers nombres parfaits.
Deux nombres entiers
et
sont dits amicaux si la somme des
diviseurs de
(
non compris) vaut
et la somme des diviseurs
de
(
non compris) vaut
. Par exemple, 220 et 284 sont
amicaux. Écrivez une fonction ayant deux paramètres
et
, et
qui renvoie true si
et
sont amicaux, false
sinon.
Écrivez une fonction récursive permettant de traduire un nombre romain en un nombre sous la forme décimale. Il n'est pas nécessaire de vérifier la valididé du nombre romain. Pour rappel:
| romain | décimal |
| M | 1000 |
| D | 500 |
| C | 100 |
| L | 50 |
| X | 10 |
| V | 5 |
| I | 1 |
Dans cet exercice, vous allez apprendre à rechercher une valeur dans un tableau trié. La manière la plus simple est de parcourir le tableau jusqu'à ce qu'on trouve la valeur recherchée ou que l'on parvienne à la fin du tableau. Cependant, cette méthode n'est pas optimale. La recherche par dichotomie permet de faire bien plus rapide, en moyenne.
Soit un tableau
de
entiers triés. Supposons qu'on recherche
l'entier
. Une recherche par dichotomie s'effectue
comme suit:
Implémentez une fonction effectuant une recherche par dichotomie
dans un tableau d'entiers triés. La fonction devra être
récursive et prendra comme arguments un tableau d'entiers ainsi
que sa longueur et la valeur recherchée. La fonction retournera
l'indice du tableau où la valeur a été trouvée, ou
si
la valeur n'apparaît pas dans le tableau.