Langage C et expression arithmétique
XRev
-
Vicking54 Messages postés 89 Date d'inscription Statut Membre Dernière intervention -
Vicking54 Messages postés 89 Date d'inscription Statut Membre Dernière intervention -
Bonjour,
Je suis à la conquête d'un projet en langage C dans lequel je dois transformer une expression arithmétique exprimée en notation infixée, en une notation préfixée.
Ainsi (a+b)*(c+d) se transforme en *+ab+cd
Pour cela il faut utiliser les arbres binaires.
J'ai bien passé deux heures là dessus, désormais j'ai compris le sujet, cependant je bloque sur la conception. Je manque de notion en C (je débute).
Exemple de ce que j'imagine
----
Si j'entre dans mon terminal :
combien de valeur dans l'expression = 3 /* il va donc me demander trois valeur a,b,c) */
valeur de a = 2
valeur de b = 6
valeur de c = 2
que souhaitez vous faire : (a+b)*c /* ca pourrait être bien d'autres forme... */
Ainsi (a+b)*c se transforme en * c + a b ...
Soit (2+6)*2 se transforme en * 2 + 2 6
----
Enfin je suis pas sûr de ma démarche vis à vis du sujet, et d'autre part je ne sais pas comment m'y prendre... u_u
Merci de votre lecture, j'attends avec impatience vos réponses !
Cordialement,
M. XR
Je suis à la conquête d'un projet en langage C dans lequel je dois transformer une expression arithmétique exprimée en notation infixée, en une notation préfixée.
Ainsi (a+b)*(c+d) se transforme en *+ab+cd
Pour cela il faut utiliser les arbres binaires.
J'ai bien passé deux heures là dessus, désormais j'ai compris le sujet, cependant je bloque sur la conception. Je manque de notion en C (je débute).
Exemple de ce que j'imagine
----
Si j'entre dans mon terminal :
combien de valeur dans l'expression = 3 /* il va donc me demander trois valeur a,b,c) */
valeur de a = 2
valeur de b = 6
valeur de c = 2
que souhaitez vous faire : (a+b)*c /* ca pourrait être bien d'autres forme... */
Ainsi (a+b)*c se transforme en * c + a b ...
Soit (2+6)*2 se transforme en * 2 + 2 6
----
Enfin je suis pas sûr de ma démarche vis à vis du sujet, et d'autre part je ne sais pas comment m'y prendre... u_u
Merci de votre lecture, j'attends avec impatience vos réponses !
Cordialement,
M. XR
A voir également:
- Langage C et expression arithmétique
- Langage ascii - Guide
- Langage binaire - Guide
- Moyenne arithmétique excel - Guide
- Expression écrite cm1 cm2 télécharger gratuit - Télécharger - Éducatifs
- Microsoft expression encoder - Télécharger - Divers Utilitaires
5 réponses
Merci à KX et ydurce pour l'initiation, voir même le developpement de l'idée. Je ne m'était pas rendu compte de la complexité de la tâche. Oui il s'agit bien entendu de le réaliser en C.
Je posterais d'autre commentaire si j'en ai l'occasion sur ce que vous m'avez dit. Mais avant tout je tenais à vous remercier pour la rapidité de vos réponses. (je suis en cours)
Donc je m'y attarderais en soirée !
Bonne journée à vous !
Je posterais d'autre commentaire si j'en ai l'occasion sur ce que vous m'avez dit. Mais avant tout je tenais à vous remercier pour la rapidité de vos réponses. (je suis en cours)
Donc je m'y attarderais en soirée !
Bonne journée à vous !
Salut !
Comme ça je dirai qu'un arbre binaire permet facilement de résoudre le problème :
Les opérateurs seront sur les noeuds
Les opérandes seront sur les feuilles.
Les expressions entre parenthèses donneront des sous arbres (remarque : les parenthèses sont inutiles en notation préfixée)
Ici tu sembles te limiter au cas simple où tous tes opérateurs sont binaires, mais si tu voulais avoir des opérateurs unaires tu aurais ta feuille de droite vide, et pour des opérateurs n-aires bonne chance ;-)
Une fois l'arbre construit, il suffit de le lire en ordre préfixe (opérateur, opérande ou sous-arbre de gauche, puis opérande ou sous-arbre de droit) et le tour est joué.
Il te faudra bien sûr avoir une méthode d'analyse de ta formule pour identifier où sont les opérateurs, les opérandes, et les parenthèses (attention à bien distinguer les parenthèses ouvrantes et fermantes).
Le plus simple est surement de te limiter à des opérateurs atomiques comme + - * / ( ) et de les analyser dans un tableau de caractères avec la propriété suivante : si un caractère n'est pas un opérateur alors il constitue une opérande.
Le parenthésage va te poser beaucoup de problèmes de même que la priorité des opérateurs (exemple a*b+c donne + * a b c et non * a + b c)
J'espère que tu connais la récursivité car tu ne t'en sortiras pas sans !
Je pense que tu as compris maintenant qu'il te faudra plus de 2 heures pour terminer, alors persévère, et bonne continuation !
La confiance n'exclut pas le contrôle
Comme ça je dirai qu'un arbre binaire permet facilement de résoudre le problème :
Les opérateurs seront sur les noeuds
Les opérandes seront sur les feuilles.
Les expressions entre parenthèses donneront des sous arbres (remarque : les parenthèses sont inutiles en notation préfixée)
Ici tu sembles te limiter au cas simple où tous tes opérateurs sont binaires, mais si tu voulais avoir des opérateurs unaires tu aurais ta feuille de droite vide, et pour des opérateurs n-aires bonne chance ;-)
Une fois l'arbre construit, il suffit de le lire en ordre préfixe (opérateur, opérande ou sous-arbre de gauche, puis opérande ou sous-arbre de droit) et le tour est joué.
Il te faudra bien sûr avoir une méthode d'analyse de ta formule pour identifier où sont les opérateurs, les opérandes, et les parenthèses (attention à bien distinguer les parenthèses ouvrantes et fermantes).
Le plus simple est surement de te limiter à des opérateurs atomiques comme + - * / ( ) et de les analyser dans un tableau de caractères avec la propriété suivante : si un caractère n'est pas un opérateur alors il constitue une opérande.
Le parenthésage va te poser beaucoup de problèmes de même que la priorité des opérateurs (exemple a*b+c donne + * a b c et non * a + b c)
J'espère que tu connais la récursivité car tu ne t'en sortiras pas sans !
Je pense que tu as compris maintenant qu'il te faudra plus de 2 heures pour terminer, alors persévère, et bonne continuation !
La confiance n'exclut pas le contrôle
une solution (simplifiée) à améliorer bien sur!
#include <stdio.h>
#include <stdlib.h>
#include <malloc.h>
typedef struct
{
int chiffre_gauche;
int chiffre_droite;
void *Gauche;
void *Droite;
char Op[2];
int A_gauche;
} type_expression;
void PrintArbre(type_expression *Ptr);
type_expression *Sweep(int *Ind, char Chaine[]);
int _tmain(int argc, _TCHAR* argv[])
{
char Chaine[128];
type_expression *Arbre;
printf("entrer l'expression\n");
scanf("%s",Chaine);
int Ind=0;
Arbre=Sweep(&Ind,Chaine);
PrintArbre(Arbre);
scanf("%s",Chaine);
return 0;
}
void PrintArbre(type_expression *Ptr)
{
printf(Ptr->Op);
if(Ptr->Gauche!=NULL) PrintArbre((type_expression *)Ptr->Gauche);
else printf("%d",Ptr->chiffre_gauche);
if(Ptr->Droite!=NULL) PrintArbre((type_expression *)Ptr->Droite);
else printf("%d",Ptr->chiffre_droite);
}
type_expression *Sweep(int *Ind, char Chaine[])
{
type_expression *New;
New=new type_expression; //malloc(sizeof(type_expression)); en C
New->Gauche=New->Droite=NULL;
New->chiffre_gauche=New->chiffre_droite=0;
New->A_gauche=0;
while(1)
{
switch(Chaine[(*Ind)++])
{
case '(':
if(New->Gauche==NULL && New->A_gauche==0) New->Gauche=Sweep(Ind,Chaine);
else New->Droite=Sweep(Ind,Chaine);
break;
case ')':
case '\n':
case '\0':
return New;
break;
case '+':
case '-':
case '*':
case '/':
New->Op[0]=Chaine[*Ind-1];New->Op[1]='\0';
break;
default:
if(Chaine[*Ind-1]>=0x30 && Chaine[*Ind-1]<=0x39)
{
if(New->Gauche==NULL && New->A_gauche==0) {New->chiffre_gauche=Chaine[*Ind-1]-0x30;New->A_gauche=-1;}
else {New->chiffre_droite=Chaine[*Ind-1]-0x30;}
}
break;
}
}
}
#include <stdio.h>
#include <stdlib.h>
#include <malloc.h>
typedef struct
{
int chiffre_gauche;
int chiffre_droite;
void *Gauche;
void *Droite;
char Op[2];
int A_gauche;
} type_expression;
void PrintArbre(type_expression *Ptr);
type_expression *Sweep(int *Ind, char Chaine[]);
int _tmain(int argc, _TCHAR* argv[])
{
char Chaine[128];
type_expression *Arbre;
printf("entrer l'expression\n");
scanf("%s",Chaine);
int Ind=0;
Arbre=Sweep(&Ind,Chaine);
PrintArbre(Arbre);
scanf("%s",Chaine);
return 0;
}
void PrintArbre(type_expression *Ptr)
{
printf(Ptr->Op);
if(Ptr->Gauche!=NULL) PrintArbre((type_expression *)Ptr->Gauche);
else printf("%d",Ptr->chiffre_gauche);
if(Ptr->Droite!=NULL) PrintArbre((type_expression *)Ptr->Droite);
else printf("%d",Ptr->chiffre_droite);
}
type_expression *Sweep(int *Ind, char Chaine[])
{
type_expression *New;
New=new type_expression; //malloc(sizeof(type_expression)); en C
New->Gauche=New->Droite=NULL;
New->chiffre_gauche=New->chiffre_droite=0;
New->A_gauche=0;
while(1)
{
switch(Chaine[(*Ind)++])
{
case '(':
if(New->Gauche==NULL && New->A_gauche==0) New->Gauche=Sweep(Ind,Chaine);
else New->Droite=Sweep(Ind,Chaine);
break;
case ')':
case '\n':
case '\0':
return New;
break;
case '+':
case '-':
case '*':
case '/':
New->Op[0]=Chaine[*Ind-1];New->Op[1]='\0';
break;
default:
if(Chaine[*Ind-1]>=0x30 && Chaine[*Ind-1]<=0x39)
{
if(New->Gauche==NULL && New->A_gauche==0) {New->chiffre_gauche=Chaine[*Ind-1]-0x30;New->A_gauche=-1;}
else {New->chiffre_droite=Chaine[*Ind-1]-0x30;}
}
break;
}
}
}
Je n'ai pas regardé ton code en détail ydurce, mais je l'ai testé.
Comme tu l'as dit c'est une solution simplifiée, voici donc pour XRev les points à améliorer :
1) Utiliser des opérandes de plusieurs caractères. Exemple : "12+5"
2) Utiliser plusieurs opérateurs dans la même parenthèse. Exemple : "(1+2+3)+4"
3) Gérer les cas particuliers de parenthésage. Exemple : "(1+2)"
4) Ne pas se limiter aux améliorations 1 à 3 !
Sinon concernant ton code ydurce, il m'apparaît évident que l'utilisation d'un langage objet (C++ par exemple) est plus appropriée, même si la question de XRev portait effectivement sur le langage C.
PS. Pour mettre du code dans un poste utilisez les balises code faites pour ça.
Comme tu l'as dit c'est une solution simplifiée, voici donc pour XRev les points à améliorer :
1) Utiliser des opérandes de plusieurs caractères. Exemple : "12+5"
2) Utiliser plusieurs opérateurs dans la même parenthèse. Exemple : "(1+2+3)+4"
3) Gérer les cas particuliers de parenthésage. Exemple : "(1+2)"
4) Ne pas se limiter aux améliorations 1 à 3 !
Sinon concernant ton code ydurce, il m'apparaît évident que l'utilisation d'un langage objet (C++ par exemple) est plus appropriée, même si la question de XRev portait effectivement sur le langage C.
PS. Pour mettre du code dans un poste utilisez les balises code faites pour ça.
tout à fait d'accord avec toi pour le C++, KX.
laissons quand même un peu de travail à notre ami XRev qui, pour améliorer le code, devra l'analyser un peu !
laissons quand même un peu de travail à notre ami XRev qui, pour améliorer le code, devra l'analyser un peu !
Vous n’avez pas trouvé la réponse que vous recherchez ?
Posez votre question
je te donne la structure de donné d'un arbre syntaxique avec les primitives d'accès
Le .h :
Le .cpp
Avec cela ca te permettra d'avancer
cordialement
Le .h :
#ifndef _PRIMITIVEARBRESYNT_ #define _PRIMITIVEARBRESYNT_ typedef enum {Constante , Variable , Binaire , Fonction} TNature; typedef struct NoeudSynt { TNature Nature ; double ValConst; char OpOuFonct; struct NoeudSynt *fg; struct NoeudSynt *fd; } TNoeudSynt , *TArbreSynt; // Primitive sur les Arbres Syntaxique // Création extern TArbreSynt CreerArbreSyntVide (); extern TArbreSynt CreerVariable (); extern TArbreSynt CreerConstante (double Val); extern TArbreSynt CreerOperateurBinaire (char OpFonct, TArbreSynt fg , TArbreSynt fd); extern TArbreSynt CreerFonction (char OpFonct, TArbreSynt fg); // Consultation extern bool EstArbreSyntVide (TArbreSynt a); extern TArbreSynt FG(TArbreSynt a); extern TArbreSynt FD(TArbreSynt a); extern TNature Nature (TArbreSynt a); extern double ValConst (TArbreSynt a); extern char OpOuFonct (TArbreSynt a); // Modification extern void ModifFD(TArbreSynt a, TArbreSynt fd); extern void ModifFG(TArbreSynt a, TArbreSynt fg); extern void ModifNature(TArbreSynt a, TNature Nature); extern void ModifValConst(TArbreSynt a, double Val); extern void ModifOpOuFonct(TArbreSynt a, char OpFonct); // Destruction extern void Libérer(TArbreSynt a); #endif
Le .cpp
// Primitive sur les Arbres Syntaxique // Création TArbreSynt CreerArbreSyntVide () { return NULL; } TArbreSynt CreerVariable () { TArbreSynt NvM = (TArbreSynt) malloc (sizeof (TNoeudSynt)); NvM->Nature = Variable; return NvM; } TArbreSynt CreerConstante (double Val) { TArbreSynt NvM = (TArbreSynt) malloc (sizeof (TNoeudSynt)); NvM->Nature = Constante; NvM->ValConst = Val; return NvM; } TArbreSynt CreerOperateurBinaire (char OpFonct, TArbreSynt fg , TArbreSynt fd) { TArbreSynt NvM = (TArbreSynt) malloc (sizeof (TNoeudSynt)); NvM->Nature = Operateur_Binaire; NvM->OpOuFonct = OpFonct; NvM->fg = fg; NvM->fd = fd; return NvM; } TArbreSynt CreerFonction (char OpFonct, TArbreSynt fg) { TArbreSynt NvM = (TArbreSynt) malloc (sizeof (TNoeudSynt)); NvM->Nature = Fonction; NvM->OpOuFonct = OpFonct; NvM->fg = fg; return NvM; } // Consultation bool EstArbreSyntVide (TArbreSynt a) { if(a == NULL) { return true; } else { return false; } } TArbreSynt FG(TArbreSynt a) { return a->fg; } TArbreSynt FD(TArbreSynt a) { return a->fd; } TNature Nature (TArbreSynt a) { return a->Nature; } double ValConst (TArbreSynt a) { return a->ValConst; } char OpOuFonct (TArbreSynt a) { return a->OpOuFonct; } // Modification void ModifFD(TArbreSynt a, TArbreSynt fd) { a->fd = fd } void ModifFG(TArbreSynt a, TArbreSynt fg) { a->fg = fg; } void ModifNature(TArbreSynt a, TNature Nature) { a->Nature = Nature; } void ModifValConst(TArbreSynt a, double Val) { a->ValConst = Val; } void ModifOpOuFonct(TArbreSynt a, char OpFonct) { a->OpOuFonct = OpFonct; } // Destruction void Libérer(TArbreSynt a) { if (!EstVide(a)) { Libérer(FG(a)) Libérer(FD(a)) free(a) } }
Avec cela ca te permettra d'avancer
cordialement
Je vais regarder plus attentivement ta contribution Viking54 mais il me semble à première vue qu'il y ait plusieurs erreurs, en particulier si on considère que le problème est en C !
De plus je pense que la solution, certes incomplète, de ydurce était une base largement suffisante pour résoudre ce problème, même si j'aurai fait encore plus simple !
Personnellement ma structure d'arbre serait tout simplement :
De plus je pense que la solution, certes incomplète, de ydurce était une base largement suffisante pour résoudre ce problème, même si j'aurai fait encore plus simple !
Personnellement ma structure d'arbre serait tout simplement :
typedef struct { char *expression; // opérateur si un noeud - opérande si une feuille void *gauche; // sous-arbre gauche void *droite; // sous-arbre droit } arbreSyntaxique;
Je pense que quelques commentaires seraient mieux pour expliquer ce que tu as fait, pour mieux juger si nécessaire la qualité de ton code. J'ai juste corrigé ton code pour qu'il compile :
#ifndef _PRIMITIVEARBRESYNT_ #define _PRIMITIVEARBRESYNT_ #include <stdlib.h> typedef enum { Constante, Variable, Binaire, Fonction } TNature; typedef struct NoeudSynt { TNature Nature; double ValConst; char OpOuFonct; struct NoeudSynt *fg; struct NoeudSynt *fd; } TNoeudSynt, *TArbreSynt; // Primitives sur les Arbres Syntaxiques // Création TArbreSynt CreerArbreSyntVide() { return NULL; } TArbreSynt CreerVariable() { TArbreSynt NvM = (TArbreSynt) malloc(sizeof (TNoeudSynt)); NvM->Nature = Variable; return NvM; } TArbreSynt CreerConstante(double Val) { TArbreSynt NvM = (TArbreSynt) malloc(sizeof (TNoeudSynt)); NvM->Nature = Constante; NvM->ValConst = Val; return NvM; } TArbreSynt CreerOperateurBinaire(char OpFonct, TArbreSynt fg, TArbreSynt fd) { TArbreSynt NvM = (TArbreSynt) malloc(sizeof (TNoeudSynt)); NvM->Nature = Binaire; NvM->OpOuFonct = OpFonct; NvM->fg = fg; NvM->fd = fd; return NvM; } TArbreSynt CreerFonction(char OpFonct, TArbreSynt fg) { TArbreSynt NvM = (TArbreSynt) malloc(sizeof (TNoeudSynt)); NvM->Nature = Fonction; NvM->OpOuFonct = OpFonct; NvM->fg = fg; return NvM; } // Consultation int EstArbreSyntVide(TArbreSynt a) { return (a == NULL); } TArbreSynt FG(TArbreSynt a) { return a->fg; } TArbreSynt FD(TArbreSynt a) { return a->fd; } TNature Nature(TArbreSynt a) { return a->Nature; } double ValConst(TArbreSynt a) { return a->ValConst; } char OpOuFonct(TArbreSynt a) { return a->OpOuFonct; } // Modification void ModifFD(TArbreSynt a, TArbreSynt fd) { a->fd = fd; } void ModifFG(TArbreSynt a, TArbreSynt fg) { a->fg = fg; } void ModifNature(TArbreSynt a, TNature Nature) { a->Nature = Nature; } void ModifValConst(TArbreSynt a, double Val) { a->ValConst = Val; } void ModifOpOuFonct(TArbreSynt a, char OpFonct) { a->OpOuFonct = OpFonct; } // Destruction void Liberer(TArbreSynt a) { if (!EstArbreSyntVide(a)) { Liberer(FG(a)); Liberer(FD(a)); free(a); } } #endif
Elle ne pouvait pas fonctionner en C, regarde Libérer, déjà un nom de fonction avec un accent c'est incorrect et puis il manquait des ";"
De plus en C, les fichiers .cpp ne sont pas reconnus, de même que bool, true, ou false !
Et puis les extern, je n'ai pas trop compris à quoi ils servaient... Je trouve ça plus clair de tout mettre au même endroit !
De plus en C, les fichiers .cpp ne sont pas reconnus, de même que bool, true, ou false !
Et puis les extern, je n'ai pas trop compris à quoi ils servaient... Je trouve ça plus clair de tout mettre au même endroit !