0

スタックを使用して、中置記法で指定された式を後置記法に変換する基本的なプログラムを作成しています。

これが私のプログラムです。

#include<stdio.h>
#include<stdlib.h>
#include<stdbool.h>
#include<string.h>
#define  MAX_STACK_SIZE 100

//STACK IMPLEMENTATION BEGINS
struct stack{
    int top;
    char items[MAX_STACK_SIZE];
};
void push(struct stack* s, char n){
    if(s->top==MAX_STACK_SIZE-1)
        printf("Stack Overflow. Cannot push\n");
    else
        s->items[++s->top]=n;
}
bool isempty(struct stack* s){
    if(size(s)==0)
        return 1;
    else return 0;

}


char pop(struct stack* s){
 if(isempty(s))
{printf("\nStack Underflow. Cannot Pop\n");
return 0;}
else
{return (s->items[s->top--]);
}
}

bool isfull(struct stack* s){
    if(size(s)==MAX_STACK_SIZE)
        return 1;
    else return 0;

}
void display(struct stack* s){
    int num;
    if(isempty(s))
        printf("Stack empty. Nothing to display\n");
    else
    {
        for(num=0;num<=s->top;num++)
            printf("%d ",s->items[num]);
    }

}
int size(struct stack* s){
    if(s->top==-1)
        return 0;
    else
return (s->top+1);


}
//STACK IMPLEMENTATION ENDS

//checks if a character entered is an operator or not
bool isOperator(char ch){
    if(ch=='-'||ch=='+'||ch=='*'||ch=='/')
        return true;
    else
        return false;
}
//checks if a character entered is an operand(0-9) or not
bool isOperand(char ch){
    if(ch>=48 && ch<=57)
        return true;
    else
        return false;


}
//decides the precedence of operators
int precedence(char ch){
    if(ch=='*'||ch=='/')
        return 2;
    if(ch=='+'||ch=='-')
        return 1;

}
void main(){
/*
    /*Declarations Begin*/
    char infix_exp[50],ch;
    int a;    
    struct stack s;
    s.top=-1;
    /*Declarations End*/

    printf("Enter your infix expression\n");
    scanf("%s",&infix_exp);
    for(a=0;a<strlen(infix_exp);a++)//scanning the entire array
    {
        if(isOperator(infix_exp[a])){
              while(s.top>=0 && isOperator(s.items[s.top]))
            {
                  if(s.items[s.top]=='('|| isempty(&s))
                  {
                      push(&s,infix_exp[a]);

                  }
                  if(isOperator(s.items[s.top])){
                      while((s.top--)>=0){
                      if(precedence(infix_exp[a])>=precedence(s.items[s.top]))
                      {
                          ch=pop(&s);
                           printf("%c",ch);

                         push(&s,infix_exp[a]);  
                      }
                      else
                      {
                           push(&s,infix_exp[a]);  
                      }}}}}
        if(isOperand(infix_exp[a])){printf("%c",infix_exp[a]);}
        if(infix_exp[a]=='('){push(&s,'(');}
        if(infix_exp[a]==')'){
             while(s.top>=0 && s.items[s.top]!='(')
            {
                ch=pop(&s);
                printf("%c",ch);

            }
            pop(&s);
        }}}

これが出力です。

Enter your infix expression
6+1
61
RUN FINISHED; exit value 3; real time: 4s; user: 0ms; system: 0ms

私が従うロジックはこれです。

ユーザーが式を入力すると、プログラムはすべての要素をスキャンします。要素がオペランドの場合、それが出力されます。要素が開き括弧の場合、スタックにプッシュされます。要素が閉じ括弧の場合、スタック内のすべての要素がポップアウトされ、対応する開き括弧が検出されるまで出力されます。要素が (関数によってチェックされたisOperator()) 演算子である場合、スタックの一番上の要素は 3 つのうちの 1 つになる可能性があります。

  1. 開始ブラケット - 要素は単にスタックにプッシュされます。
  2. Null、つまりスタックが空です - 要素は単純にスタックにプッシュされます。
  3. もう 1 つの演算子 - 次に、スタックがトラバースされprecedence()、中置式要素の precedence( ) がスタック トップ要素の優先順位以上である場合、スタック トップがポップされて出力され、中置式要素がプッシュされます。それ以外の場合は、中置式要素のみがプッシュされ、何もポップされません。

出力で演算子を取得できません。エラーは何ですか?私は些細なことかもしれません、おそらく値の印刷を伴うか、それは私の論理によるものかもしれません. どんな助けでも感謝します。

4

1 に答える 1

1

Shunting-yard アルゴリズムを使用しているように見えますが、間違っていることがいくつかあります。

まず第一に、アルゴリズムの要点が実行された後でも、スタックの残りの内容を出力し、括弧の不一致をチェックする必要があります。ウィキの記事が言うように:

  1. 読み取るトークンがなくなった場合
  2. スタックにオペレーター トークンがまだある場合:
    • スタックの一番上の演算子トークンが括弧である場合、括弧が一致していません。
    • オペレーターを出力キューにポップします。

これをコードに追加するのは簡単です。for ループの後に次のようなものを追加するだけです。

while(!isempty(&s))
{
    ch = pop(&s);
    if(ch == ')' || ch == '(') {
        printf("\nMismatched parens\n");
        break;
    }
    printf("%c",ch);
}

しかし、別の問題があるため、これですぐに問題が解決するわけではありません。

2番目の問題は、現在の入力トークンが演算子である場合です。これについて、次のように言います。

要素が演算子である場合 ( isOperator() 関数によってチェックされる)、スタックの一番上の要素は 3 つのうちの 1 つになる可能性があります。

  1. 開始ブラケット - 要素は単にスタックにプッシュされます。
  2. Null、つまりスタックが空です - 要素は単純にスタックにプッシュされます。
  3. 別の演算子 - 次に、スタックがトラバースされ、中置式要素の優先順位 (precedence()) がスタック トップ要素の優先順位以上である場合、スタック トップがポップされて出力され、中置式要素がプッシュされます。 . それ以外の場合は、中置式要素のみがプッシュされ、何もポップされません。

この説明は基本的に正しいですが、優先順位が逆になっていると思います。出力キューに最後に 1 回だけプッシュする必要があります (スタック内のすべての要素に対して 1 回ではなく)。

しかし、あなたのコードはそれに一致しません。

コメント注釈を含むコードの関連部分は次のとおりです

//if the input token is an operator
if(isOperator(infix_exp[a]))
{
    //while s isn't empty and has an operator on top
    while(s.top>=0 && isOperator(s.items[s.top]))
    {
        //if the top element is a '(' (NEVER HAPPENS because '(' isn't an operator)
        if(s.items[s.top]=='('|| isempty(&s))
        {
            push(&s,infix_exp[a]);
        }
        //If the top element is an operator (ALWAYS HAPPENS)
        if(isOperator(s.items[s.top]))
        {
            //discard the top element of the stack, loop while there are still elements left
            while((s.top--)>=0)
            {
                //if the top element of the stack (after the one that was discarded) has precedence
                //then pop it to the output queue and push the input token to the stack
                if(precedence(infix_exp[a])>=precedence(s.items[s.top]))
                {
                    ch=pop(&s);
                    printf("%c",ch);
                    push(&s,infix_exp[a]);  
                }
                //otherwise push the input token to the stack
                else {                
                    push(&s,infix_exp[a]);  
                }
            }
        }
    }
}

if ステートメントの 1 つがトリガーされないことに注意してください。スタックを反復処理する 2 つの while ループがあり、そのうちの 1 つは実際には反復処理を行いません。2 番目の while ループの 2 つの異なる場所でスタックを縮小します。また、入力トークンをプッシュして複数回出力することもできます。

全体として、それはただの大きな混乱です。

次に、アルゴリズムが何をするかを見てみましょう (これもウィキペディアによると) (おかしな書式設定で申し訳ありません)。

  1. トークンが演算子 o1 の場合:

  2. スタックの一番上にオペレーター トークン o2 があり、

    o1 が左結合であり、その優先順位が o2 の優先順位と等しい

    または o1 の優先順位が o2 の優先順位よりも低い。

    • o2 をスタックから出力キューにポップします。
  3. o1 をスタックにプッシュします。

これは上記のコードと実際には一致しませんが、どうでしょうか?

まあ最初の部分は正しい

//if the input token is an operator
if(isOperator(infix_exp[a]))
{

次に、ループ チェックを使用して、適切な優先順位を持つ演算子がスタックの一番上にあるかどうかを確認する必要があります。

    //Traverse stack while the precedence is right
    while(!isempty(&s) && isOperator(s.items[s.top])
          && (precedence(infix_exp[a]) <= precedence(s.items[s.top])) )
    {

そして、ループ内からポップします:

        ch = pop(&s);
        printf("%c",ch);
    }

最後に、入力トークンをスタックにプッシュします。

    push(&s, infix_exp[a]);
}
于 2013-09-01T20:30:07.210 に答える