Copyright (C) IOI日本委員会 1994. All rights reserved.


問題6.

数式を記述する際、演算子(+,-,*,/ など:operator)をオペランド(演算の対象と なるもの:operand)の後ろに書く記法を逆ポーランド記法という。例えば、

        (1)  a+b              は  ab+
        (2)  a*b+c            は  ab*c+
        (3)  a+b*c            は  abc*+
        (4)  (a+b)/(c-d)      は  ab+cd-/
        (5)  a*(b-c)          は  abc-*
        (6)  (a+b)+c          は  ab+c+
        (7)  a+(b+c)          は  abc++
        (8)  a+b+c            は  ab+c+
と書く。
(8)の例が示すように、結合の強さが同じ演算子は「左から右」の順に結合することと定める。 この記法では括弧が全く不要である。

[(1)] 次の数式を逆ポーランド記法で書け。 [各1点]

      (i)  (a-b)*c
      (ii)  a*(b+c/d+e)/f-g

[(2)] 以下の3つの異なる言語で書かれたプログラムはどれも 普通の記法で書かれた数式を逆ポーランド記法の数式に変換するものである。 演算子としては四則演算(+,-,*,/)しか考えず、単項演算子としての+と-(すなわち、 -aとか+bのように使われる場合)も考えないことにする。また、 変数名としては、英小文字(a〜z)1文字だけのものを考えることにし、 定数は含まない。

選択した言語について、空欄を埋めよ。 空欄には2つの演算子の強さを比較する条件式(論理式)が入る。 ただし、演算子 x の強さは下記のどのプログラム中でも order(x) により定められている(値が大きいほど強い)。また、文字コードはASCIIとする。 [2点]


Cプログラム(6)


#include <stdio.h>
#include <ctype.h>
#include <string.h>
#define STKMAX 128
#define STRLEN 256
#define OPERAND  0
#define OPERATOR 1
#define LPAREN   2
#define RPAREN   3
#define OTHERS   4

int syurui(char);
int order(char);

main()
{  
    char stack[STKMAX],data[STRLEN];
    int  n, stkPtr = 0;

    printf("数式を入力しなさい。\n"); gets(data);
    printf("%s → ", data);
    for (n=0; n<strlen(data); n++) {
        switch (syurui(data[n])) {
            case OPERAND :
                putchar(data[n]); break;
            case OPERATOR :
                while (stkPtr>0 &&
                       syurui(stack[stkPtr-1])==OPERATOR &&
                        -------------------------------- 
                       |     空欄箇所                   | )
                        --------------------------------
                    putchar(stack[--stkPtr]);
                stack[stkPtr++] = data[n]; break;
            case LPAREN :
                stack[stkPtr++] = '('; break;
            case RPAREN :
                while (stack[stkPtr-1] != '(')
                    putchar(stack[--stkPtr]);
                --stkPtr; break;
            case OTHERS :
                printf("データエラー\n"); exit(1);
        }
    }
    do {
        putchar(stack[--stkPtr]);
    } while (stkPtr>0);
}

int syurui(char x) 
{  
    switch (x) {
        case '+' :
        case '-' :
        case '*' :
        case '/' : return OPERATOR;
        case '(' : return LPAREN;
        case ')' : return RPAREN;
        default  : return (isalpha(x) ? OPERAND : OTHERS);
    }
}

int order(char x)
{
    switch (x) {
        case '+' : case '-' : return 1;
        case '*' : case '/' : return 2;
    }
}


QuickBASICプログラム(6)


DEFINT A-z
DECLARE FUNCTION syurui(x)
DECLARE FUNCTION order(x)
DIM SHARED stack(128) AS INTEGER
DIM SHARED stkPtr AS INTEGER
CONST operand=0, operator=1, lparen=2, rparen=3, others=4

   stkPtr=0
   PRINT "数式を入力しなさい。"
   LINE INPUT data$
   PRINT USING "@ → "; data$;

   FOR n=1 TO LEN(data$)
      d$=MID$(data$,n,1)
      SELECT CASE syurui(ASC(d$))
         CASE operand
            PRINT d$;
         CASE operator
            DO           
               IF stkPtr<=0 THEN GOTO POS1
               IF syurui(stack(stkPtr))<>operator THEN GOTO POS1
                   -------------------------------
               IF |         空欄箇所              | THEN GOTO POS1
                   -------------------------------
               PRINT CHR$(stack(stkPtr));
               stkPtr=stkPtr-1
            LOOP
            POS1:
            stkPtr=stkPtr+1: stack(stkPtr)=ASC(d$)
         CASE lparen
            stkPtr=stkPtr+1: stack(stkPtr)=ASC("(")
         CASE rparen
            WHILE stack(stkPtr)<>ASC("(")
               PRINT CHR$(stack(stkPtr));
               stkPtr=stkPtr-1
            WEND
            stkPtr=stkPtr-1
         CASE others
            PRINT "データエラー": STOP
      END SELECT
   NEXT n

      PRINT CHR$(stack(stkPtr));
      stkPtr=stkPtr-1
   WEND
END


FUNCTION syurui(CodeOfX)
   x$=CHR$(CodeOfX)
   SELECT CASE x$
      CASE "+" : syurui=operator
      CASE "-" : syurui=operator
      CASE "*" : syurui=operator
      CASE "/" : syurui=operator
      CASE "(" : syurui=lparen
      CASE ")" : syurui=rparen
      CASE ELSE
         IF ("a"<=x$)AND(x$<="z") THEN syurui=operand ELSE syurui=others
   END SELECT
END FUNCTION


FUNCTION order(CodeOfX)
   x$=CHR$(CodeOfX)
   SELECT CASE x$
      CASE "+" : order=1
      CASE "-" : order=1
      CASE "*" : order=2
      CASE "/" : order=2
   END SELECT
END FUNCTION


Pascalプログラム(6)


PROGRAM test6;
CONST stkmax  = 128;
      strlen  = 255;
      operand = 0;
      operator= 1;
      lparen  = 2;
      rparen  = 3;
      others  = 4;
VAR stack : ARRAY[1..stkmax] OF char;
    n,stkPtr : integer;
    data : string[strlen];

FUNCTION syurui(x:char): integer;
BEGIN
    CASE x OF
        '+','-','*','/' : syurui:=operator;
        '('             : syurui:=lparen;
        ')'             : syurui:=rparen;
        ELSE 
            IF ('a'<=x) AND (x<='z') THEN syurui:=operand
                                     ELSE syurui:=others;
    END
END;

FUNCTION order(x:char): integer;
BEGIN
    CASE x OF
        '+','-' : order:=1;
        '*','/' : order:=2;
    END
END;

BEGIN
    stkPtr:=0;
    writeln('数式を入力しなさい。'); 
    readln(data);
    write(data, ' → ');
    FOR n:=1 TO length(data) DO
    BEGIN
        CASE syurui(data[n]) OF
            operand : 
                write(data[n]);
            operator : 
                BEGIN 
                    WHILE (stkPtr>0) AND 
                          (syurui(stack[stkPtr])=operator) AND
                             -----------------------------------
                          ( |           空欄箇所                | ) DO
                             -----------------------------------
                    BEGIN 
                        write(stack[stkPtr]); stkPtr:=stkPtr-1
                    END;
                    stkPtr:=stkPtr+1; stack[stkPtr]:=data[n]
                END;
            lparen : 
                BEGIN 
                    stkPtr:=stkPtr+1; stack[stkPtr]:='('
                END;
            rparen : 
                BEGIN 
                    WHILE stack[stkPtr]<>'(' DO
                    BEGIN 
                        write(stack[stkPtr]); stkPtr:=stkPtr-1
                    END;
                    stkPtr:=stkPtr-1
                END;
            others : 
                BEGIN 
                    writeln('データエラー'); 
                    exit 
                END;
        END
    END;
    WHILE stkPtr>0 DO
    BEGIN 
        write(stack[stkPtr]); stkPtr:=stkPtr-1 
    END
END.


JOI'94へ戻る

JOIホームページへ戻る