---------- Exercice 1 ---------- Un exercice peu difficile, redigeable de multiples manieres. Il faut chercher les departs de mots, et comparer leur valeur a celle d'un compteur char allant de 'a' a 'z'. Par exemple : (1) on ignore les espaces (2) lorsqu'on arrive a un depart de mot... (3) ... on verifie que le compteur n'a pas depasse la valeur 'z', et que la premiere lettre du mot et la valeur du compteur coincident. (4) dans ce cas, on incremente le compteur, et on passe les lettres restantes. (5) en fin de traitement, toutes les lettres de l'alphabet doivent avoir ete enumerees. int lettre(char c) { return 'a' <= c && c <= 'z'; } int est_abc(char *s) { char c = 'a'; int i = 0; while (s[i] != '\0') { if (!lettre(s[i])) i++; //(1) else { //(2) if (c > 'z' || s[i] != c) //(3) return 0; c++; //(4) while(lettre(s[i])) i++; } } return c == 'z' + 1; //(5) } ---------- Exercice 2 ---------- Cet exercice est un peu plus difficile a rediger que le precedent - la verification a effectuer est claire, mais il faut la mettre en forme. Il faut necessairement un tableau de marquage permettant de memoriser les lettres du mot rencontrees dans chaque ligne. Voici l'une des nombreuses solutions possibles, utilisant un inventaire de caracteres de taille 256 afin d'eviter d'avoir a rechercher des lettres dans m (on pourrait bien sur se contenter de 26, avec une verification a la fin de chaque ligne 10 fois plus rapide, mais aussi un code moins clair). Noter que le texte n'est jamais relu. (1) l'inventaire des lettres de m, (2) l'inventaire des lettres rencontrees dans chaque ligne (3) mise a 0 des inventaires (4) initialisation de l'inventaire de m (5) lecture de la ligne cl, m[cl] est la lettre interdite. (6) si t[i] est une lettre de m... (7) ... et n'est pas la lettre interdite... (8) ... on allume sa case dans l_inv. (9) une fois la ligne lue... (10) on verifie que toutes les lettres de m autorisees sont dans l'inventaire l_inv (on pourrait aussi relire m) tout en remettant a 0 l'inventaire. (11) si le compteur de ligne est a la fin de m, le texte doit etre fini. int absente(char *m, char *t) { int m_inv[256]; //(1) int l_inv[256]; //(2) int i, j, cl = 0; for (j = 0; j < 256; j++) { //(3) m_inv[j] = 0; l_inv[j] = 0; } for (i = 0; m[i] != '\0'; i++) //(4) m_inv[m[i]] = 1; i = 0; while(t[i] != '\0') { while(t[i] != '\n') { //(5) if (m_inv[t[i]]) { //(6) if (t[i] == m[cl]) //(7) return 0; l_inv[t[i]] = 1; //(8) } i++; } //(9) for (j = 0; j < 256; j++) { //(10) if (m_inv[j] && j != m[cl] && !l_inv[j]) return 0; l_inv[j] = 0; } cl++; i++; if (m[cl] == 0 && t[i] != '\0') //(11) return 0; } return 1; } ---------- Exercice 3 ---------- Un exercice simple. (1,2) la liste est deja sans clefs successives egales si elle est vide ou reduite a un element. (3) si les deux premiers clefs sont egales, on supprime la premiere, et on simplifie la liste commencant a la clef suivante. (4) sinon, on se contente de simplifier la liste commencant a la clef suivante. struct cell *non_iter(struct cell *pc) { struct cell *pcs; if (pc == NULL) //(1) return NULL; if (pc -> suiv == NULL) //(2) return pc; if (pc -> clef == pc -> suiv -> clef) { //(3) pcs = pc -> suiv; free(pc); return non_iter(pcs); } pc -> suiv = non_iter(pc -> suiv); //(4) return pc; } ---------- Exercice 4 ---------- (1) si l'une des deux listes est vide, le resultat est une liste vide. (2) si les premieres clefs de pc1, pc2 ne sont pas egales, on oublie leurs premieres cellules. (3) sinon, on cree une nouvelle cellule contenant la clef commune, et on la cable a l'intersection des listes pc1->suiv et pc2->suiv. struct cell *inter(struct cell *pc1, struct cell *pc2) { struct cell *pnc; if (pc1 == NULL || pc2 == NULL) //(1) return NULL; if (pc1 -> clef != pc2 -> clef) //(2) return inter(pc1 -> suiv, pc2 -> suiv); pnc = malloc(sizeof(struct cell)); //(3) pnc -> clef = pc1 -> clef; pnc -> suiv = inter(pc1 -> suiv, pc2 -> suiv); return pnc; } ---------- Exercice 5 ---------- la fonction auxiliaire peut prendre en parametre supplementaire la clef de reference. On ne garde de pc que les cellules contenant une clef au plus egale a cette clef : struct cell *aux(struct cell pc, int ref) { struct cell *pcs; if (pc == NULL) return NULL; if (pc -> clef > ref) { pcs = pc -> suiv; free(pc); return aux(pcs, ref); } pc -> suiv = aux(pc -> suiv,ref); return pc; } Voici la fonction principale. Noter la perte de la valeur de retour dans l'appel de la fonction auxiliaire. void *liste_inf(struct cell *pc) { if (pc == NULL) return; aux(pc -> suiv, pc -> clef); } -------------- Exercice Final -------------- Voici le moyen (tordu) dont on peut se passer de fonction auxiliaire. Il n'y a pas de traitement si la liste est vide ou reduite a un element. Sinon, on memorise l'adresse de la seconde cellule, on recable la premiere cellule a la liste commencant apres la seconde, on reinvoque la fonction sur la liste resultante (de meme premiere cellule que la liste initiale, mais privee d'une cellule, i.e. la recurrence termine effectivement). Au retour de l'appel recursif, on ne remet en place la seconde cellule que si sa clef n'est pas plus grande que la premiere. void *liste_inf(struct cell *pc) { struct cell pcs; if (pc == NULL) return; pcs = pc -> suiv; if (pcs == NULL) return; pc -> suiv = pcs -> suiv; liste_inf(pc); if (pc -> clef < pcs ->clef) { free(pcs); return; } pcs -> suiv = pc -> suiv; pc -> suiv = pcs; }