• 締切済み

ポインタ版リスト構造によるスタックの実装

C言語を用いてアルゴリズムの勉強をしています。 現在、ポインタ版リスト構造によるスタックを実装し、入力された文字列の中で括弧の整合性を判定するプログラムを作成しているのですが、難航しています。 プログラムの内容は、以下の通りです。 入力:a{z[e(b){j}(p)]w}(j) 結果:整合 入力:a{z[e(b){j}(p)}w](j) 結果:不整合 ですが、所持している参考書の例題プログラムには、スタックに入れる要素が整数値のものしかなく、文字をスタックに入れるところからわかりません。 また、先輩に尋ねたところ、以下のような構造体を使うと良いとアドバイスされました。 typedef struct { int max; int num; List stk; } Stack; typedef struct { Node *head; Node *crnt; } List; typedef struct node { char data; struct node *next; } Node; 先輩には申し訳ないのですが、余計にわからなくなってしまいました。 この構造体を用いてプログラムをかける方、ご指導のほどよろしくお願いします。

みんなの回答

noname#208507
noname#208507
回答No.5

> char型に変更してみたのですが、何故かエラーが発生してしまいます。 関数StackAllocは、きちんと構造体のメモリを確保していますか。まさかとは思いますが、第一と第二引数を関数calloc(もしくは関数malloc)に渡して呼び出しているだけ、ではありませんよね。 ポップするとき、結果を引数で受け取るならStackPop(s, &x)のようにxのアドレスを渡すべきですが、プッシュするときはStackPush(s, x)のようにxを値渡しするべきです。それとデータ型に気を付けてください。 先輩さんのアドバイスを活かすなら、私は下のようにします。あとは括弧の対応を確認する方法ですが、これはスタックの使い方をよく考えれば分かるでしょう。 #include <stdlib.h> #define StackNo(s) ((s)->num) #define StackSize(s) ((s)->max) Stack *StackAlloc(int max) { Stack *stack = malloc(sizeof(Stack)); if (stack != NULL) { stack->max = max; stack->num = 0; stack->stk.head = stack->stk.crnt = NULL; } return stack; } int StackPush(Stack *stack, char data) { int ng = 0; Node *next = malloc(sizeof(Node)); if ((next != NULL) && (stack->num < stack->max)) { next->data = data; next->next = NULL; if (stack->stk.head == NULL) { stack->stk.head = stack->stk.crnt = next; } else { stack->stk.crnt->next = next; stack->stk.crnt = next; } stack->num++; } else { free(next); ng = -1; } return ng; } int StackPop(Stack *stack, char *data) { int ng = 0; Node *prev = stack->stk.head; Node *crnt = stack->stk.crnt; if (prev != NULL) { *data = crnt->data; if (prev == crnt) { stack->stk.head = stack->stk.crnt = NULL; } else { while (prev->next != crnt) { prev = prev->next; } prev->next = NULL; stack->stk.crnt = prev; } free(crnt); stack->num--; } else { ng = -1; } return ng; } void StackFree(Stack *stack) { char data = '\0'; if (stack != NULL) { while (StackPop(stack, &data) != -1); } free(stack); }

  • kmee
  • ベストアンサー率55% (1857/3366)
回答No.4

C言語では、char は「文字が表現できるサイズの整数」です。 intはcharより大きな整数なので、「intを格納するスタック」にcharを入れることが可能です。 補足にあった実装では、intへのポインタを使っているので、一旦int型の変数に入れて使えば、そのまま流用できます Stack *s; char str[] ; /* 文字列 */ int c ; (略) c=str[i] ; /*1文字取り出す*/ StackPush(s, &c) ... StackPop(s, &c) str[i]=c ; /*1文字戻す*/ それよりも、本来の目的「括弧の対応を確認する」の方は大丈夫ですか? スタックをどう作るか、等は小さな問題です。

  • Tacosan
  • ベストアンサー率23% (3656/15482)
回答No.3

とりあえず「先輩には申し訳ないのですが、余計にわからなくなってしまいました」じゃダメだね. 「どこがどう」わからないのか, 自分で考えないと. ちなみに「適当な定数」としては, 例えば ( には '(' を使うことを推奨します.

  • honor
  • ベストアンサー率35% (25/71)
回答No.2

括弧の整合性を確認したいだけならa-zの文字は読み飛ばしてもいいんですよね。 (){}[]に適当な定数を決めて順番にスタックに入れて、対応するものが来たらスタックから出せばいいんじゃないでしょうか。

synox
質問者

補足

ご回答ありがとうございます。 > 括弧の整合性を確認したいだけならa-zの文字は読み飛ばしてもいいんですよね。 はい、その通りです。 > (){}[]に適当な定数を決めて順番にスタックに入れて 『適当な定数』というのは初めに定義しておく、ということでしょうか。

noname#208507
noname#208507
回答No.1

> 例題プログラムには、スタックに入れる要素が整数値のものしかなく、 その要素はint型ですよね? とりあえずスタックについては、int型をchar型に変えればよいだけでは。

synox
質問者

補足

ご指摘ありがとうございます。 char型に変更してみたのですが、何故かエラーが発生してしまいます。 以下、main関数のソースコードです。 ※現在、完成しているプログラムは『整数値をプッシュ/ポップする』ところまでです。 /**/ int main(void) { Stack *s; if ((s = StackAlloc(sizeof(int), 100)) == NULL) { puts("スタックの確保に失敗しました。"); return (1); } while (1) { int m; double x; printf("現在のデータ数:%d/%d\n", StackNo(s), StackSize(s)); printf("(1) プッシュ (2) ポップ (0) 終了:"); scanf("%d", &m); if (m == 0) break; switch (m) { case 1: printf("データ:"); scanf("%d", &x); if (StackPush(s, &x) == -1) puts("スタックへのプッシュに失敗しました。"); break; case 2: if (StackPop(s, &x) == -1) puts("ポップできません。"); else printf("ポップしたデータは%dです。\n", x); break; } } StackFree(s); return (0); }

関連するQ&A

  • リスト

    プログラムのデータ構造の勉強を進めてるのですが リストのところである問題がどうしてもリスト(ポインタ)で解けません 基礎的なことがわかるのですが(ノードの使い方などマロックなど) その問題は人の名前を入力し国語、数学、英語の点数を入力して3教科の点数を合計し名前、それぞれの点数、合計の表示、そしてまた入力を続けると指示した場合また名前3教科の点数をいれてと繰り返すのですが、繰り返したときに今まで入っているデータの人々の合計を比較して表示を昇順にしなくちゃなりません。どうすればいいか検討もつきません。 typedef struct _node { char name[10]; int Jap; int math; int eng; struct _node *next; } Node; で構造体はいいのでしょうか? できればくわしくプログラムを教えてください。 お願いします。

  • 線形リスト

    どうしても解けない課題がありまして、投稿しました。 どうか、お願いします。。。。 課題内容 下記の構造体を利用した線形リストを作り、 文字列の頻度を計算するプログラムを作成することを考えます。 typedef struct node { char *str; int hindo; struct node *next; } Node; このため、以下のヘッダファイルの名前を hindo.h とするとき、 以下の課題に答えなさい。 hindo.h typedef struct node { char *str; int hindo; struct node *next; } Node; Node* newnode(); void dispHindo(Node* p); int countHindo(Node* p, char *key); void delList(Node*p); Node のポインタを与えると、そのポインタが指す線形リストを解釈し、頻度を出力した後 ---------- を出力する void dispHindo(Node* pointer) を作成しなさい。 書式は一行ずつ「文字列: 頻度」となるようにしなさい。 なお、線形リストの最終ノードの next には NULL が入っていることとし、この場合他のメンバの値は使用しないものとします。 そして下記のプログラムと結合し、実行例と同じものが出ることを確認しなさい。 テストプログラム #include <stdio.h> #include "hindo.h" int main(void){ Node x, y , z, end; x.str="abc"; x.hindo=2; x.next=&y; y.str="def"; y.hindo=3; y.next=&z; z.str="ghi"; z.hindo=1; z.next=&end; end.next=NULL; dispHindo(&end); dispHindo(&x); return 0; } 実行例 ---------- abc: 2 def: 3 ghi: 1 ----------

  • スタックの配列プログラム

    スタックを配列で実現するプログラムとして #include<stdio.h> #define stack_size 100 #define stack_el_type int stack_el_type stack[stack_size]; int sp; void init_stack() { sp=-1 } void push(stack_el_type x) { if (sp < stack_size -1) stack[++sp] = x; else{ printf("stack full error.\n"); exit(1); } } stack_el_type pop() { if(sp >= 0 ) return stack[sp--]; else { printf("stack empty error.\n") exit(1); } } 上の完成形を参照として、 他の作り方として int stack[100] int sp void push(int x) int pop() を用いて作成する場合どのようにすればよいのでしょうか? またスタックを一方向リストで実現するプログラムを作成するとき struct node{ int data; struct node *next; } struct node *push(int x,struct node *root) struct node *pop(struct node *root) を用いて作成する場合どのようにすればよいのでしょうか? よろしければご教授お願いします

  • 構造体について

    構造体について分からない点があり,教えて頂きたく投稿いたします. 現在,以下のような構造体を作成しています. typedef struct{ int data; struct node *NEXT; }node; また,それを管理するためのリストを以下の構造体にて宣言しました. typedef struct{ node *crnt; node *last; }node_list; また,使用する関数内での宣言は以下の通りです. node_list *non_dscvr_node_list; //未探査ノードを格納する node *crt_dscvr_node; //現在探査中のノードを示す node *start; そして, start->data = 10; start->NEXT = NULL; non_dscvr_node_list->crnt = start; non_dscvr_node_list->last = start; : : crt_dscvr_node = non_dscvr_node_list->crnt; non_dscvr_node_list->crnt = crt_dscvr_node->NEXT; //ここでエラーがでる. エラーの詳細は以下の通りです. warning: assignment from incompatible pointer type 私としては,リストに格納されている先頭ノードをポップして,次のノードを先頭にしたつもりだったのですが,ポインタタイプに互換性がないと怒られてしまいました. 少し調べては見ましたが,nodeの構造体を管理するために別に構造体を定義しているページがあまり見あたりません. 従って,そのようなページがあれば教えて頂きたいと思います. このような方法はあまりよくないのでしょうか. 併せて教えていただけますようお願いいたします.

  • リスト構造をファイルに出力

    struct node{ NODE *next[5]; NODE *pre; }NODE; というような構造体を定義して int main(){ int i; NODE *first; NODE *nd[1000]; first=(NODE*)malloc(sizeof(NODE)); for(i=0;i<1000;i++){ nd[i]=(NODE*)malloc(sizeof(NODE)); } //各NODEを樹構造に定義 first->next[0]=nd[0]; : : } のようなプログラムを組んで NODE[5]→NODE[0]→NODE[1]→NODE[3]       ↓     ←NODE[4]→   のようなリンクリストを構成したのですが そのリストをそのままファイルに出力できませんか? テキストに落として再読み込みすることは考えたのですがメモリの状態をそのままファイルに落とす方法があればそちらのほうが簡便ですので 詳しいいらっしゃいますか? 開発環境はVisualSturio.NETでC++を使っています。

  • スタックのデータ構造を作りたい

    C言語でスタックと、スタックにデータを入れるプッシュ、取り出すポップを作りたいと思っており そこで以下のようなものを作ってみました。 ********************************************** #include<stdio.h> typedef struct{ int a[100]; int head=0; }Stack; void push(Stack stc,int x){ stc.a[head]=x; stc.head++; } int pop(Stack stc){ return(stc.a[head-1]); stc.head--; } int main void{ int j; Stack s; push(s,5); push(s,90); j=pop(s); printf("%d",j); j=pop(s); printf("%d",j); return 0; } ****************************** コンパイルするとエラーが出まくりです。 何をどう直せばよいのか、どこが変なのかご教授いただきたいです。 よろしくお願いいたします。

  • リストがわかりません。

    下のプログラムはリストに昇順になるように 入力された要素を挿入するプログラムですが、うまくいきません。どうか教えてください。 #include<stdio.h> static int count; struct node_tag{ int data; struct node_tag *next; }; typedef struct node_tag node_t; node_t *insert_node( node_t *t, int d ); node_t *print_list( node_t *r ); int main( void ) { node_t root; int data; root.next = NULL; for ( ;; ) { printf( "> " ); if ( scanf( "%d", &data ) != 1 ) break; insert_node( &root, data ); print_list( &root ); } return; } node_t *insert_node( node_t *t, int d ) { node_t *new_node; new_node = (node_t *)malloc( sizeof(node_t) ); if( new_node == NULL ) return NULL; if(count == 0) { new_node -> data = d; new_node -> next = NULL; t -> next = new_node; count++; } else { for(; t -> next != NULL; t = t -> next) { if(t -> next -> data >= d) break; } if(t -> next -> data == d) return; else if(t -> next -> data > d) { new_node -> data = d; new_node -> next = t -> next; t -> next = new_node; } else if(t -> next == NULL) { new_node -> data = d; t -> next = new_node; new_node -> next = NULL; } } return new_node; } node_t *print_list( node_t *r ) { node_t *p; printf("[ "); for( p = r -> next; p != NULL; p = p -> next) { printf("%d ", p -> data); } printf("]\n"); }

  • 構造体のポインタにNULLが入らない

    typedef struct tag{ int number; char name[10]; struct tag *next; }DATA; という構造体があって、 DATA *p; と宣言し、 p->next == NULL; とすることはできないんですか? セグメンテーション違反になってしまうのですが。 pが指すnextにNULLを入れるにはどうしたらいいのでしょうか?

  • List構造

    Listの尻にノードを追加する関数で困っています。 以下に、ソースの一部を掲載させていただきます。 typedef struct __node{ int data; struct __node *next; }Node; ... /*リストの尻にノードを追加する関数 * 引数: head. リストの先頭ノードのポインタ data. リストの尻に追加したいint型の変数*/ void Insert_Tail(Node *head, int data) { Node *ptr = head; if(ptr == NULL){ /*<ノードが存在しない時には追加されない>*/ /*領域の確保*/      head = (Node*)calloc(1,sizeof(Node)); /*データをセット*/ head->data = data; head->next = NULL; return ; }else{ /*<ノードが存在するときには正常に動作>*/ while(ptr->next != NULL){ ptr = ptr->next; } /*領域の確保*/ ptr->next = (Node*)calloc(1,sizeof(Node));      /*データのセット*/ ptr->next->data = data; ptr->next->next = NULL; } } コメントアウトにも書かせていただきましたが、ノードがすでに存在するときには、正常にノードの最後に追加してくれるのですが、ノードが存在しない時にはリストに追加してくれません。 どうかご指導、ご指摘の程お願いします。

  • リスト構造を双方向リスト構造に書き換えたいです

    C言語初心者です。以下のリスト構造を双方向リストに書き換えたいです。 構造体にstruct transcript *prvs;を追加するのはいいとして、その後どのように変更したらよいでしょうか。関数printingdudeのprvs版を追加し、メイン部でprintingdude_prvs(Z)をすればよいでしょうか。詳しい方、お手数ですがご教示頂きたいです。。 #include <stdio.h> #include <stdlib.h> typedef struct transcript { int no; struct transcript *next; } tra; void printingdude(tra *x) { if (x == NULL) return; printf("%d",x->no); if (x->next != NULL) { printf(", "); printingdude(x->next); } else { printf("\n"); } return; } void free_noud(tra *x) { while (x != NULL) { tra *t = x->next; free(x); x = t; } return; } tra* nnoud(int v, tra* c) { tra *x = (tra *) malloc(sizeof(tra)); if (!x) { printf("\ncan't allocate memory for a new node"); exit(EXIT_FAILURE); } x->no = v; x->next = c; return x; } int main() { tra *Z = NULL; for (int n = 10; n>0; n--) { printingdude(Z); Z = nnoud(n, Z); } printingdude(Z); free_noud(Z); return 0; }

専門家に質問してみよう