🎄teratailクリスマスプレゼントキャンペーン2024🎄』開催中!

\teratail特別グッズやAmazonギフトカード最大2,000円分が当たる!/

詳細はこちら
C

C言語は、1972年にAT&Tベル研究所の、デニス・リッチーが主体となって作成したプログラミング言語です。 B言語の後継言語として開発されたことからC言語と命名。そのため、表記法などはB言語やALGOLに近いとされています。 Cの拡張版であるC++言語とともに、現在世界中でもっとも普及されているプログラミング言語です。

Q&A

解決済

5回答

8857閲覧

c言語で二分探索木を実装したいです

kyapi

総合スコア5

C

C言語は、1972年にAT&Tベル研究所の、デニス・リッチーが主体となって作成したプログラミング言語です。 B言語の後継言語として開発されたことからC言語と命名。そのため、表記法などはB言語やALGOLに近いとされています。 Cの拡張版であるC++言語とともに、現在世界中でもっとも普及されているプログラミング言語です。

0グッド

1クリップ

投稿2020/12/01 03:12

編集2020/12/02 08:18
コード `#include <stdio.h> #include <stdlib.h> /* 木の節の定義 */ typedef struct node{ int data; /* 探索のキーになるデータ型 */ struct node *left; /* 左の子 */ struct node *right; /* 右の子 */ }NODE; /* メンバright,leftにNULLポインタがセットされているときは該当する子がいないことを表す */ /* 初期状態では二分探索木は空の状態。 グローバル変数rootが二分探索木の根へのポインタを保持しているものとする */ /* グローバル変数rootをNULLで初期化 */ NODE *root = NULL; /* エラーメッセージをプリントしてexitする関数*/ /* ポインタ(アドレス)の先のデータを読み取り専用にする */ void fatal_error(const char *s) { /* fprintf関数を使ってstderrで標準エラーを出力する*/ fprintf(stderr,"%s", s); exit(1); /* 異常終了 */ } /* 二分探索木から最小の要素を削除する関数 */ /* 削除した節へのポインタを返す p:二分探索木へのポインタへのポインタ (つまり*pが木へのポインタとなる) NODE型へのポインターが戻り値 */ NODE *deletemin(NODE **p) { NODE *x; while ((*p)->left != NULL) p=&(*p)->left; x=*p; *p=(*p)->right; return x; } /* 二分探索木を探索する関数 */ /* パラメータkeyを受け取ってポインタを返す関数として定義 key:探索すべきキーの値 探索に成功した場合そのデータの節へのポインタを返す NODE型へのポインターが戻り値 */ NODE *search(int key) { NODE *p; /* 現在注目している節 */ p=root; /* まず根に注目する */ /* 進むべき子が存在する限り繰り返す */ while (p != NULL) { /* キーと注目している節のデータが等しいか比較 */ if (key == p->data){ /* もしキーと注目している節のデータとが等しければポインタを関数として返す */ printf("探索した値の番地です>>%p\n",p); return p; }else if (key < p->data){ /* キーの方が小さければ左部分木に進む */ p = p->left; }else{ /* キーの方が大きければ右部分木に進む*/ p = p->right; } /* ループを抜け出たということは見付からなかったというと NULL返して失敗したことを知らせる */ printf("NotExist\n"); return NULL; } } /* 二分探索木から要素を追加する関数*/ /* 探索と同じ要領で木を辿り、辿るべき部分木がなければそこに挿入する */ /* 挿入した要素が置かれる節へのポインタを返す すでに要素が登録されているのなら、何もしないでNULLを返す key:挿入するデータ NODE型へのポインターが戻り値 */ NODE *insert(int key) { NODE **p,*new; /* 変数pが変数rootを指すように初期化する */ p=&root; /* 挿入すべき場所が見つかるまで繰り返す */ while (*p != NULL) { /* キーと注目している節のデータが等しいか比較 */ if (key == (*p)->data){ /* すでに登録されている */ printf("AlreadyExsits\n"); return NULL; }else if (key < (*p)->data){ /* キーの方が小さければ左部分木に進む */ p =&(*p)->left; }else{ /* キーの方が大きければ右部分木に進む */ p =&(*p)->right; } } /* 挿入されるべき場所が見つかったら */ /* 挿入される節をつくる */ /* strct型のメモリを確保した分だけnewに入れる。もしNULLだったらエラー */ if((new=malloc(sizeof(NODE)))==NULL) fatal_error("out of memory!!"); /* 新しい節には子がないのでNULLにしておく */ new->left =NULL; new->right=NULL; /* 要素の値をセットする */ new->data=key; /* 正しい場所に挿入する */ /* ポインタpは挿入される節へのポインタが入っている場所を指している */ *p=new; return new; } /* 二分探索木から要素を削除する関数 */ /* 削除に成功したら1、要素が存在しなければ0を返す key:削除するデータ */ int delete(int key) { /* 親へのポインタを使う */ NODE **p, *x; /* 変数pが変数rootを指すように初期化する */ p = &root; /* 削除対象となる要素を探す */ while (*p != NULL) { /* 見つかった 変数pは削除される節の親のメンバleft,right 変数xは削除される節そのものを指している */ if (key == (*p)->data) { x = *p; /* 1つも子を持っていない、葉である場合 */ if (x->left == NULL && x->right == NULL){ *p = NULL; /* 右の子のみをもつ */ }else if (x->left == NULL){ *p = x->right; /* 左の子のみをもつ */ }else if (x->right == NULL){ *p = x->left; /* 左右2つの子を持つ */ }else{ /* 部分木から最小の要素を取り去る */ *p = deletemin(&x->right); (*p)->right = x->right; (*p)->left = x->left; } /* 取り除いた節を解放させる */ free(x); printf("Done\n"); return 1; }else if (key < (*p)->data){ /* 左部分木に進む */ p = &(*p)->left; }else{ /* 右部分木に進む */ p = &(*p)->right; } } /* 削除対象が見つからなかった */ printf("NotExist\n"); return 0; } /* 二分木を行きがけ順でなぞる */ void preorder(NODE *p) { /* 木が空なら何もしない */ if(p==NULL) return; else{ printf("%d ",p->data); /* 自身の値を出力 */ preorder(p->left); /* 左ノードへ移動 */ preorder(p->right); /* 右ノードへ移動 */ } } /* 二分木を通りがけ順でなぞる */ /* 全要素を昇順に表示する関数 二分探索木の全要素を小→大の順で表示する */ /* 全体の流れ ある要素の左枝先を全部調べ終えたら、自身の値を出力し、 次にその要素の右枝先の要素を全部調べる 左枝を調べる 調べ終えたら戻ってくる 値を出力する 右枝を調べる 調べ終えたら戻ってくる 関数を終了して、自身を呼び出した関数の元へと戻る */ void inorder(NODE *p) { /* 木が空なら何もしない */ if(p==NULL) return; else{ /* 引数に左へのポインタを渡すことで、再帰を繰り返して延々と左枝へ移動し 一番左、一番小さい値にたどり着く 子ノードはないため、引数の値はNULLに当たって戻ってくる 一番下位の要素なので、左枝と同様に右枝もない。 なので終点である NULL に行き当たり、また return で戻ってくる。 そして「一番左を操作する関数」は処理を終える。 この関数に戻り値はない。「画面に出力」して、それで終了*/ inorder(p->left); /* 左ノードへ移動 */ printf("%d ",p->data); /* 自身の値を出力 */ inorder(p->right); /* 右ノードへ移動 */ } /* 関数を終了して、自身を呼び出した関数のもとへ戻る */ } /* 二分木を帰りがけ順でなぞる */ void postorder(NODE *p) { /* 木が空なら何もしない */ if(p==NULL) return; else{ postorder(p->left); /* 左ノードへ移動 */ postorder(p->right); /* 右ノードへ移動 */ printf("%d ",p->data); /* 自身の値を出力 */ } } int main(void) { int a,key; int mn=0; printf("二分探索木をします\n"); do{ printf("\nメニューを選んでください\n1=追加 2=行きがけ順 3=通りがけ順 4=帰りがけ順 5=指定した値の番地 6=削除 9=終了\n"); scanf("%d",&mn); switch(mn){ case 1: printf("追加する数字を入力してください\n"); scanf("%d",&a); insert(a); break; case 2: printf("行きがけ順です\n"); preorder(root); break; case 3: printf("通りがけ順です\n"); inorder(root); break; case 4: printf("帰りがけ順です\n"); postorder(root); break; case 5: printf("指定した値の番地を出力します\n"); scanf("%d",&key); search(key); break; case 6: printf("指定した値を削除します\n"); scanf("%d",&key); delete(key); break; case 9: printf("終了します\n"); break; default: printf("エラー:メニューの中の数字を入力してください\n"); } }while (mn !=9); return 0; } `` ```### 前提・実現したいこと`````` 二分探索木のプログラムを実装したいです 仕様は 数字を入力して 1=追加 2=行きがけ順で表示 3=通りがけ順で表示 4=帰りがけ順で表示 5=指定した値の番地で表示 6=削除 9=終了 ができるようにしたいです アドバイスお願いいたします!! ### 発生している問題・エラーメッセージ 「34行目」で記述エラーを発見しました。 「identifier」を付け忘れています。 と出てしまいます

該当のソースコード

ここに言語を入力 ``` コード ``` ### 悩んでいること ① まず、 NODE *search(int key) 教科書に書いてあったこの宣言の仕方がよく分かりません 型名なしの関数の宣言の仕方を調べると一つだけ解説しているサイトが見つかり、自動的にint型になると書  いてあったのですが正しいのでしょうか? 引数があり、戻り値がある場合はvoid型ではない、 引数があり、戻り値がない場合はvoid型、 引数がなし、戻り値がある場合もvoid型、 引数がなし、戻り値がない場合もvoid型 と学びました preorder(NODE *p) postorder(NODE *p) inorder(NODE *p) これらの関数は引数があり、戻り値がない場合なのでvoid型、 int delete(int key) この関数も引数があり、戻り値がない場合なのでvoid型だと思われるのですがなぜint型なのでしょうか NODE *search(int key) NODE *insert(int key) NODE *deletemin(NODE **p) これらの関数は引数があり、戻り値がある場合はvoid型ではない、int型だと思います。 ②keyの扱い方についてです if (key == p->data) ここの部分で教科書では関数を使って比べていましたがむずかしいので不等号を使って比べることにしました keyは値ですが、p->dataは番地ですよね 同じように値同士で扱うにはどのようにしたら良いのでしょうか 構造体の場合、アロー演算子は番地、ドットが実体だと習いましたがエラーが出てしまいます ③関数の値渡しについてです case 1: printf("追加する数字を入力してください\n"); scanf("%d",&a); insert(a); break; case 5: printf("指定した値の番地を出力します\n"); scanf("%d",&key1); search(key1); break; case 6: printf("指定した値を削除します\n"); scanf("%d",&key2); delete(key2); break; ここの部分で出力する場合の値と指定した値の変数名はそれぞれ変えたほうが良いですよね? ④探索した値の番地を出力する際に、 /* もしキーと注目している節のデータとが等しければポインタを関数として返す */ printf("探索した値の番地です>>%d\n",p->data); return p; としていますが、めちゃくちゃな状態です 探索した値の番地を返す場合、 return pはどのように扱えば良いのか悩みます。 ### 補足情報(FW/ツールのバージョンなど 初心者で使い方がよく分かっていません 自分の理解が正しいのか不安なのでコメント多いです 見づらければ修正します ご指摘ください

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

y_waiwai

2020/12/01 03:15

このままではコードが読みづらいので、質問を編集し、<code>ボタンを押し、出てくる’’’の枠の中にコードを貼り付けてください
Zuishin

2020/12/01 03:19

> 「34行目」で記述エラーを発見しました。 > 「identifier」を付け忘れています。 > と出てしまいます それどころじゃなく、数えきれないほどの warning と error が出ました。
kyapi

2020/12/01 03:31

y_waiwaiさん、 コードの挿入をしました!
Zuishin

2020/12/01 03:34

> 他にも凡ミスがあるかもしれません 凡ミスというのは、本来できるはずのことをミスした時に使う言葉です。 20 行目や 30 行目などを見ても、まったく何もわからない人が書いたものにしか見えません。 あなたにはこの課題は早すぎます。この手の質問を見るたびに思うんですが、なぜ学習してから取り組まないのでしょう? テスト勉強せずにテストしなければならないルールでもあるんでしょうか?
fana

2020/12/01 06:49

> ドットにしたり、他の変数にに代入して値にしてもダメだった 行き当たりばったりにいじくってても仕方ないのでは. (確率的にたまたま正解と同じになることもあるハズ!という可能性に賭けた取り組み方なのか?) 課題が教科書に沿う内容であれば,教科書を読み返すのが最も手っ取り早い「頑張り」方なのでは.
guest

回答5

0

ベストアンサー

searchのインデントを修正しました。
あきらかにおかしいことが判るかと思います。
whileの外側でNotExistを印字すべきです。

C

1NODE *search(int key) 2{ 3 NODE *p; /* 現在注目している節 */ 4 p = root; /* まず根に注目する */ 5 6 /* 進むべき子が存在する限り繰り返す */ 7 while (p != NULL) { 8 /* キーと注目している節のデータが等しいか比較 */ 9 if (key == p->data) { 10 /* もしキーと注目している節のデータとが等しければポインタを関数として返す */ 11 printf("探索した値の番地です>>%p\n", p); 12 return p; 13 } else if (key < p->data) { 14 /* キーの方が小さければ左部分木に進む */ 15 p = p->left; 16 } else { 17 /* キーの方が大きければ右部分木に進む */ 18 p = p->right; 19 } 20 /* ループを抜け出たということは見付からなかったというと 21 NULL返して失敗したことを知らせる */ 22 printf("NotExist\n"); 23 return NULL; 24 } 25} 26

投稿2020/12/02 08:50

tatsu99

総合スコア5493

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

kyapi

2020/12/02 09:19

インデントについてよく理解していなくて申し訳ありません ルールをしっかり学ぼうと思います インデントをきちんとするとミスがすぐ見つかりますね 誠にありがとうございました!!! 完璧に動作するようになりました、丁寧な解説で本当に助かりました!!
guest

0

あなたの修正したソースをコピペして、
こちらの環境(Mingw gcc)でコンパイルするとエラーになります。
全角の空白が混じっています。あなたの環境ではエラーになりませんか。
(コンパイラによっては全角空白も半角空白と同じ扱いをするのがあるかもしれませんが)
添付図の黄色の部分です。
イメージ説明

int deleteのみ整形しました。
if (x->left == NULL) { //ここからif文の書き方変えました
の個所ですが、少し上の行で
if (x->left == NULL && x->right == NULL) {
の判断をしているので、
if (x->left == NULL) { は必ず成立します。
以前のより悪くなっているような気がします。
インデントをきちんとすれば、わかりやすいかと。

C

1int delete(int key) 2{ 3 /* 親へのポインタを使う */ 4 NODE **p, *x; 5 /* 変数pが変数rootを指すように初期化する */ 6 p = &root; 7 /* 削除対象となる要素を探す */ 8 while (*p != NULL) { 9 /* 見つかった 10 変数pは削除される節の親のメンバleft,right 11 変数xは削除される節そのものを指している */ 12 if (key == (*p)->data) { 13 x = *p; 14 /* 1つも子を持っていない、葉である場合 */ 15 if (x->left == NULL && x->right == NULL) { 16 *p = NULL; 17 /* 右の子のみをもつ */ 18 if (x->left == NULL) { //ここからif文の書き方変えました 19 *p = x->right; 20 /* 左の子のみをもつ */ 21 } else if (x->right == NULL) { 22 *p = x->left; 23 /* 左右2つの子を持つ */ 24 } else { 25 /* 部分木から最小の要素を取り去る */ 26 *p = deletemin(&x->right); 27 (*p)->right = x->right; 28 (*p)->left = x->left; 29 } 30 /* 取り除いた節を解放させる */ 31 free(x); 32 printf("Done\n"); 33 return 1; 34 35 } else if (key < (*p)->data) 36 /* 左部分木に進む */ 37 p = &(*p)->left; 38 else 39 /* 右部分木に進む */ 40 p = &(*p)->right; 41 } 42 } 43 /* 削除対象が見つからなかった */ 44 printf("NotExist\n"); 45 return 0; 46} 47

こちらで実行した結果です。
30を追加
20を追加
行きがけ順で表示
20を削除・・・ここで応答なしになるため、Ctrl+Cで強制終了
削除の処理で無限ループしていると思われます。

D:\goo\c>goo1_1
二分探索木をします
メニューを選んでください

1=追加
2=行きがけ順
3=通りがけ順
4=帰りがけ順
5=指定した値の番地
6=削除
9=終了
1
追加する数字を入力してください
30
メニューを選んでください

1=追加
2=行きがけ順
3=通りがけ順
4=帰りがけ順
5=指定した値の番地
6=削除
9=終了
1
追加する数字を入力してください
20
メニューを選んでください

1=追加
2=行きがけ順
3=通りがけ順
4=帰りがけ順
5=指定した値の番地
6=削除
9=終了
2
行きがけ順です
3020メニューを選んでください

1=追加
2=行きがけ順
3=通りがけ順
4=帰りがけ順
5=指定した値の番地
6=削除
9=終了
6
指定した値を削除します
20
^C

投稿2020/12/02 02:53

編集2020/12/02 03:30
tatsu99

総合スコア5493

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

kyapi

2020/12/02 03:21

すみません、編集のときに全角が入ってしまったのだと思います インデントをきちんとするとわかりやすいですね ありがとうございます!!! しかしpaizaでRuntime error(Exit status:153(File size limit exceeded)) というエラーがでてしまいます。 オーバーフローではなく、他に原因があるのでしょうか tatsu99さんの環境ではどのようなエラーが出るのか教えていただけませんか?
tatsu99

2020/12/02 03:31

追記しました。
kyapi

2020/12/02 07:57

ありがとうございます!!! エラーなく実行できるようになりました しかし、値の番地が出てこない時があります 例えば、追加を三回したときに 2  5  6 としたとき、 5=指定した値の番地は 最初に追加した2だけ番地が出て、 5、6はNotExistになってしまいます どのkeyも一致すれば番地がでるはずなのですが、先頭以外はなにか特別なことをしなければならないのでしょうか その場合は何か助言をお願いいたします それともプログラムの仕組みが間違えているのでしょうか??
tatsu99

2020/12/02 08:03

最新のソースで、既存のソースを更新してください。そのソースをみてみます
kyapi

2020/12/02 08:19

最新のソースに修正しました! だらだら長くなるのでメニューは横並びにしました
tatsu99

2020/12/02 08:52

次の回答欄に書きました。 インデントを正しく書けばわかるバグかと思います。
guest

0

とりあえず、コンパイルエラーをとり、整形しました。
https://paiza.io/ja/projects/new?language=c
でも、確認できます。実行はしていません。
//追加
//変更
//削除
のコメントを入れてます。

C

1#include <stdio.h> 2#include <stdlib.h> 3/* 木の節の定義 */ 4typedef struct node { 5 int data; /* 探索のキーになるデータ型 */ 6 struct node *left; /* 左の子 */ 7 struct node *right; /* 右の子 */ 8} NODE; 9 10/* 初期状態では二分探索木は空の状態。 11 グローバル変数rootが二分探索木の根へのポインタを保持しているものとする */ 12/* グローバル変数rootをNULLで初期化 */ 13NODE *root = NULL; 14 15/* エラーメッセージをプリントしてexitする関数*/ 16/* ポインタ(アドレス)の先のデータを読み取り専用にする */ 17void fatal_error(const char *s) 18{ 19 /* fprintf関数を使ってstderrで標準エラーを出力する */ 20 fprintf(stderr, "%s", s); 21 exit(1); /* 異常終了 */ 22 23} 24 25/* 二分探索木を探索する関数 */ 26NODE *search(int key) 27{ 28 NODE *p; /* 現在注目している節 */ 29 p = root; /* まず根に注目する */ 30 /* 進むべき子が存在する限り繰り返す */ 31 while (p != NULL) { 32 /* キーと注目している節のデータが等しいか比較 */ 33 if (key == p->data) { //変更開始 34 /* もしキーと注目している節のデータとが等しければポインタを関数として返す */ 35 printf("探索した値の番地です>>%d\n", p->data); 36 return p; 37 } else { 38 if (key < (p->data)) 39 /* キーの方が小さければ左部分木に進む */ 40 p = p->left; 41 else 42 /* キーの方が大きければ右部分木に進む */ 43 p = p->right; 44 } 45 } //変更終了 46 printf("NotExist\n"); 47 return NULL; 48} 49 50/* 二分探索木から要素を追加する関数*/ 51NODE *insert(int key) 52{ 53 //int key; //削除 54 NODE **p, *new; 55 /* 変数pが変数rootを指すように初期化する */ 56 p = &root; 57 /* 挿入すべき場所が見つかるまで繰り返す */ 58 while (*p != NULL) { 59 /* キーと注目している節のデータが等しいか比較 */ 60 if (key == (*p)->data) 61 /* すでに登録されている */ 62 return NULL; 63 else if (key < (*p)->data) //変更 64 /* キーの方が小さければ左部分木に進む */ 65 p = &(*p)->left; 66 else 67 /* キーの方が大きければ右部分木に進む */ 68 p = &(*p)->right; 69 } 70 /* 挿入されるべき場所が見つかったら */ 71 /* 挿入される節をつくる */ 72 if ((new = malloc(sizeof(NODE))) == NULL) //変更 73 fatal_error("out of memory!!"); 74 /* 新しい節には子がないのでNULLにしておく */ 75 new->left = NULL; 76 new->right = NULL; 77 /* 要素の値をセットする */ 78 new->data = key; 79 /* 正しい場所に挿入する */ 80 /* ポインタpは挿入される節へのポインタが入っている場所を指している */ 81 *p = new; 82 return new; 83} 84 85/* 二分探索木から最小の要素を削除する関数 */ 86 87NODE *deletemin(NODE ** p) 88{ 89 NODE *x; 90 91 while ((*p)->left != NULL) 92 p = &(*p)->left; 93 x = *p; 94 *p = (*p)->right; 95 return x; 96} 97 98/* 二分探索木から要素を削除する関数 */ 99int delete(int key) 100{ 101 //int key; //削除 102 /* 親へのポインタを使う */ 103 NODE **p, *x; 104 /* 変数pが変数rootを指すように初期化する */ 105 p = &root; 106 /* 削除対象となる要素を探す */ 107 while (*p != NULL) { 108 /* 見つかった 109 変数pは削除される節の親のメンバleft,right 110 変数xは削除される節そのものを指している */ 111 if (key == (*p)->data) { 112 x = *p; 113 /* 1つも子を持っていない、葉である場合 */ 114 if (x->left == NULL && x->right == NULL) 115 *p = NULL; 116 /* 右の子のみをもつ */ 117 else if (x->left == NULL) 118 *p = x->right; 119 /* 左の子のみをもつ */ 120 else if (x->right == NULL) 121 *p = x->left; 122 /* 左右2つの子を持つ */ 123 else { 124 /* 部分木から最小の要素を取り去る */ 125 *p = deletemin(&x->right); 126 (*p)->right = x->right; //変更 127 (*p)->left = x->left; //変更 128 } 129 /* 取り除いた節を解放させる */ 130 free(x); 131 printf("Done\n"); 132 return 1; 133 } else if (key < (*p)->data) 134 /* 左部分木に進む */ 135 p = &(*p)->left; 136 else 137 /* 右部分木に進む */ 138 p = &(*p)->right; 139 } 140 /* 削除対象が見つからなかった */ 141 printf("NotExist\n"); 142 return 0; 143} 144 145/* 二分木を行きがけ順でなぞる */ 146void preorder(NODE * p) //変更 147{ 148 /* 木が空なら何もしない */ 149 if (p == NULL) 150 return; 151 else { 152 printf("%d", p->data); /* 自身の値を出力 */ 153 preorder(p->left); /* 左ノードへ移動 */ 154 preorder(p->right); /* 右ノードへ移動 */ 155 } 156} 157 158/* 二分木を通りがけ順でなぞる */ 159 160void inorder(NODE * p) //変更 161{ 162 /* 木が空なら何もしない */ 163 if (p == NULL) 164 return; 165 else { 166 inorder(p->left); /* 左ノードへ移動 */ 167 printf("%d", p->data); /* 自身の値を出力 */ 168 inorder(p->right); /* 右ノードへ移動 */ 169 } 170} 171 172/* 二分木を帰りがけ順でなぞる */ 173void postorder(NODE * p) //変更 174{ 175 /* 木が空なら何もしない */ 176 if (p == NULL) 177 return; 178 else { 179 postorder(p->left); /* 左ノードへ移動 *///変更 180 postorder(p->right); /* 右ノードへ移動 */ 181 printf("%d", p->data); /* 自身の値を出力 */ 182 } 183} 184 185 186int main(void) 187{ 188 int i; 189 int n; 190 int a, b, c; 191 int key; //追加 192 int mn = 0; 193 194 printf("二分探索木をします\n"); 195 do { 196 printf 197 ("メニューを選んでください\n\n1=追加\n2=行きがけ順\n3=通りがけ順\n4=帰りがけ順\n5=指定した値の番地\n6=削除\n9=終了\n"); 198 scanf("%d", &mn); 199 switch (mn) { 200 201 202 case 1: 203 printf("追加する数字を入力してください\n"); 204 scanf("%d", &a); 205 insert(a); 206 break; 207 208 case 2: 209 printf("行きがけ順です\n"); 210 preorder(root); //変更 211 break; 212 213 case 3: 214 printf("通りがけ順です\n"); 215 inorder(root); //変更 216 break; 217 218 case 4: 219 printf("帰りがけ順です\n"); 220 postorder(root); //変更 221 break; 222 223 case 5: 224 printf("指定した値の番地を出力します\n"); 225 search(key); 226 break; 227 228 case 6: 229 printf("指定した値を削除します\n"); 230 delete(key); 231 break; 232 233 case 9: 234 printf("終了します\n"); 235 break; 236 237 default: 238 printf("エラー:メニューの中の数字を入力してください\n"); 239 } 240 } while (mn != 9); 241 242 return 0; 243} 244

投稿2020/12/01 12:22

tatsu99

総合スコア5493

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

kyapi

2020/12/02 01:09

訂正してくださりありがとうございます、 変なミスばかりで申し訳ありません paizaでエラーを確認します ありがとうございます!!!
kyapi

2020/12/02 02:40

上記を参考にし、他の細々としたコンパイルエラーはとれました! プログラムコードを編集しました、よろしければご覧下さい paizaでは実行できても Runtime error(Exit status:153(File size limit exceeded)) というエラーがでてしまいます。 オーバーフローしているそうなのですが 関係しているとしたらmalloc関数ですが うまく解放できていないのでしょうか それとも int delete(int key) では //ここからif文の書き方を変えました のところでif文の書き方を変えたのですが、エラーがでなくて{}の閉じ方が違うのでしょうか?? EasyIDECでは実行はできましたが削除のみできませんでした アドバイスよろしくお願いいたします
guest

0

インラインで回答します。

① まず、
NODE *search(int key)
教科書に書いてあったこの宣言の仕方がよく分かりません

型名なしの関数の宣言の仕方を調べると一つだけ解説しているサイトが見つかり、自動的にint型になると書  いてあったのですが正しいのでしょうか?
(回答:正しいです。 sub(int key) と int sub(int key)は同じとみなされます。

引数があり、戻り値がある場合はvoid型ではない、(回答:正しい 例 int sub(int key)の場合)
引数があり、戻り値がない場合はvoid型、(回答:正しい 例 void sub(int key)の場合)
引数がなし、戻り値がある場合もvoid型、(回答:誤り 例 int sub(void) は引数なしのint型を返す関数)
引数がなし、戻り値がない場合もvoid型 回答:正しい 例 void sub(void)の場合)
と学びました

preorder(NODE *p)
postorder(NODE *p)
inorder(NODE *p)
これらの関数は引数があり、戻り値がない場合なのでvoid型、
回答:正しい。正確には
void preorder(NODE *p)
void postorder(NODE *p)
void inorder(NODE *p)
と記述すべきです。

int delete(int key)
この関数も引数があり、戻り値がない場合なのでvoid型だと思われるのですがなぜint型なのでしょうか
回答:戻り値はあります。int型です。あなたのソースの中で
return 1;
return 0;
の個所で、0又は1のint型のデータを戻り値として返しています。

NODE *search(int key)
NODE *insert(int key)
NODE *deletemin(NODE **p)
これらの関数は引数があり、戻り値がある場合はvoid型ではない、int型だと思います。
回答:誤り NODE型へのポインターが戻り値です。NODE型へのポインター型です。int型ではありません。

②keyの扱い方についてです

if (key == p->data)
ここの部分で教科書では関数を使って比べていましたがむずかしいので不等号を使って比べることにしました
keyは値ですが、p->dataは番地ですよね
回答:p->dataは値です。
printf("追加する数字を入力してください\n");
scanf("%d",&a);
で入力した数値が格納されます。
p->dataのpは番地(ポインター)です。p->dataは値です。
従ってif (key == p->data)は何の問題もありません。

同じように値同士で扱うにはどのようにしたら良いのでしょうか
構造体の場合、アロー演算子は番地、ドットが実体だと習いましたがエラーが出てしまいます

③関数の値渡しについてです
case 1:
printf("追加する数字を入力してください\n");
scanf("%d",&a);
insert(a);
break;
case 5:
printf("指定した値の番地を出力します\n");
scanf("%d",&key1);
search(key1);
break;

case 6:
printf("指定した値を削除します\n");
scanf("%d",&key2);
delete(key2);
break;

ここの部分で出力する場合の値と指定した値の変数名はそれぞれ変えたほうが良いですよね?
回答:a,key1,key2は全てint型なので同じにしても良いが、変えておいた方が、良いでしょう。
意味的に異なる変数は、別々に確保したほうが判りやすくなります。

④探索した値の番地を出力する際に、

/* もしキーと注目している節のデータとが等しければポインタを関数として返す */
printf("探索した値の番地です>>%d\n",p->data);
return p;
としていますが、めちゃくちゃな状態です
探索した値の番地を返す場合、 return pはどのように扱えば良いのか悩みます。
回答:p->dataは探索した値のデータです。したがって
printf("探索した値のデータです>>%d\n",p->data);
printf("探索した値の番地(アドレス)です>>%p\n",p);
return p;
とします。
ポインター(p)を印字する場合は %pを使用します。

投稿2020/12/01 10:19

tatsu99

総合スコア5493

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

kyapi

2020/12/02 00:50

丁寧に解説してくださり助かります、誠にありがとうございます! 参考にさせていただきます!!
guest

0

回答ではありません。
https://paiza.io/ja/projects/new?language=c
上記URLがwebで実行可能なCコンパイラです。
こちらで、実行してみてください。
エラーがたくさん出ます。
会員にならなくても、とりあえず、実行はできるみたいです。
但し、本格的に使うなら、会員になったほうが良いかも知れません。

蛇足ですが、下記が私の環境でコンパイルした結果です。(ソースはgoo1.cとしています)
(Mingw gcc version 8.3.0 (x86_64-posix-seh, Built by strawberryperl.com project))

D:\goo\c>vgcc goo1.c <gcc goo1.c -o goo1.exe --input-charset=cp932 --exec-charset=cp932> goo1.c: In function 'search': goo1.c:20:17: error: 'key' redeclared as different kind of symbol struct node key; ^~~ goo1.c:18:18: note: previous definition of 'key' was here NODE *search(int key) ~~~~^~~ goo1.c:26:13: error: invalid operands to binary == (have 'struct node' and 'int') if (key == p->data) ^~ ~~~~~~~ goo1.c:30:5: error: 'else' without a previous 'if' else if (key < (p->data)) { ^~~~ goo1.c:30:18: error: invalid operands to binary < (have 'struct node' and 'int') else if (key < (p->data)) { ^ ~~~~~~~~~ goo1.c:33:10: error: expected '}' before 'else' else ^~~~ goo1.c: In function 'insert': goo1.c:44:9: error: 'key' redeclared as different kind of symbol int key; ^~~ goo1.c:42:18: note: previous definition of 'key' was here NODE *insert(int key) ~~~~^~~ goo1.c:57:5: error: expected '}' before 'else' else ^~~~ goo1.c:63:14: warning: implicit declaration of function 'malloc' [-Wimplicit-function-declaration] if((new=malloc(sizeof(NODE)))=NULL) ^~~~~~ goo1.c:63:14: warning: incompatible implicit declaration of built-in function 'malloc' goo1.c:63:14: note: include '<stdlib.h>' or provide a declaration of 'malloc' goo1.c:2:1: +#include <stdlib.h> goo1.c:63:14: if((new=malloc(sizeof(NODE)))=NULL) ^~~~~~ goo1.c:63:35: error: lvalue required as left operand of assignment if((new=malloc(sizeof(NODE)))=NULL) ^ goo1.c:64:6: warning: implicit declaration of function 'error'; did you mean 'perror'? [-Wimplicit-function-declaration] error("out of memory!!"); ^~~~~ perror goo1.c: In function 'delete': goo1.c:79:9: error: 'key' redeclared as different kind of symbol int key; ^~~ goo1.c:77:16: note: previous definition of 'key' was here int delete(int key) ~~~~^~~ goo1.c:103:14: warning: implicit declaration of function 'deletemin'; did you mean 'delete'? [-Wimplicit-function-declaration] *p=deletemin(&x->right); ^~~~~~~~~ delete goo1.c:103:13: warning: assignment to 'NODE *' {aka 'struct node *'} from 'int' makes pointer from integer without a cast [-Wint-conversion] *p=deletemin(&x->right); ^ goo1.c:104:23: error: lvalue required as left operand of assignment &(*p)->right=x->right; ^ goo1.c:105:22: error: lvalue required as left operand of assignment &(*p)->left=x->left; ^ goo1.c:108:7: warning: implicit declaration of function 'free' [-Wimplicit-function-declaration] free(x); ^~~~ goo1.c:108:7: warning: incompatible implicit declaration of built-in function 'free' goo1.c:108:7: note: include '<stdlib.h>' or provide a declaration of 'free' goo1.c: At top level: goo1.c:125:7: error: conflicting types for 'deletemin' NODE *deletemin(NODE **p) ^~~~~~~~~ goo1.c:103:14: note: previous implicit declaration of 'deletemin' was here *p=deletemin(&x->right); ^~~~~~~~~ goo1.c:137:1: warning: return type defaults to 'int' [-Wimplicit-int] preorder(NODE *p) ^~~~~~~~ goo1.c: In function 'preorder': goo1.c:141:5: warning: 'return' with no value, in function returning non-void return; ^~~~~~ goo1.c:137:1: note: declared here preorder(NODE *p) ^~~~~~~~ goo1.c:150:1: warning: implicit declaration of function 'inorder'; did you mean 'preorder'? [-Wimplicit-function-declaration] inorder(NODE *p) ^~~~~~~ preorder goo1.c:150:9: error: expected expression before 'NODE' inorder(NODE *p) ^~~~ goo1.c:150:17: error: expected ';' before '{' token inorder(NODE *p) ^ ; { ~ goo1.c:230:1: error: expected declaration or statement at end of input }

投稿2020/12/01 09:19

tatsu99

総合スコア5493

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

kyapi

2020/12/02 00:48

ありがとうございます!!! paizaを使って一つずつ確認していこうと思います!
Zuishin

2020/12/02 08:25

オートインデントも補完もスペルチェックもステップ実行も使えない、いい加減な環境ではなく、まともなソースコードエディタを使いましょう。 何度も質問を編集されていますが、一向にインデントが直る気配がなく、それに起因するバグもたくさん入ったままです。 まともなエディタを使えば問題の大半が解決すると思います。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.36%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問