Aller au menu - Aller au contenu

Exercices pour débutants en C

Au menu : zSommeChiffres (nombres, algo)

Pour accéder à cette section
Connectez-vous !
connexion_rpx
Page Précédente  1  2  3  ...  24  25  26  27  28  29  30  ...  50  51  52  53  Suivante
Auteur Message
1 visiteur sur ce sujet (1 Anonyme)
Page Précédente  1  2  3  ...  24  25  26  27  28  29  30  ...  50  51  52  53  Suivante
Hors ligne GurneyH # Posté le 09/05/2009 à 08:34:06
Avatar

Reprise du dernier message de la page précédente :
Salut,

Une autre version, avec l'algorithme Boyer-Moore simple.
Le principe consiste à précalculer les déplacement à effectuer dans la chaîne(haystack) lorsqu'il n'y a pas d'occurrence de la sous_chaîne(needle) à la position courante.
Secret (cliquez pour afficher)
Code : C
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
/* Algorithme de Boyer-Moore simple*/
#include <stdio.h>
#include <limits.h>

/* retourne la longueur d'une chaîne caractères */
static size_t my_strlen(char const *src)
{
    char const *cpy = src;
    while (*cpy++);

    return --cpy - src;
}


char *my_strstr(char const *haystack, char const *needle)
{
    char *res = NULL;
    int tab[UCHAR_MAX + 1];
    int i;
    int nLen = my_strlen(needle);
    int hLen = my_strlen(haystack);
    if (nLen && hLen)
    {
        for (i = 0; i < UCHAR_MAX + 1; i++)
            tab[i] = nLen;
        for (i = 0; i < nLen - 1; ++i)
            tab[(size_t)needle[i]] = nLen - 1 - i;

        while (hLen >= nLen && !res)
        {
            i = nLen - 1;
            while(haystack[i] == needle[i] && !res)
            {
                if (!i)
                    res = (char *)haystack;
                --i;
            }
            if (!res)
            {
                hLen     -= tab[(size_t)haystack[nLen - 1]];
                haystack += tab[(size_t)haystack[nLen - 1]];
            }
        }
    }
    return res;
}


int zStrSearch(const char *haystack, const char *needle)
{
    const char *occ = haystack;
    int cpt = 0;

    while(occ)
    {
        occ = my_strstr(occ, needle);
        if (occ != NULL)
        {
            printf("Une occurence a la position %d\n", 1 + occ - haystack);
            occ++;
            cpt++;
        }
        else
        {
            if (!cpt)
                printf("Pas d'occurence.\n");
        }
    }
    return cpt;
}

int main(void)
{
    const char *meule = "blffoobarblofoohaha";
    const char *aiguille = "foo";

    printf("%d occurences trouvees\n", zStrSearch(meule, aiguille));
    return 0;

}


a++
 
Hors ligne HighTam # Posté le 09/05/2009 à 21:53:40
Sleep(FOR_EVER);
Avatar

Ville : Sfax
Pays : Tunisie

zx-spectrum ==>

Code : C
1
2
3
4
5
6
7
8
9
for (j = i; j < i+len2 ; j++)
{
    if (chaine1[j]==chaine2[j-i]) trouve++;
    else
    {
        i=i+len2;
        /*break; equivalent pour i = i+ len2;*/
    }
}


Supposons quelen2 = 5
Au premier tour :i = j = 0
Code : C
1
2
3
4
5
6
if (chaine1[j]==chaine2[j-i]) trouve++;
else
{
    i=i+len2;
    /*break; equivalent pour i = i+ len2;*/
}

Supposons quechaine1[0] != chaine2[0-0]
Donci = i + len2 = 0 + 5 = 5

On retourne toujours dans la boucle car :j < i+len2
Puis : if (chaine1[j]==chaine2[j-i]) trouve++;
Orj = 1 eti = 5
Donc on teste :if (chaine1[1]==chaine2[1-5])
chaine[-4] n'existe pas.

Enfin, quand j'exécute ton code, j'obtiens une erreur de violation d'accès. (A la ligne 33)


Tosh ==>

J'ai testé avec ton code :
Code : C
1
2
3
4
5
6
7
8
int main(void)
{
  char sousChaine[] = "fofo";
  char chaine[] = "fofofo";
  printf ("Occurences trouvées : %d\n", zStrsearch (sousChaine, chaine));

  return 0;
}


Code : Console
Occurence trouvée en : 1
Caractères lus : 8
Occrences trouvées : 1


Alors, qu'il faut trouver 2 occurrences : fofofo et fofofo

Cette erreur vient du fait que :

Code : C
1
2
3
4
5
6
7
if (test == longueurS)
{
    printf ("Occurence trouvée en : %d\n", i + 1);
    test = 0;
    occurences++;
    i += longueurS - 1;
}


Voilà, dès que tu trouves la première occurence tu fais :i += 4 - 1 donc i = 3 .
Donc tu te trouves au caractère fofofo.
C'est normal donc que tu ne trouves pas la deuxième occurrence.


Je redonne mes solutions :
La première (Je pense qu'elle utilise l'algorithme de KMP mais je ne suis pas sûr) :
Secret (cliquez pour afficher)
Code : C
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
void findString(const char* str, const char* underStr)
{
    int i = 0, j = 0, back = 0, strike = 0, done = 0;
    for (i = 0 ; str[i] != '\0' ; i++)
    {
        if (str[i] == underStr[0])
	{
	    for (j = 1 ; underStr[j] != '\0' && !strike ; j++)
            {
	        if (str[i+j] == underStr[0] && !done)
		{
		    back = i+j;
		    done = 1;
	        }
		else if (str[i+j] != underStr[0] && !done)
		    back = i+j+1;

		if (str[i+j] != underStr[j])
		    strike = 1;
            }
            if (!strike)
	        printf("%d  ", i);
			
            i = back > i ? back-1 : i;
	}
	strike = 0;
        done = 0;
    }
}


La deuxième (La solution naïve) :
Secret (cliquez pour afficher)
Code : C
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
void findString(const char* str, const char* underStr)
{
    int i = 0, j = 0, strike = 0;
    for (i = 0 ; str[i] != '\0' ; i++)
    {
        if (str[i] == underStr[0])
	{
	    for (j = 1 ; underStr[j] != '\0' && !strike ; j++)
	    {
		if (str[i+j] != underStr[j])
	            strike = 1;
            }
            if (!strike)
                printf("%d  ", i);
	}
	strike = 0;
    }
}
Édité le 09/05/2009 à 23:01:40 par HighTam

Windows Vista User

Rule n°25 : Relation to the original topic decreases with every single post.
 
Hors ligne RaSaN20 # Posté le 14/05/2009 à 20:03:29
Avatar

une bonne idée je participe

quand on veut on peut
 
Connecté Tosh # Posté le 14/05/2009 à 23:02:59
"La musique peut rendre libre"
Avatar

Ah, merci HighTam.

J'ai édité mon code, mais du coup l'algorithme est moins performant.

Un MMORPG gratuit en 3D pour Linux, Windows et Mac ? C'est par ici !

 
Hors ligne zx-spectrum # Posté le 19/05/2009 à 10:21:53
http://www.worldofspectrum.org
Avatar

Citation : HighTam
zx-spectrum ==>

Code : C
1
2
3
4
5
6
7
8
9
for (j = i; j < i+len2 ; j++)
{
    if (chaine1[j]==chaine2[j-i]) trouve++;
    else
    {
        i=i+len2;
        /*break; equivalent pour i = i+ len2;*/
    }
}


Supposons quelen2 = 5
Au premier tour :i = j = 0
Code : C
1
2
3
4
5
6
if (chaine1[j]==chaine2[j-i]) trouve++;
else
{
    i=i+len2;
    /*break; equivalent pour i = i+ len2;*/
}

Supposons quechaine1[0] != chaine2[0-0]
Donci = i + len2 = 0 + 5 = 5

On retourne toujours dans la boucle car :j < i+len2
Puis : if (chaine1[j]==chaine2[j-i]) trouve++;
Orj = 1 eti = 5
Donc on teste :if (chaine1[1]==chaine2[1-5])
chaine[-4] n'existe pas.

Enfin, quand j'exécute ton code, j'obtiens une erreur de violation d'accès. (A la ligne 33)



je piges pas que tu trouves une erreur dans mon code, je viens "de verifier à la main mon prog" je n'ai pas d'indice négatif :
Secret (cliquez pour afficher)
Code : C
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
#include <stdio.h>
#include <stdlib.h>

int lenString ( char *chaine)
/*en entrée : une chaine de caractere nommé chaine*/
/*en sortie : donne le nombre de caractere de la chaine*/
/*traitement :calcule la longueur d'une chaine*/
{
    int len =0;
    while ( chaine[len] != '\0' )
    {
        len ++ ;
    }
    return len;
}

int occurence (char *chaine1, char *chaine2)
{
    int nb_occurence =0;/*pour compter les occurences*/
    int len1,len2;/*pour les longueurs de chaines à traiter*/
    int i=0,j=0;/*compteurs de boucle de boucle*/
    int trouve;/*la chaine est identique si trouve = len2*/
    len1 = lenString(chaine1);
    len2 = lenString(chaine2);
    int z = len1-len2+1;
    if (len2 !=0) /*dans le seul cas ou la chaine contient rien*/
    {
        i=0;
        while (i< z)
        {
            trouve = 0;
            for (j=i;j<i+len2;j++)
            {
                if ((j-i) !=0) printf("%d  ",j-i);/*ligne test j-i*/
                if (chaine1[j]==chaine2[j-i]) trouve++;
                else
                {
                  /* i=i+len2; */
                  break;
                }
            }

            if (trouve == len2)
            {
                nb_occurence ++ ;
                printf ("en position N.: %d\n",i+1);
            }

            i++;
        }
    }
    return nb_occurence;
}
int main(void)
{
    char chaine[]="ZxHello word ! Zx-Spectrum soluce, exercice may 2009. Easy soluce by Zx";
    char ch[]="soluce";

    printf("%s\n-->%s<--\n",chaine,ch);
    printf("nous avons %d occurence(s) trouvee(s)",occurence (chaine,ch));
    return 0;
}

@+

Hors ligne Drủby♣B75 # Posté le 20/05/2009 à 06:00:18
<br />
Avatar

waa c'est pas mal de proposé des exercices comme ca , Dommage je suis au debut de la

2 partie des tuto a Matheo , mais je le ferait quand j'orai ratrapée mon retard

thx

[URL=http://sms.informatiquefrance.com][IMG]http://informatiquefrance.free.fr/sms/mini-banniere-bleu.png[/IMG][/URL]
 
Hors ligne HighTam # Posté le 24/05/2009 à 15:56:41
Sleep(FOR_EVER);
Avatar

Ville : Sfax
Pays : Tunisie

zx-spectrum ==>
Tu as remplacé ça :
Citation : HighTam
Code : C
1
2
3
4
5
6
if (chaine1[j]==chaine2[j-i]) trouve++;
else
{
    i=i+len2;
    /*break; equivalent pour i = i+ len2;*/
}


Par ça :
Citation : zx-spectrum
Code : C
1
2
3
4
5
6
if (chaine1[j]==chaine2[j-i]) trouve++;
else
{
    /* i=i+len2; */
    break;
}


C'est pourquoi, ça marche maintenant !
Apparemment, contrairement à ce que tu dis :break n'est pas équivalent ài=i+len2
(/*break; equivalent pour i = i+ len2;*/ )

Je teste avecbreak et ça marche.
Et je teste aveci = i+ len2 , j'obtiens :
Secret (cliquez pour afficher)
Erreur
Édité le 24/05/2009 à 15:59:02 par HighTam

Windows Vista User

Rule n°25 : Relation to the original topic decreases with every single post.
 
Hors ligne zx-spectrum # Posté le 24/05/2009 à 20:20:42
http://www.worldofspectrum.org
Avatar

Merci hightam, pour ton explication
effectivement tu avais raison
@+
Hors ligne Eusebus # Posté le 29/05/2009 à 20:30:42
Geek mangeur de cookies
Avatar

Bonjour à tous.

Comme vous avez pu le constater, j'ai été assez absent du topic ce mois-ci, mais un déménagement ça prend du temps. :p

Donc, je vais déjà vous proposer une correction pour l'exercice que je vous avez soumis le mois dernier. Il y a eu pas mal de participations, c'est une bonne chose. Vous ne pourrez pas dire après que vous n'êtes pas à l'aise avec les chaînes de caractères en C (du moins je l'espère :-° ) ! Rappelez-vous, il s'agissait de trouver, dans une chaîne de caractères donnée, une certaine sous-chaîne (que j'appellerai pattern dans la suite). Il y avait plusieurs possibilités, la plupart d'entre-vous ont choisi de coder ce que j'avais appelé la méthode "naïve". En effet, c'est la manière la plus "naturelle" de traiter le problème.

Elle consiste simplement à comparer un à un les caractères du pattern avec le texte de départ. On commence bien sûr au début de la chaîne, et s'il y a une concordance, on le signale, sinon on passe à la position suivante en décalant d'un caractère la position de départ de comparaison. On recommence le tout jusqu'à ce qu'on ait exploré toutes les positions exploitables. Cet algo est assez gourmant, car si on note n la taille de la chaine et m celle du pattern, cet algo est en O((n - m + 1)m). En voici une implémentation possible :

Code : C
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
#include <stdio.h>

size_t my_strlen(const char *s);

int main(void)
{
        const char str[] = "foobarfofoobafoobarffoobfoo";
        const char pattern[] = "foo";
        size_t slen = my_strlen(str), plen = my_strlen(pattern), i, j;
        int find = 0;

        /* Parcours de la chaine */
        for(i = 0; i < slen - plen + 1; i++)
        {
                /* Parcours et comparaison du pattern */
                for(j = 0; j < plen && str[i + j] == pattern[j]; j++);

                if(j == plen)
                {
                        find = 1;
                        printf("Occurence en position %d\n", i + 1);
                }
        }

        if(!find)
                puts("Aucune occurence trouvee");

        return 0;

}

size_t my_strlen(const char *s)
{
        size_t i = 0;

        while(s[i] != '\0')
                i++;

        return i;
}


Je pense que le code est assez explicite, je vais juste expliquer la borne supérieure de i. Un petit schéma devrait suffir pour comprendre :

Code : Autre
1
2
3
4
5
Exemple :

       v
FOOBARFOO
      BAR


Là on en est à la dernière position possible, simplement car à la position d'après (celle marquée par le v), notre pattern "dépasse" de la chaîne et on s'évite de traiter ces cas-là. Si vous observez bien, vous verrez qu'il y a taille("FOOBARFOO") - taille("FOO") + 1 solutions possibles (pour parler plus technique, c'est en fait l'application d'une petite formule qui donne le nombre d'entiers dans un intervalle entier [a,b] qui est b-a+1).

Alors, il est possible d'appliquer toutes sortes de petites optimisations, comme par exemple le fait de mémoriser la prochaine position en se basant sur le premier caractère (du pattern) si on le rencontre lors de notre parcours du pattern. Ce qui peut nous faire penser à la chose suivante : pour optimiser un peu notre recherche, il pourrait être bien d'utiliser les informations que l'on obtient lors d'un parcours du pattern, afin de s'affranchir de certaines positions dont on sait qu'elles ne pourront pas être valides. Un algorithme efficace que l'on peut trouver est celui de Knuth-Morris-Pratt (lien wiki), qui fait d'abord un pré-traitement du pattern (en \theta(m) )puis qui utilise ces infos pour progresser plus efficacement (on parcourt simplement la chaîne et on aura des sauts, opération en \theta(n)). On passe alors à une complexité en \theta(n+m) si l'on garde les notations précédemment utilisées ce qui est bien mieux que le cas précédent. Une seule personne a proposé un code pour cet algo (redskull, pour le citer), j'aurais pensé que plus de monde aurait tenté sa chance ^^ .

Pour ceux qui veulent se frotter à cet algorithme (et je vous y encourage !), sachez qu'il n'est pas forcément évident à comprendre (ce qui explique surement pourquoi pratiquement personne ne s'y est aventuré ?), et j'avoue que vous l'expliquer serait assez long et je n'en ai malheureusement pas le temps, mais il est intéressant je trouve. Ca dépasse le cadre du vrai débutant, néanmoins je me permets d'en poster une implémentation. Je précise que je me suis grandement aidé du livre "Introduction à l'algorithmique" de Cormen, Leiserson, Rivest & Stein (souvent appelé "le Cormen" ou le "CLRS") ; excellent livre, de ce que j'en ai lu, mais qui demande de (très) bonnes bases en maths. Je propose donc cette implémentation :

Code : C
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
#include <stdio.h>
#include <stdlib.h>

int *prefix_fun(const char *s, const size_t len);
size_t my_strlen(const char *s);

int main(void)
{
        const char str[] = "foobarfofoobafoobarffoobfoo";
        const char pattern[] = "foo";
        size_t slen = my_strlen(str), plen = my_strlen(pattern),
            q = 0, find = 0, i;
        int *prefix = NULL; 

        /* q : nombres de caractères correspondants
         * prefix : tableau de prétraitement du pattern */

        prefix = prefix_fun(pattern, plen);

        if(prefix == NULL)
        {
                perror("malloc()");
                exit(EXIT_FAILURE);
        }

        printf("Chaine : %s\nPattern : %s\n", str, pattern);

        for(i = 0; i < slen; i++)
        {
                while(q > 0 && pattern[q] != str[i])
                        q = prefix[q - 1];

                if(pattern[q] == str[i])
                        q++;

                if(q == plen)
                {
                        printf("Occurence en position %d\n",
                                i + 2 - plen);
                        q = prefix[q - 1];
                        find = 1;
                }
        }

        if(!find)
                puts("Aucune occurence.");

        free(prefix);

        return 0;
}

size_t my_strlen(const char *s)
{
        size_t i = 0;

        while(s[i] != '\0')
                i++;

        return i;
}

/* Fonction de pré-traitement du pattern */

int *prefix_fun(const char *s, const size_t len)
{
        int *tab = malloc(len * sizeof *tab);
        size_t q, k = 0;

        if(tab != NULL)
        {
                tab[0] = 0;

                for(q = 1; q < len; q++)
                {
                        while(k > 0 && s[k] != s[q])
                                k = tab[k - 1];

                        if(s[k] == s[q])
                                k++;

                        tab[q] = k;
                }
        }

        return tab;
}



Voilà, merci à tous les participants, prochain exercice... dans pas longtemps (oui, je ne me mouille pas trop là, je sais. :p).

"Ce qui est affirmé sans preuve peut être nié sans preuve" Euclide
"Tout ensemble inductif admet au moins un élément maximal." Lemme de Zorn
 
Hors ligne Monsieur_JaKy # Posté le 10/06/2009 à 18:07:12
JaKy & Rory FTW!
Avatar

Ville : Bourges
Pays : France métropolitaine

J'up pour demander quand viendra le nouvel exercice...Car ça fait fait déjà 2 semaines sans réponses.
Édité le 10/06/2009 à 18:07:29 par Monsieur_JaKy
 
Hors ligne shareman # Posté le 10/06/2009 à 18:27:22
charlotte <3
Avatar

Ville : Mertzwiller
Pays : France métropolitaine

Exercice du mois de Juin : < zBrace >



Après la longue et intéressante correction de l'exercice sur la recherche de sous-chaîne par Eusebus, je propose ici (un petit exo parce que j'ai du temps, surtout que c'est bientôt les vacances) un nouvel exercice intitulé zBrace. C'est avant tout un exercice qui demandera énormément de réflexion, en premier lieu au niveau algorithmique puis au niveau du codage même en C (mais c'est surmontable).

Objectif


L'idée de cet exercice peut se résumer en quelques mots : coder un algorithme qui vérifie qu'une expression est correctement parenthésée. Une expression désigne ici n'importe quoi, en réalité, tous les caractères sauf '(' et ')' peuvent être utilisés et ces deux derniers seront utilisés pour la représentation des parenthèses. Vous pouvez permettre à l'utilisateur de choisir les caractères de ses parenthèses (c'est plus pratique et plus générique) comme '[' ']' ou encore '{' '}'.

Voici un petit test qui devrait être facilement réalisable avec votre algorithme (d'où l'utilité de s'organiser, faites des fonctions ! (j'en profite)) :

Code : Console
()()(())
bien parenthésé
((()(
mal parenthésé !
)(
mal parenthésé
fmldkf(fmldk(flk)()fdmkf)(f)d
bien parenthésé
...


Sur ce coup (enfin je le dis, mais c'est pas nouveau), il faudra bien réfléchir et trouver un algorithme sûr ne permettant aucune "faille" (commencez de préférence avec papier + crayon). Le code en C doit être travaillé avant d'être posté ici, et pour qu'on comprenne facilement, par la sémantique, ce que vous essayez de faire, pensez à donner des noms explicites (mais ça, vous le faites naturellement hein :-° ).

Si vous ne l'avez pas encore remarqué, je le rappelle : vous pouvez désormais poster vos codes ici, permettant ainsi un système d'entraide plus "communautaire". Si vous avez besoin d'un ou deux tuyaux, vous pouvez également demander ici.

Bonne chance !

shareman

Nouvel atelier : Codez votre propre petit préprocesseur pour langage C !
Citation : Woody Allen
Si l'au-delà existe, c'est à quelle distance du centre ville, et c'est ouvert jusqu'à quelle heure ?
 
Hors ligne dldk-g # Posté le 10/06/2009 à 19:07:45
Avatar

Ma solution (ne permet pas à l'utilisateur de choisir les caractères de ses parenthèses) :
Secret (cliquez pour afficher)
Code : C
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
/* Renvoie 1 si la chaîne est bien parenthésée
        0 sinon */
static int
bien_pth (const char *s)
{
  int nbPth = 0;

  while (*s != '\0')
    {
      if (*s == '(')
	nbPth++;
      else if (*s == ')')
	nbPth--;
      if (nbPth < 0)
	return 0;
      s++;
    }

  if (nbPth == 0)
    return 1;
  return 0;
}


Code entier pour les tests :
Secret (cliquez pour afficher)
Code : C
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
#include <stdio.h>
#include <stdlib.h>

/* Renvoie 1 si la chaîne est bien parenthésée
           0 sinon */
static int
bien_pth (const char *s)
{
  int nbPth = 0;

  while (*s != '\0')
    {
      if (*s == '(')
	nbPth++;
      else if (*s == ')')
	nbPth--;
      if (nbPth < 0)
	return 0;
      s++;
    }

  if (nbPth == 0)
    return 1;
  return 0;
}

static void 
usage (const char *name)
{
  printf ("%s : << chaine >>\n", name);
  exit (EXIT_FAILURE);
}

int
main (int argc, char *argv[])
{
  if (argc != 2)
   usage (argv[0]);

  if (bien_pth (argv[1]) == 1)
    printf ("Oui\n");
  else
    printf ("Non\n");
     
  return EXIT_SUCCESS;
}

Édité le 10/06/2009 à 19:16:04 par dldk-g
Hors ligne Jaloyan1 # Posté le 10/06/2009 à 19:19:38
Sms = portable,forum = clavier
Avatar

Citation : ShareMan
C'est avant tout un exercice qui demandera énormément de réflexion, en premier lieu au niveau algorithmique puis au niveau du codage même en C (mais c'est surmontable).


Euh beaucoup de réflexion, beaucoup de réflexion... C'est un peu exagéré je trouve, car pour dire beaucoup de réflexion, il faudrait passer des heures dessus, alors que au niveau algorithmique, je dis 5 minutes au max (j'ai trouvé en peu de temps, mais je pense pas que ce sera le cas de tout le monde).
Je vais me lancer dans le code, peut être pour ce soir, cependant, je considérerais que l'entrée est formatée, comme sur france-ioi.
EDIT : (surtout que l'algo naif(je pense pas qu'il y en ait 50 000) est en O(N).)

EDIT2 : voici le code avec les tests

Secret (cliquez pour afficher)
Code : C
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
#include <stdio.h>
#include <stdlib.h>

/**CONSTANTES DE L'ENNONCE**/
char expression[200];

void verifier(void)
{
   int differenceOuvranteFermante = 0;
   int i = 0;
   for(;expression[i] != '\0';i++)
	{
	   if(differenceOuvranteFermante < 0)
	   {
         printf("mal parenthese !\n");
         return;
	   }
	   if(expression[i] == '(')
	   {
	      differenceOuvranteFermante++;
	   }
	   else if(expression[i] == ')')
	   {
	      differenceOuvranteFermante--;
	   }
	}
	if(differenceOuvranteFermante == 0)
	{
	   printf("bien parenthese\n");
	   return;
	}
	printf("mal parenthese !\n");
}

int main(void)
{
   for(;;)
   {
      fgets(expression, 200, stdin);
      verifier();
   }
	return 0;
}



Et les fichiers tests

)(()( OK
)( OK
a OK
(()()())()(((()())())) OK
(()()())()(((()())()) OK
bonjour comment ça va () OK
me revoila (vraiment) OK
tu est sur (alors la)) OK
(((ex)emple)( ) )au(t())re) OK
(((ex)emple)( ) )au(t())re OK




EDIT3 : après avoir lu ton code, je viens de me rendre compte qu'il était basé sur exactement le même algorithme (sauf que j'affiche dans la fonction), bon ben cela me rassure ... Je vais me lancer dans une version permettant de choisir ses parenthèses.

EDIT4 : enfin fini, saletés de saisies non sécurisées ...

Secret (cliquez pour afficher)
Code : C
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
#include <stdio.h>
#include <stdlib.h>

/**CONSTANTES DE L'ENNONCE**/
char expression[200];
char caracOuvrant;
char caracFermant;

void verifier(void)
{
   int differenceOuvranteFermante = 0;
   int i = 0;
   for(;expression[i] != '\0';i++)
	{
	   if(differenceOuvranteFermante < 0)
	   {
         printf("mal parenthese !\n");
         return;
	   }
	   if(expression[i] == caracOuvrant)
	   {
	      differenceOuvranteFermante++;
	   }
	   else if(expression[i] == caracFermant)
	   {
	      differenceOuvranteFermante--;
	   }
	}
	if(differenceOuvranteFermante == 0)
	{
	   printf("bien parenthese\n");
	   return;
	}
	printf("mal parenthese !\n");
}

int main(void)
{
   for(;;)
   {
      scanf("%c %c ", &caracOuvrant, &caracFermant);
      fgets(expression, 200, stdin);
      if(caracOuvrant == caracFermant)
      {
         printf("le caractere d'ouverture et de fermeture sont les memes\n");
      }
      else
      {
         verifier();
      }
   }
	return 0;
}


J'ai pas fait de fichiers tests, mais j'ai juste testé avec un mélange de tout, et les cas précédents en changeant les caractères. rajout d'une petite sécurité.
Édité le 10/06/2009 à 19:59:18 par Jaloyan1

Si quelqu'un vous dit : "Je me tue à vous le répéter", laissez-le mourir.
:D int x = 0; x >?= (a < b)?((a < c)?((a < d)?a:d):((c < d)?c:d)):((b < c)?((b < d)?b:d):((c < d)?c:d));
Quelqu'un a compris ce que ce code fait? :-°
 
Hors ligne Eusebus # Posté le 10/06/2009 à 20:04:40
Geek mangeur de cookies
Avatar

Plusieurs critiques :

- Utilisations de variables globales alors qu'il n'y a pas lieu (quelle utilité ?), c'est très moche à mon avis.
- Une boucle infinie dans le main, ça aussi c'est vraiment très moche (et tu en sors comment ?)
- Des noms de variables à rallonge qui nuisent à la lisibilité.

"Ce qui est affirmé sans preuve peut être nié sans preuve" Euclide
"Tout ensemble inductif admet au moins un élément maximal." Lemme de Zorn
 
Hors ligne robocop # Posté le 10/06/2009 à 20:07:21
Avatar

Jaloyan1 :
Il ne faut pas juste compter les parenthèses !
Sinon, tu valides aussi ")(", ce qui n'est pas le but.
Edit : ha non, ok, autant pour moi, tu vérifies bien que la somme n'est jamais négative.
Édité le 10/06/2009 à 20:23:58 par robocop
 
Hors ligne Jaloyan1 # Posté le 10/06/2009 à 20:46:26
Sms = portable,forum = clavier
Avatar

Citation : Eusebus
Plusieurs critiques :

- Utilisations de variables globales alors qu'il n'y a pas lieu (quelle utilité ?), c'est très moche à mon avis.

Les données fournies dans l'énoncé/entrée sont ,chez ma norme, toujours en variable globale, car ils sont constants tout au long du programme (j'appelle programme la partie qui suit la saisie les entrées).
Et surtout, cela permet de coder plus vite sans se casser la tête avec les pointeurs.
(Sans compter que si on maitrise vraiment, on a pas de problèmes avec).
Après le question de la beauté, je pense que c'est une notion subjective et donc on ne peut pas en juger. Personnellement, je trouve que bien codé, cela n'est pas particulièrement moche, pas plus que des conditions ternaires ou des pointeurs de pointeurs.

Citation : Eusebus

- Une boucle infinie dans le main, ça aussi c'est vraiment très moche (et tu en sors comment ?)

ctrl+c sous linux ou la croix sur windows.
J'ai suivi selon l'exemple de l'énoncé, il y a en aucun cas la précision de commande spécifique pour quitter, ou alors une entrée précisant le nombre de tours de boucle.
Donc l'idée de la boucle inifinie peut être envisageable.

Citation : Eusebus

- Des noms de variables à rallonge qui nuisent à la lisibilité.


Euh, je préfère avoir des noms de variables longs (c'est vrai que là j'aurais pu raccourcir, mais j'avais pas d'imagination), mais au moins tu perds pas 2 heures à déboguer, vu que dès le codage, sans compiler tu te rends compte de tes erreurs. Ce qui permet de coder plus rapidement encore (surtout que les noms de variables veulent quand même dire quelque chose).
Et surtout vive l'auto complétion de C::B (et aussi que si Mathias me voit à nommer des variables s, j,dif et ans, je risque de me faire taper sur les doigts)

Si quelqu'un vous dit : "Je me tue à vous le répéter", laissez-le mourir.
:D int x = 0; x >?= (a < b)?((a < c)?((a < d)?a:d):((c < d)?c:d)):((b < c)?((b < d)?b:d):((c < d)?c:d));
Quelqu'un a compris ce que ce code fait? :-°
 
Hors ligne Crehn # Posté le 10/06/2009 à 21:52:34
Got it ?
Avatar

Bon voici ma version claire et propre:
Secret (cliquez pour afficher)
Code : C
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
#include <stdio.h>

int cb(char *s){int n=0;for(;*s;++s){if(*s==
'(')++n;if(*s==')')if(--n<0)break;}return n;}

int main(int argc, char **argv) {
    if(cb(argv[1])) {
        puts("Ok.");
    } else {
        puts("Damn.");
    }

    return 0;
}


EDIT:
Hop, et encore plus petit! Fonction de 90 caractères.
Édité le 10/06/2009 à 22:48:42 par Crehn
 
Hors ligne Eusebus # Posté le 10/06/2009 à 22:03:26
Geek mangeur de cookies
Avatar

Je maintiens que la boucle infinie est quand même à éviter très fortement si ça n'est pas dument justifié, ça ressemble surtout à du code torché à la va-vite parce que tu n'as pas daigné t'arrêter deux secondes sur quelques points, notamment une condition d'arrêt ou je ne sais quoi. D'ailleurs, on pouvait très bien s'en passer... Tu veux vraiment chipoter quand tu dis "c'est pas spécifié dans l'énoncé". C'est évident, quand même ; j'ai l'impression que tu fais de la mauvaise foi. Certaines choses coulent de source, et ça en fait partie (parce qu'avec ta façon de procéder, ton programme ne se termine pas normalement, même lorsqu'il a effectué correctement la tâche qui lui est confiée).

Je maintiens également que les globales sont à éviter aussi, leur utilisation peut parfois se justifier de manière agréable, mais là c'est clairement pas le cas. Encore de la faignantise ? Et quand je parle de "moche", je parle par rapports au usages du C, les "us et coutumes", ou encore les "bonnes pratiques" pour reprendre un terme de -ed-.

Pour info, sans variable globale et sans boucle infinie, ça m'a pris environ 5 minutes à coder lorsque Shareman a posté l'exo. Comme quoi ça ne prend pas tant de temps que ça de s'attarder à faire des trucs un peu plus clairs.

Secret (cliquez pour afficher)
Code : C
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
#include <stdio.h>

/* OK 0
 * KO 1 */

int check(const char *s);

int main(void)
{
        char str[BUFSIZ];

        fgets(str, sizeof str, stdin);
        str[BUFSIZ - 1] = '\0'; /* Sécurité pour la boucle for de check() */

        if(check(str) == 0)
                puts("Correct.");
        else
                puts("Incorrect.");

        return 0;
}

int check(const char *s)
{
        int cpt = 0, stop = 0;

        for(; *s && !stop; s++)
        {
                if(*s == '(')
                        cpt++;
                else if(*s == ')')
                        cpt--;
                if(cpt < 0)
                        stop = 1;
        }

        return cpt;
}


Edit : LOL Crehn. GG.
Édité le 10/06/2009 à 22:15:57 par Eusebus

"Ce qui est affirmé sans preuve peut être nié sans preuve" Euclide
"Tout ensemble inductif admet au moins un élément maximal." Lemme de Zorn
 
Hors ligne shareman # Posté le 10/06/2009 à 22:12:39
charlotte <3
Avatar

Ville : Mertzwiller
Pays : France métropolitaine

+1 Eusebus.

Et puis pour la "difficulté" dont je parle dans l'énoncé ... il faut se mettre à la place de celui qui débute vraiment en programmation. Je me rappelle il y a quelques années (quand j'ai commencé en programmation) que je n'arrivais pas à coder un algorithme qui trouve le maximum dans un tableau et maintenant j'ai du mal à croire à cette histoire (:-°). Alors si je me remets un peu dans l'ancienne situation, je vois parfaitement que ce genre d'exercices est en réalité un vrai casse-tête pour débutant. Si tu affirmes le contraire sans preuve, je vais le nier sans preuve (merci Eusebus ^^).

Nouvel atelier : Codez votre propre petit préprocesseur pour langage C !
Citation : Woody Allen
Si l'au-delà existe, c'est à quelle distance du centre ville, et c'est ouvert jusqu'à quelle heure ?
 
Hors ligne Jaloyan1 # Posté le 10/06/2009 à 22:42:34
Sms = portable,forum = clavier
Avatar

Citation : Eusebus
Certaines choses coulent de source, et ça en fait partie (parce qu'avec ta façon de procéder, ton programme ne se termine pas normalement, même lorsqu'il a effectué correctement la tâche qui lui est confiée).


Ouai bon, on va pas se taper pour cela, je vais rajouter une condition d'arrêt. (personnellement, c'est le débogueur qui vient de me faire comprendre l'intérêt de la condition d'arrêt).

Citation : Eusebus
Je maintiens également que les globales sont à éviter aussi, leur utilisation peut parfois se justifier de manière agréable, mais là c'est clairement pas le cas. Encore de la faignantise ? Et quand je parle de "moche", je parle par rapports au usages du C, les "us et coutumes", ou encore les "bonnes pratiques" pour reprendre un terme de -ed-.


Citation : mateo21
Alors, comme les programmeurs sont de grosses feignasses (comment ça je l'ai déjà dit ?!

(c'est pas moi qui l'ai dit) ...




Si quelqu'un vous dit : "Je me tue à vous le répéter", laissez-le mourir.
:D int x = 0; x >?= (a < b)?((a < c)?((a < d)?a:d):((c < d)?c:d)):((b < c)?((b < d)?b:d):((c < d)?c:d));
Quelqu'un a compris ce que ce code fait? :-°
 
Hors ligne BoudBoulMan # Posté le 11/06/2009 à 11:03:42
Saucisse transgénique
Avatar

Citation : Eusebus
Code : C
1
2
fgets(str, sizeof str, stdin);
str[BUFSIZ - 1] = '\0'; /* Sécurité pour la boucle for de check() */

Il est inutile d'ajouter soi-même le caractère nul à la fin de la chaîne, la fonction fgets le fait automatiquement.
(En plus, tu ne tiens pas compte du fait que la chaîne entrée ne va pas forcément remplir le tableau de BUFSIZ-1 caractères et que donc le caractère nul n'est pas forcément en fin de tableau)

Je ne vais pas proposer le code que j'ai réalisé parce qu'il est quasi identique à celui déjà proposé par Eusebus :-°
Édité le 11/06/2009 à 11:06:35 par BoudBoulMan

Archlinux
 
Hors ligne Eusebus # Posté le 11/06/2009 à 11:39:24
Geek mangeur de cookies
Avatar

Ah oui, j'aurais du mieux RTFM, merci. (sinon effectivement il n'est pas en fin mais c'est juste en sécurité)

"Ce qui est affirmé sans preuve peut être nié sans preuve" Euclide
"Tout ensemble inductif admet au moins un élément maximal." Lemme de Zorn
 
Hors ligne Monsieur_JaKy # Posté le 11/06/2009 à 12:22:34
JaKy & Rory FTW!
Avatar

Ville : Bourges
Pays : France métropolitaine

Voici mon code qui n'apporte pas grand chose d'original dans ceux déjà présentés :D
Secret (cliquez pour afficher)
Code : C
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
/* 11/07/09
By Monsieur_JaKy

But : vérifier si une expression est bien paranthésée

*/

#include <stdio.h>

static int check(const char* s)
{
    int occ = 0;
    while (*s != '\0')
    {
        if (*s == '(')
            occ++;
        else if (*s == ')')
            occ--;
        if (occ < 0)
            return 0;
        s++;
    }

    return occ == 0 ? 1 : 0;
}

int main()
{
    char s[50] = "";
    fgets(s, sizeof s, stdin);
    if (check(s) == 1)
        puts("Yes");
    else
        puts("No");

    return 0;
}
 
Hors ligne GurneyH # Posté le 11/06/2009 à 17:48:52
Avatar

Bonjour à tous.

Je propose une version récursive...
Les test sont effectués dans la fonction main, selon une méthode piquée à -ed-.
Secret (cliquez pour afficher)

Code : C
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
#include <stdio.h>

#define NELEM(a) (sizeof(a) / sizeof(*a))

static char zBrassRec(char const *src, char open, char close, int lvl)
{
    /* Si on est à la fin de la chaîne et que le niveau d'imbrication courant
      * est nul, la chaîne est correctement parenthèsée.
      */
    if (*src == '\0')
        return !lvl ? 0 : -1;

    if (*src == open)
        lvl = zBrassRec(src + 1, open, close, lvl + 1);
    else if (*src == close)
        lvl = zBrassRec(src + 1, open, close, lvl - 1);
    else
        lvl = zBrassRec(src + 1, open, close, lvl);

    return lvl;
}



/* char zBrass(char const *src, int lvl)
 * src    : Chaîne dont on veut vérifier le parenthèsage.
 * open   : Caractère representant la parenthèse ouvrante.
 * close  : Caractère représentant la parenthèse fermante.
 * Retour : 0 si la chaîne est ok, -1 sinon.
 */

char zBrass(char const *src, char open, char close)
{
    return zBrassRec(src, open, close, 0);
}



int main(void)
{
    struct test
    {
        /* Index du test courant */
        int id;
        /* Chaîne testée */
        char s[32];
        /* type de parenthèse */
        char open, close;
        /* Résultat attendu */
        int res;
    };

    static const struct test a[] =
    {
        {1, "(",		'(', ')', -1},
        {2, "()",		'(', ')',  0},
        {3, ")",	        '(', ')', -1},
        {4, "int main(void)",	'(', ')',  0},
        {5, "[a]a[aaa())))]",	'[', ']',  0},
        {6, "a}",	        '{', '}', -1},
        {7, "int main(void){}", '{', '}',  0},
    };
    size_t i;
    int terr = 0;
    for (i = 0; i < NELEM(a) && !terr; ++i)
    {
        struct test const *const p = a + i;
        int res = zBrass(p->s, p->open, p->close);

        if (res != p->res)
        {
            printf("ERR at test %d\n", p->id);
            terr = 1;
        }
    }
    if (!terr)
    {
        puts("\nP A S S E D\n");
    }

    return 0;
}

La fonction zBrass, sert à masquer l'initialisation du niveau d'imbrication lors de l'appel de zBrassRec qui fait tout le travail.

Code : C
1
char zBrass(char const *src, char open, char close)

exemple d'utilisation
Code : C
1
printf("%d", zBrass("((un test !...))", '(', ')'));


a++
edit1 : problème de mise en forme.
edit2 code en secret, désolé...
Édité le 11/06/2009 à 17:56:05 par GurneyH
 
Hors ligne Monsieur_JaKy # Posté le 11/06/2009 à 17:53:36
JaKy & Rory FTW!
Avatar

Ville : Bourges
Pays : France métropolitaine

Mets ta solution en secret !
 
Hors ligne Jaloyan1 # Posté le 11/06/2009 à 19:25:00
Sms = portable,forum = clavier
Avatar

Gurneh j'ai une question, c'est pas mieux au niveau de

Code : C
1
2
if (*src == '\0')
        return !lvl ? 0 : -1;

de faire plutôt
Code : C
1
2
if (*src == '\0')
        return !!lvl;


J'attends ta réponse comme cela je pourrais moi aussi m'instruire et en savoir plus sur ceci.
Cordialement.

Si quelqu'un vous dit : "Je me tue à vous le répéter", laissez-le mourir.
:D int x = 0; x >?= (a < b)?((a < c)?((a < d)?a:d):((c < d)?c:d)):((b < c)?((b < d)?b:d):((c < d)?c:d));
Quelqu'un a compris ce que ce code fait? :-°
 
Hors ligne GurneyH # Posté le 11/06/2009 à 19:49:54
Avatar

@Jaloyan1

Je n'emploie pas la combinaison d'opérateur !!, tu vas donc devoir attendre la réponse d'une personne plus compétente...
Tout ce que je peut te dire, c'est que j'ai choisi de renvoyer un valeur négative au cas où la chaîne est mal parenthésée... Avec !!, on ne renvoie dans tous les cas 0 ou 1...
Essaye, tu ne passes pas les tests...

a++
 
Hors ligne shareman # Posté le 11/06/2009 à 21:38:38
charlotte <3
Avatar

Ville : Mertzwiller
Pays : France métropolitaine

Bah au final, il suffit juste de choisir une valeur de retour pour chaque cas possible (deux ici). Gurney a choisi 0 et -1 mais avec 0 et 1, y'a pas de soucis non plus.

Jaloyan1, je ne vois pas vraiment en quoi ton alternative (qui, rigoureusement parlant, n'en est pas une puisqu'elle ne fait pas exactement la même chose) serait meilleure. Grossièrement, sauf quelconques optimisations du compilo, ta première version (celle provenant du code de Gurney) fait une "opération" (la condition) et ta seconde version en fait deux (opération "non" unaire appliquée deux fois). Mais au fond, je pense surtout que c'est profondément sans importance, surtout ici.

Nouvel atelier : Codez votre propre petit préprocesseur pour langage C !
Citation : Woody Allen
Si l'au-delà existe, c'est à quelle distance du centre ville, et c'est ouvert jusqu'à quelle heure ?
 
Hors ligne Jaloyan1 # Posté le 12/06/2009 à 08:00:34
Sms = portable,forum = clavier
Avatar

Citation : ShareMan
Jaloyan1, je ne vois pas vraiment en quoi ton alternative (qui, rigoureusement parlant, n'en est pas une puisqu'elle ne fait pas exactement la même chose) serait meilleure. Grossièrement, sauf quelconques optimisations du compilo, ta première version (celle provenant du code de Gurney) fait une "opération" (la condition) et ta seconde version en fait deux (opération "non" unaire appliquée deux fois). Mais au fond, je pense surtout que c'est profondément sans importance, surtout ici.


Ben justement, je me demande si c'est meilleur, c'est pour cela que je l'ai posté.

Merci en tout cas.

Si quelqu'un vous dit : "Je me tue à vous le répéter", laissez-le mourir.
:D int x = 0; x >?= (a < b)?((a < c)?((a < d)?a:d):((c < d)?c:d)):((b < c)?((b < d)?b:d):((c < d)?c:d));
Quelqu'un a compris ce que ce code fait? :-°
 
Hors ligne HighTam # Posté le 13/06/2009 à 00:43:34
Sleep(FOR_EVER);
Avatar

Ville : Sfax
Pays : Tunisie

Salut à tous :)
Je vois que la plupart des solutions se ressemblent. La mienne aussi :

Secret (cliquez pour afficher)
Code : C
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
int brace(const char *str, const char start, const char end)
{
    int n = 0;
    for ( ; *str ; str++)
    {
        if (*str == start)
            n++;
        else if (*str == end)
            n--;
        if (n < 0)
            return 0;
    }
    return n == 0 ? 1 : 0;
}


A+ et au prochain exercice ;)

Windows Vista User

Rule n°25 : Relation to the original topic decreases with every single post.
 
Hors ligne Kushou # Posté le 13/06/2009 à 16:30:55
#sdz powered
Avatar

études : EPITA

Bonjour,

Bon ben voilà une petite participation, mais je suis plutot mauvais en C (vous avez dit partout ?), donc mon code est surement moche. Pour pas faire une boucle comme tout le monde, et histoire qu'on ait de quoi discuter, j'ai décidé de faire ça en récurcif (tail-rec en plus %%). Donc le code est ici. On peut choisir les délimiteurs entre (), [] et {}, voilà. Le code est un peu plus long que celui des autres. Si j'avais réussi a faire fonctionner fflush, il auraut fait 42 lignes, c'est à souligner.

Image utilisateur
Guitariste à découvrir ! (Kiko Loureiro) - Comment faire du code illisible ?
"L'informatique c'est l'art de passer 10 jours à économiser 10 secondes."
EPITA 2014 :: Membre de Prologin
 

Retour au forum "Langage C" ou à la liste des forums

Pour accéder à cette section
Connectez-vous !
connexion_rpx