C言語関係掲示板

過去ログ

No842 括弧の組合せを判断する

[戻る] [ホームページ]
No.10753

この課題がわからないのですが・・・
投稿者---ゆか(2003/11/24 02:43:47)


括弧や文字の列を読み込んで、読み込んだ括弧が ()や[]や{}というようにすべて ()や[]や{}なら1を返えす。というプログラムなのです。

例: [[{}]](a)[a]という括弧の列なら1を返す。(aなどの文字を中にいれても括弧が全てかみ合うのでOK!)

例: [[(() など括弧の組み合わせがかみ合わないのなら0を返す。

しかし、私が作ったのだとaとか文字を読み括弧の列はかみ合う場合でも0を返してしまいます。  長々とすいません。


#include<stdio.h>
#define  SIZE 100

   char S[SIZE];
   int sp=-1;

void push(char ch){
  sp++; S[sp]=ch;
 }

void pop(void){
  sp--;
 }

char top(void){
  return S[sp];
}

int empty(void){
  if(sp==-1){
    return 1;
  }
  else{
    return 0;
  }
}

int check(char P[]){
  char ch;
  int  i=0;

  while(P[i]!='\0'){
    if(P[i]=='('||P[i]=='['||P[i]=='{'){
      push(P[i]);
    }
    else{
      ch=top();
      if((ch=='('&&P[i]==')')||(ch=='['&&P[i]==']')||(ch=='{'&&P[i]=='}')){
	pop();
      }
      else{
        return 0;
      }
    }
      i++;
    }

    if(empty()){
      return 1;
    }
    else{
      return 0;
    }
  }

int main(void){
  char P[SIZE];
  int  rval;

  printf("文字列を入力してください。\n");
  scanf("%s",P);
  rval=check(P);

  if(rval==1){
    printf("括弧の列はかみ合います。 \n",P);
  }
  else{
    printf("括弧の列はかみ合いません。 \n",P);
  }

  return 0;
}


No.10755

Re:この課題がわからないのですが・・・
投稿者---おでん(2003/11/24 03:15:58)


恐ろしく簡単なのですが、一応機能は果たすと思います。
本当は、[aa(bb]cc) 等の場合も考えなくてはならないと思いますが?

#include <stdio.h>

int main(void)
{
    static char str[]= "[[aaa]{bbb]] (111{123aaa) " ;

    char *ptr= str ;
    int p1,p2,p3 ;
    p1= 0 ;
    p2= 0 ;
    p3= 0 ;
    
    while( *ptr != '\0' ){
        switch(*ptr){
            case '[':
                p1++ ;
                break ;
            case ']':
                p1-- ;
                break ;
            case '{':
                p2++ ;
                break ;
            case '}':
                p2-- ;
                break ;
            case '(':
                p3++ ;
                break ;
            case ')':
                p3-- ;
                break ;
        }
        ptr++ ;
    }
    if(( p1 + p2 + p3 ) != 0 ){
        puts( "カッコがおかしい\n" ) ;
    }
    return 0 ;
}


No.10759

Re:この課題がわからないのですが・・・
投稿者---かずま(2003/11/24 05:09:09)


> 恐ろしく簡単なのですが、一応機能は果たすと思います。
> 本当は、[aa(bb]cc) 等の場合も考えなくてはならないと思いますが?

[aa) の場合、「カッコがおかしい」と出ませんが、機能を果たすと言えるのでしょうか?

さて、こんなのを書いてみましたが、参考になりますかどうか。

#include <stdio.h>
#include <string.h>

const char *bp;

int check(char e)
{
    char c, *p;  static char l[] = "([{", r[] = ")]}";

    while ((c = *bp) != '\0') {
        bp++;
        if (strchr(r, c)) return c == e;
        if ((p = strchr(l, c)) != NULL && !check(r[p-l])) return 0;
    }
    return e == 0;
}

int main(void)
{
    char P[100];  int rval;

    printf("文字列を入力してください。\n");
    scanf("%99s", P);
    bp = P;
    rval = check(0);
    if (rval == 1)
        printf("括弧の列はかみ合います。 \n", P);
    else
        printf("括弧の列はかみ合いません。 \n", P);
    return 0;
}


No.10762

Re:この課題がわからないのですが・・・
投稿者---おでん(2003/11/24 11:35:19)


>[aa) の場合、「カッコがおかしい」と出ませんが、機能を果たすと言えるのでしょうか?

おお! そうでした (^.^?
→個別に判断が必要ですね。間違った投稿をしました、お許しください m(_"_)m

No.10763

Re:この課題がわからないのですが・・・
投稿者---かずま(2003/11/24 13:32:43)


> →個別に判断が必要ですね。間違った投稿をしました、お許しください m(_"_)m
 
「個別に判断」と言うのは、 if(( p1 + p2 + p3 ) != 0 ){  を
if (p1 != 0 || p2 != 0 || p3 != 0) {  にするということでしょうか。

でも、それなら、)ab(  が正しいことになってしまいませんか?

結局、この問題を解決するには、( と [ と { がどういう順番で出てきたかという
履歴を配列やスタックに記録しておく必要があると思います。


No.10777

Re:この課題がわからないのですが・・・
投稿者---おでん(2003/11/25 00:19:59)


>> →個別に判断が必要ですね。間違った投稿をしました、お許しください m(_"_)m

>「個別に判断」と言うのは、 if(( p1 + p2 + p3 ) != 0 ){ を
>if (p1 != 0 || p2 != 0 || p3 != 0) { にするということでしょうか。

「本当は、[aa(bb]cc) 等の場合も考えなくてはならないと思いますが?」の事です。
・・・早とちりもしてしまいましたが・・・

#include <stdio.h>

char GetR( char ch )
{
    const char nBrackets[]= "(){}[]" ;
    const char rBrackets[]= ")(}{][" ;
    int i ;
    for( i= 0 ; nBrackets[i] != '\0' ; i++ ){
        if( nBrackets[i] == ch ){
            return rBrackets[i] ;
        }
    }
    return '\0' ;
}

int main(void)
{
    static char str[]= "[[aaa]{bbb}] (111{123(aaa)})(" ;

    char *ptr= str ;
    char buf[100] ;
    int  inx= 0 ;
    char ch ;

    while( *ptr != '\0' ){
        ch= * ptr++ ;
        if( ch == '[' || ch == '{' || ch == '(' ){
            buf[inx++]= ch ;
        }else if( ch == ']' || ch == '}' || ch == ')' ){
            if( inx <= 0 || buf[--inx] != GetR(ch)){
                puts( "1.カッコの順序が違います\n" ) ;
                inx= 0 ;
                break ;
            }
        }
    }
    if( inx != 0 ){
        puts( "2.カッコの数が違います\n" ) ;
    }
    return 0 ;
}

・・・と、言う事ですね?・・・まだ問題がありそうだけど。

No.10756

Re:この課題がわからないのですが・・・
投稿者---YuO(2003/11/24 03:35:35)


しかし、私が作ったのだとaとか文字を読み括弧の列はかみ合う場合でも0を返してしまいます。
    if(P[i]=='('||P[i]=='['||P[i]=='{'){
      push(P[i]);
    }
    else{
      ch=top();
      if((ch=='('&&P[i]==')')||(ch=='['&&P[i]==']')||(ch=='{'&&P[i]=='}')){
	pop();
      }
      else{
        return 0;
      }
    }

ここが問題です。

外側のif文は「P[i]が開き括弧か否か」を判定しています。
当然,else節は「P[i]が開き括弧ではない場合」全ての場合に実行されます。

そして,else節内のif文は,「P[i]が対応する閉じ括弧か否か」を判定しています。
対応する閉じ括弧でない場合,問答無用で0を返しています。

P[i]が'a'の時,P[i]を'a'に置き換えると,
if ('a' == '(' || 'a' == '[' || 'a' == '{') {
    push('a');
} else {
    ch = top();
    if ((ch == '(' && 'a' == ')') || (ch == '[' && 'a' == ']') || (ch == '{' && 'a' == '}')) {
        pop();
    } else {
        return 0;
    }
}

というコードになり,等価式を計算すると
if (0 || 0 || 0) {
    push('a');
} else {
    ch = top();
    if ((ch == '(' && 0) || (ch == '[' && 0) || (ch == '{' && 0)) {
        pop();
    } else {
        return 0;
    }
}

となります。if文の中の式は全て0に評価されるので,
if (0) {
    push('a');
} else {
    ch = top();
    if (0) {
        pop();
    } else {
        return 0;
    }
}

となり,else節の方を全て使って,
    ch = top();
        return 0;

だけが実際に実行されます。


改善するには,外側のelse節の中のif文,というより節の中全てを実行する前に,
P[i]が閉じ括弧であるか否かの判別を行う必要があります。

また,入力列
)
が来ると,未定義の動作となります。
topを読み込む前に,スタックが空でないことを確かめる必要があります。