質問をすることでしか得られない、回答やアドバイスがある。

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

新規登録して質問してみよう
ただいま回答率
85.49%
コマンド

コマンドとは特定のタスクを行う為に、コンピュータープログラムへ提示する指示文です。多くの場合、コマンドはShellやcmdようなコマンドラインインターフェイスに対する指示文を指します。

データ構造

データ構造とは、データの集まりをコンピュータの中で効果的に扱うために、一定の形式に系統立てて格納する形式を指します。(配列/連想配列/木構造など)

関数

関数(ファンクション・メソッド・サブルーチンとも呼ばれる)は、はプログラムのコードの一部であり、ある特定のタスクを処理するように設計されたものです。

C++

C++はC言語をもとにしてつくられた最もよく使われるマルチパラダイムプログラミング言語の1つです。オブジェクト指向、ジェネリック、命令型など広く対応しており、多目的に使用されています。

Q&A

解決済

1回答

2655閲覧

木構造編集プログラムのノードの削除機能について

退会済みユーザー

退会済みユーザー

総合スコア0

コマンド

コマンドとは特定のタスクを行う為に、コンピュータープログラムへ提示する指示文です。多くの場合、コマンドはShellやcmdようなコマンドラインインターフェイスに対する指示文を指します。

データ構造

データ構造とは、データの集まりをコンピュータの中で効果的に扱うために、一定の形式に系統立てて格納する形式を指します。(配列/連想配列/木構造など)

関数

関数(ファンクション・メソッド・サブルーチンとも呼ばれる)は、はプログラムのコードの一部であり、ある特定のタスクを処理するように設計されたものです。

C++

C++はC言語をもとにしてつくられた最もよく使われるマルチパラダイムプログラミング言語の1つです。オブジェクト指向、ジェネリック、命令型など広く対応しており、多目的に使用されています。

0グッド

0クリップ

投稿2019/11/06 13:16

木構造編集プログラムに、ノードの削除機能を追加しています.
コマンドは、以下の形式とします.
「 D n L|R 」: n番ノードの左(L)または右(R)の子ノードを削除する.
削除対象ノードが1つの子を持つときには、その子を削除ノードのあった位置に接続します.2つの子を持つときには削除しません.

以下が現在のコードです.

C++

1#include <iostream> 2#include <string> 3using namespace std; 4 5#define LINELENGTH 80 //一行の長さ 6#define END 'E' //終了 7#define ADD 'A' //追加 8#define CUT 'X' //切り取り 9#define LEFT 'L' //左 10#define RIGHT 'R' //右 11#define INSERT 'I' //挿入 12#define DELETE 'D' //削除 13 14class Node { //ノードを表すクラス 15public: 16 string word; //ノード格納単語 17 Node* pLeft; //左ノードを参照するポインタ 18 Node* pRight; //右ノードを参照するポインタ 19}; 20 21//プロトタイプ宣言 22void showTree(); 23void showTreeRecursive(Node* pNode, int nodeLevel); 24Node* searchNode(int searchNodeNo); 25Node* searchNodeRecursive(Node* pPresentNode, int searchNodeNo); 26void addNode(string word, int nodeNo, char direction); 27void cutNode(int nodeNo, char direction); 28void deleteNodeRecursive(Node* pNode); 29void showHelp(); 30void insertNode(string word, int nodeNo, char direction); 31void deleteNode(int nodeNo, char direction); 32 33Node* pRoot; //根ノードを参照するポインタ 34int nodeCounter; //ノードの番号付けカウンタ 35 36// 37//----メイン関数------- 38// 39void main() 40{ 41 char commandLine[LINELENGTH] = ""; //コマンド行(文字配列) 42 char command = ' '; //コマンド文字 43 char word[LINELENGTH] = ""; //単語(文字配列) 44 char direction = LEFT; //方向指示 45 int nodeNo; //ノード番号 46 47 //根ノードを生成して、その参照を根ノードポインタに入れる。 48 pRoot = new Node; 49 50 //根ノードの左右ポインタにNULLを、単語に"<"を入れる。 51 pRoot->pLeft = pRoot->pRight = NULL; 52 pRoot->word = "<"; 53 54 //現在の木構造を表示する。 55 showTree(); 56 57 //コマンド行を受け取り、その先頭のコマンド文字を取り出す。 58 cout << "> "; 59 cin.getline(commandLine, LINELENGTH); 60 sscanf_s(commandLine, "%c", &command, 1); 61 62 //コマンドが「プログラム終了」でない限り、以下の処理を繰り返す。 63 while (command != END) { 64 65 //コマンドが「追加」であれば、以下を実行する。 66 switch (command) { 67 case ADD: 68 69 //コマンド行から、コマンド、単語、ノード番号、方向指示を取り出せれば、追加を実行する。 70 if (sscanf_s(commandLine, "%c %s %d %c", &command, 1, word, LINELENGTH, &nodeNo, &direction, 1) == 4) { 71 addNode(word, nodeNo, direction); 72 } 73 break; 74 75 //コマンドが「切り取り」であれば、以下を実行する。 76 case CUT: 77 78 //コマンド行から、コマンド、ノード番号、方向指示を取り出せたら、切り取りを実行する。 79 if (sscanf_s(commandLine, "%c %d %c", &command, 1, &nodeNo, &direction, 1) == 3) { 80 cutNode(nodeNo, direction); 81 } 82 break; 83 84 //コマンドが「挿入」であれば、以下を実行する。 85 case INSERT: 86 87 //コマンド行から、コマンド、単語、ノード番号、方向指示を取り出せれば、挿入を実行する。 88 if (sscanf_s(commandLine, "%c %s %d %c", &command, 1, word, LINELENGTH, &nodeNo, &direction, 1) == 4) { 89 insertNode(word, nodeNo, direction); 90 } 91 break; 92 93 //コマンドが「削除」であれば、以下を実行する。 94 case DELETE: 95 96 //コマンド行から、コマンド、ノード番号、方向指示を取り出せれば、削除を実行する。 97 if (sscanf_s(commandLine, "%c %d %c", &command, 1, &nodeNo, &direction, 1) == 3) { 98 cutNode(nodeNo, direction); 99 } 100 break; 101 102 //コマンドがどれでもなければ、ヘルプ表示を行う。 103 default: 104 showHelp(); 105 } 106 107 //現在の木構造を表示する。 108 showTree(); 109 110 //コマンド行を受け取り、その先頭のコマンド文字を取り出す。 111 cout << "> "; 112 cin.getline(commandLine, LINELENGTH); 113 sscanf_s(commandLine, "%c", &command, 1); 114 } 115} 116 117// 118//----木構造を表示する。----- 119// 120void showTree() 121{ 122 int nodeLevel; //ノードの根からの深さ 123 124 //ノードカウンタ(ノード番号を数える)をリセットする。 125 nodeCounter = 0; 126 127 //ノードレベル(根からの深さ)をリセットにする。 128 nodeLevel = 0; 129 130 //木の表示再帰を呼び出す。 131 showTreeRecursive(pRoot, nodeLevel); 132} 133 134// 135//----木構造の再帰表示を行う。---- 136// 137void showTreeRecursive(Node* pNode, int nodeLevel) 138{ 139 //ノードポインタがnullならば戻る。 140 if (pNode == NULL) return; 141 142 //ノードレベルをインクリメントする。 143 nodeLevel++; 144 145 //ノードポインタの指すノード(現ノード)の右ポインタについて木の再帰表示を行う。 146 showTreeRecursive(pNode->pRight, nodeLevel); 147 148 //ノードカウンタをインクリメントする。 149 nodeCounter++; 150 151 //ノードレベルに合ったインデンションを付け、ノードカウンタと現ノードの単語を表示する。 152 for (int i = 0; i < nodeLevel; i++) cout << "\t"; 153 cout << nodeCounter << ": " << pNode->word << endl; 154 155 //現ノードの左ポインタについて木の再帰表示を行う。 156 showTreeRecursive(pNode->pLeft, nodeLevel); 157} 158 159// 160//----指定番号のノードを探索する。----- 161// 162Node* searchNode(int searchNodeNo) 163{ 164 //ノードカウンタをリセットする。 165 nodeCounter = 0; 166 167 //ノードの再帰探索を行い、その戻り値を持って戻る。 168 return searchNodeRecursive(pRoot, searchNodeNo); 169} 170 171// 172//-----ノードの再帰探索を行う。------ 173// 174Node* searchNodeRecursive(Node* pPresentNode, int searchNodeNo) 175{ 176 Node* pFoundNode; //発見したノードへのポインタ 177 178 //ノードポインタがNULLならば、戻り値をNULLにして戻る。 179 if (pPresentNode == NULL) return NULL; 180 181 //ノードポインタが参照するノード(現ノード)の右ポインタについてノードの再帰探索を行う。 182 pFoundNode = searchNodeRecursive(pPresentNode->pRight, searchNodeNo); 183 184 //戻り値がNULLでなければ、その戻り値を持って戻る。 185 if (pFoundNode != NULL) return pFoundNode; 186 187 //ノードカウンタをインクリメントする。 188 nodeCounter++; 189 190 //ノードカウンタが探索ノード番号に等しければ、現ノードポインタを持って戻る。 191 if (searchNodeNo == nodeCounter) return pPresentNode; 192 193 //現ノードの左ポインタについてノードの再帰探索を行う。 194 pFoundNode = searchNodeRecursive(pPresentNode->pLeft, searchNodeNo); 195 196 //その戻り値を持って戻る。 197 return pFoundNode; 198} 199 200// 201//----ノードを追加する。----- 202// 203void addNode(string word, int nodeNo, char direction) 204{ 205 Node* pParentNode; //親ノードへのポインタ 206 Node* pChildNode; //子ノードへのポインタ 207 208 //ノード番号に対応する親ノードを探索してノードポインタを得る。 209 pParentNode = searchNode(nodeNo); 210 211 //ノードポインタがNULLであれば戻る(探索失敗)。 212 if (pParentNode == NULL) return; 213 214 //方向指示の先が空いていなければ戻る。 215 if (direction == LEFT && pParentNode->pLeft != NULL)return; 216 if (direction == RIGHT && pParentNode->pRight != NULL)return; 217 218 //新しく子ノードのメモリ領域を確保する。 219 pChildNode = new Node; 220 221 //子ノードの内容を設定する。 222 pChildNode->word = word; 223 pChildNode->pLeft = pChildNode->pRight = NULL; 224 225 //子ノードを親ノードの方向指示の先につなぐ。 226 if (direction == LEFT)pParentNode->pLeft = pChildNode; 227 if (direction == RIGHT)pParentNode->pRight = pChildNode; 228} 229 230// 231//----ノードを切り取る。----- 232// 233void cutNode(int nodeNo, char direction) 234{ 235 Node* pNode; //ノードへのポインタ 236 237 //ノード番号に対応するノードを探索してノードポインタを得る。 238 pNode = searchNode(nodeNo); 239 240 //ノードポインタがNULLならば戻る(探索失敗)。 241 if (pNode == NULL) return; 242 243 //方向指示が右であれば以下を実行する。 244 if (direction == RIGHT) { 245 246 //ノードの右ポインタについて再帰削除を行う。 247 deleteNodeRecursive(pNode->pRight); 248 249 //ノードの右ポインタをNULLにする。 250 pNode->pRight = NULL; 251 } 252 253 //方向指示が左であれば以下を実行する。 254 if (direction == LEFT) { 255 256 //ノードの左ポインタについて再帰削除を行う。 257 deleteNodeRecursive(pNode->pLeft); 258 259 //ノードの左ポインタをNULLにする。 260 pNode->pLeft = NULL; 261 } 262} 263 264// 265//-----ノードの再帰削除を行う。------ 266// 267void deleteNodeRecursive(Node* pNode) 268{ 269 //ノードポインタがNULLならば戻る。 270 if (pNode == NULL) return; 271 272 //ノードポインタの右ポインタについてノードの再帰削除を行う。 273 deleteNodeRecursive(pNode->pRight); 274 275 //ノードポインタの左ポインタについてノードの再帰削除を行う。 276 deleteNodeRecursive(pNode->pLeft); 277 278 //ノードポインタの参照するノードのメモリ領域を解放する。 279 delete pNode; 280} 281 282// 283//----ヘルプを表示する。------ 284// 285void showHelp() 286{ 287 //コマンド一覧を表示する。 288 cout << "A word n L|R = Add:wordをn番の左(L)または右(R)に追加" << endl; 289 cout << "X n L|R = Cut:n番の(L)または右(R)を切り取り" << endl; 290 cout << "E = End:プログラムを終了" << endl; 291} 292 293// 294//----ノードを挿入する。----- 295// 296void insertNode(string word, int nodeNo, char direction) { 297 298 Node* pNode; //ノードへのポインタ 299 300 //ノード番号に対応するノード(以下、現ノード)を探索して、現ノードへのポインタを得る。 301 pNode = searchNode(nodeNo); 302 303 //ポインタがNULLならば探索失敗なので戻る。 304 if (pNode == NULL) return; 305 306 //挿入する新規ノードのメモリ領域を確保する。 307 Node* pNewNode; //新規ノードへのポインタ 308 309 pNewNode = new Node(); 310 311 //新規ノードに単語を設定し、左右ポインタをNULLにする。 312 pNewNode->word = word; 313 pNewNode->pRight = NULL; 314 pNewNode->pLeft = NULL; 315 316 //方向指示が左ならば以下を実行する。 317 if (direction == LEFT) { 318 319 //新規ノードの左ポインタに、現ノードの左ポインタを入れる。 (新規ノードの左ポインタ「の変数領域」に、現ノードの左ポインタ「の値」を入れる。) 320 pNewNode->pLeft = pNode->pLeft; 321 322 //現ノードの左ポインタに、新規ノードへのポインタを入れる。 323 pNode->pLeft = pNewNode; 324 } 325 326 //方向指示が右ならば以下を実行する。 327 if (direction == RIGHT) { 328 329 //新規ノードの右ポインタに、現ノードの右ポインタを入れる。 330 pNewNode->pRight = pNode->pRight; 331 332 //現ノードの右ポインタに、新規ノードへのポインタを入れる。 333 pNode->pRight = pNewNode; 334 } 335} 336 337// 338//----ノードを削除する。----- 339// 340void deleteNode(int nodeNo, char direction) { 341 342 Node* pNode; //ノードへのポインタ 343 344 //ノード番号に対応するノード(現ノード)を探索してポインタを得る。 345 pNode = searchNode(nodeNo); 346 347 //ポインタがNULLならば探索失敗であるので戻る。 348 if (pNode == NULL) return; 349 350 //方向指示に対応する左右ポインタから、削除対象ノードへのポインタを得る。 351 Node* pDeleteNode=new Node; 352 if (direction == RIGHT) pDeleteNode = pNode->pRight; 353 if (direction == LEFT) pDeleteNode = pNode->pLeft; 354 355 //ポインタがNULLであれば削除対象ノードが無いので戻る。 356 if (pDeleteNode== NULL) return; 357 358 //削除対象ノードの下に子ノードが2つあれば削除できないので戻る。 359 if (pDeleteNode->pRight != NULL && pDeleteNode->pLeft != NULL)return; 360 361 //存在する子ノードへのポインタを得る(子ノードが無いならばNULL)。 362 Node* pChildNode=new Node; 363 if (direction == RIGHT)pChildNode= pDeleteNode->pRight; 364 if (direction == LEFT)pChildNode = pDeleteNode->pLeft; 365 if (pDeleteNode->pRight == NULL && pDeleteNode->pLeft == NULL) pChildNode = NULL; 366 367 //子ノードへのポインタを、方向指示に対応して現ノードの左右ポインタのどちらかに入れる。 368 if (direction == RIGHT)pNode->pRight = pDeleteNode->pRight; 369 if (direction == LEFT)pNode->pLeft = pDeleteNode->pLeft; 370 371 //削除対象ノードのメモリ領域を解放する。 372 delete pDeleteNode; 373}

このコードで実行すると,削除対象ノードは削除されるのですが,削除対象ノードの子が削除ノードのあった位置に接続されません.
正しく出力されるには,削除する関数のコードをどのように直したら良いでしょうか?
教えてください.よろしくお願いします.

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

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

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

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

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

guest

回答1

0

ベストアンサー

指定ノードの左右と、削除対象ノードの左右を混同しています。

C++

1void deleteNode(int nodeNo, char direction) { 2 3 Node* pNode; //ノードへのポインタ 4 5 //ノード番号に対応するノード(現ノード)を探索してポインタを得る。 6 pNode = searchNode(nodeNo); 7 8 //ポインタがNULLならば探索失敗であるので戻る。 9 if (pNode == NULL) return; 10 11 //方向指示に対応する左右ポインタから、削除対象ノードへのポインタを得る。 12 Node* pDeleteNode; 13 if (direction == RIGHT) pDeleteNode = pNode->pRight; 14 if (direction == LEFT) pDeleteNode = pNode->pLeft; 15 16 //ポインタがNULLであれば削除対象ノードが無いので戻る。 17 if (pDeleteNode== NULL) return; 18 19 //削除対象ノードの下に子ノードが2個あれば削除できないので戻る。 20 if (pDeleteNode->pRight != NULL && pDeleteNode->pLeft != NULL) return; 21 Node* pChildNode; // に、 22 //削除対象ノードの下に子ノードが0個ならばNULLをセット。 23 if (pDeleteNode->pRight == NULL && pDeleteNode->pLeft == NULL) pChildNode = NULL; 24 //それ以外のケースは削除対象ノードの下に子ノードが1個なのでそれをセット 25 else pChildNode = pDeleteNode->pRight ? pDeleteNode->pRight : pDeleteNode->pLeft; 26 //間違っていた → else pChildNode = pDeleteNode->pRight || pDeleteNode->pLeft; 27 28 //子ノードへのポインタを、方向指示に対応して現ノードの左右ポインタのどちらかに入れる。 29 if (direction == RIGHT) pNode->pRight = pChildNode; 30 if (direction == LEFT) pNode->pLeft = pChildNode; 31 32 //削除対象ノードのメモリ領域を解放する。 33 delete pDeleteNode; 34}

でしょうか。ifの後の単文はブレースで囲まない主義なようなので、それはそのままにしてあります。普通は単文でも複数文の時のように囲みます。

あと、直後で捨てるnew Nodeを2つ書いていますが、これはdeleteせずに捨てられるので、解放漏れになるのでは?

投稿2019/11/06 13:50

編集2019/11/06 14:48
otn

総合スコア84491

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

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

otn

2019/11/06 13:58

deleteNodeの部分だけしか見ていませんので、他の部分にもおかしいところがあるかもしれません。
otn

2019/11/06 14:46

ああ、失礼しました。C/C++だとこういう書き方はだめですね。 else pChildNode = pDeleteNode->pRight ? pDeleteNode->pRight : pDeleteNode->pLeft; でしょうか。冗長ですが。 回答を直しておきます。
退会済みユーザー

退会済みユーザー

2019/11/06 15:00

otnさんが書いてくださったコードで実行してみましたが,削除対象ノードの子が削除ノードのあった位置に接続されませんでした. また,Node* pDeleteNode;と書いたところ,「初期化されていないローカル変数 'pDeleteNode' が使用されています」という エラーが出ます. 削除対象ノードの子を削除ノードのあった位置に接続するには,他にどの部分を修正したらよいのか教えて頂けませんか? よろしくお願いします.
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.49%

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

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

質問する

関連した質問