木構造編集プログラムに、ノードの削除機能を追加しています.
コマンドは、以下の形式とします.
「 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}
このコードで実行すると,削除対象ノードは削除されるのですが,削除対象ノードの子が削除ノードのあった位置に接続されません.
正しく出力されるには,削除する関数のコードをどのように直したら良いでしょうか?
教えてください.よろしくお願いします.
回答1件
あなたの回答
tips
プレビュー