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

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

詳細はこちら
アルゴリズム

アルゴリズムとは、定められた目的を達成するために、プログラムの理論的な動作を定義するものです。

ポインタ

ポインタはアドレスを用いてメモリに格納された値を"参照する"変数です。

関数

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

連結リスト

連結リストとは、データ構造のひとつであるリストの中で、要素が前後の要素の情報を持つことで、要素が連結(リンク)しているリストの事を呼びます。

C++

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

Q&A

解決済

1回答

887閲覧

整数を要素とする1次元1方向連結リスト構造の基本的操作

退会済みユーザー

退会済みユーザー

総合スコア0

アルゴリズム

アルゴリズムとは、定められた目的を達成するために、プログラムの理論的な動作を定義するものです。

ポインタ

ポインタはアドレスを用いてメモリに格納された値を"参照する"変数です。

関数

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

連結リスト

連結リストとは、データ構造のひとつであるリストの中で、要素が前後の要素の情報を持つことで、要素が連結(リンク)しているリストの事を呼びます。

C++

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

0グッド

0クリップ

投稿2019/11/04 03:44

編集2019/11/04 08:06

整数を要素とする1次元1方向連結リスト構造の基本的操作を行うプログラム作っています.ポインタと動的メモリの基本操作を学習するためにプログラムを作っているので,STLは使用しないこととします.
以下の操作命令を受け付け、対応する処理を行うことを繰り返します.
終了:プログラムを終了する。
挿入:連結リストの指定位置に整数値を挿入する。
削除:連結リストの指定位置から整数値を削除する。
探索:指定した整数値がリストの何番目の位置に含まれているか答える。
プッシュ:リストの先頭に整数値をプッシュする(先頭に挿入する)。
ポップ:リストの先頭から整数値をポップする(先頭から取り出し削除する)。
追加:リストの末尾に整数値を追加する。

・末尾ノードは有効な値を持たないダミーノードです.
・先頭と末尾のノードは、それぞれポインタ変数head、tailが参照しています.

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

C++

1#include <iostream> 2using namespace std; 3 4#define END 0 // 終了命令 5#define INSERT 1 // 挿入命令 6#define DELETE 2 // 削除命令 7#define SEARCH 3 // 探索命令 8#define PUSH 4 // プッシュ命令 9#define POP 5 // ポップ命令 10#define ADD 6 // 追加命令 11 12// プロトタイプ宣言 13void initList(void); // リストを初期化する 14void showList(void); // リストを表示する 15int getCommand(void); // 操作命令を受け取る 16void insertNode(int number, int value); // ノードを挿入する 17void deleteNode(int number); // ノードを削除する 18void searchNode(int value); // 値を探索する 19void pushNode(int value); // 値を先頭にプッシュする 20void popNode(void); // 値を先頭からポップする 21void addNode(int value); // ノードを末尾に追加する 22 23class Node { // リストノードの構造体定義 24public: 25 int value; // ノードの値 26 Node* next; // 次ノードを参照するポインタ 27}; 28 29Node* head = NULL; // リストの先頭ノードを参照するポインタ(先頭ポインタ) 30Node* tail = NULL; // リストの末尾ノードを参照するポインタ(末尾ポインタ) 31 32/********** 33メイン関数 34**********/ 35void main() { 36 37 int command; // 操作命令番号 38 int number; // ノード番号 39 int value; // ノード値 40 41 // リストを初期化する 42 initList(); 43 44 // リストを表示し操作命令を受け取る 45 showList(); 46 command = getCommand(); 47 48 // 操作命令が終了でない限り以下を繰り返す 49 while (command != END) { 50 51 // 命令によって分岐する 52 switch (command) { 53 54 // 操作命令が挿入であれば以下を実行する 55 case INSERT: 56 57 // 挿入する位置と値を受け取る 58 cout << "挿入位置のノードの番号(負/0は先頭、正はその番号ノードの後) = "; 59 cin >> number; 60 cout << "挿入する値(整数) = "; 61 cin >> value; 62 63 // リストに入力値を挿入する 64 insertNode(number, value); 65 break; 66 67 // 操作命令が削除であれば以下を実行する 68 case DELETE: 69 70 // 削除するノード番号を受け取る 71 cout << "削除するノードの番号 = "; 72 cin >> number; 73 74 // リストからノードを削除する 75 deleteNode(number); 76 break; 77 78 // 操作命令が探索であれば以下を実行する 79 case SEARCH: 80 81 // 探索する値を受け取る 82 cout << "探索する値 = "; 83 cin >> value; 84 85 // 値を探索して結果を表示する 86 searchNode(value); 87 break; 88 89 // 操作命令がプッシュであれば以下を実行する 90 case PUSH: 91 92 // プッシュする値を受け取る 93 cout << "プッシュする値 = "; 94 cin >> value; 95 96 // 先頭に値をプッシュする 97 pushNode(value); 98 break; 99 100 // 操作命令がポップであれば以下を実行する 101 case POP: 102 103 // 先頭から値をポップする 104 popNode(); 105 break; 106 107 // 操作命令が追加であれば以下を実行する 108 case ADD: 109 110 // 追加する値を受け取る 111 cout << "追加する値 = "; 112 cin >> value; 113 114 // 末尾に値を追加する 115 addNode(value); 116 break; 117 // それ以外はエラー表示する 118 default: 119 cout << "★番号が不正です" << endl << endl; 120 break; 121 122 } 123 124 // リストを表示し次の操作命令を受け取る 125 showList(); 126 command = getCommand(); 127 } 128} 129 130/***************************************************** 131リストを初期化する 132*****************************************************/ 133void initList(void) { 134 135 // ダミーノードを作成し、先頭ノードを参照するポインタhead(以下、先頭ポインタ)と 136 // 末尾ノードを参照するポインタtail(以下、末尾ポインタ)につなぐ 137 head = tail = new Node(); 138 139 // ダミーノードの内容を設定する 140 tail->value = 0; 141 tail->next = NULL; 142} 143 144/**************************************************** 145リストを表示する 146****************************************************/ 147void showList(void) { 148 149 // ヘッダーを表示する 150 cout << endl; 151 cout << "-----List-----" << endl; 152 cout << "No: \tValue" << endl; 153 cout << "--------------" << endl; 154 155 // 先頭ノードから始めて末尾ノードでない間、以下を繰り返す 156 Node* p = head; 157 int number = 1; 158 while (p != tail) { 159 160 // 現ノードの番号と値を表示する 161 cout << number << ": \t" << p->value << endl; 162 163 // 次のノードへ移動する 164 p = p->next; 165 number++; 166 } 167 168 // フッターを表示する 169 cout << "--------------" << endl << endl; 170} 171 172/**************************************************** 173リスト操作の命令を受け取る 174****************************************************/ 175int getCommand(void) { 176 177 int number; // 命令番号 178 179 // メニューを表示する 180 cout << "命令番号を入力してください" << endl; 181 cout << END << ": 終了" << endl; 182 cout << INSERT << ": 挿入" << endl; 183 cout << DELETE << ": 削除" << endl; 184 cout << SEARCH << ": 探索" << endl; 185 cout << PUSH << ": プッシュ" << endl; 186 cout << POP << ": ポップ" << endl; 187 cout << ADD << ": 追加" << endl; 188 189 // 命令番号を受け取る 190 cout << "命令番号 = "; 191 cin >> number; 192 193 // 命令番号を返す 194 return number; 195} 196 197/***************************************************** 198値valueを持つノードをnumber番目のノードの次に挿入する 199numberが負またはゼロの時は先頭の前に挿入する 200numberが末尾より先の時は末尾に挿入する 201*****************************************************/ 202void insertNode(int number, int value) { 203 204 // 新たなノード(新ノード)の領域を確保し、ポインタpNewにつなぐ 205 Node* pNew = new Node(); 206 207 // 新ノードに値を入れる 208 pNew->value = value; 209 210 // 指定ノード番号numberが負またはゼロの時、またはリストが空の時は、以下を実行する 211 if ((number <= 0) || head == tail) { 212 213 // 先頭ポインタheadが参照するノードの前に新ノードを挿入する 214 pNew->next = head; 215 head = pNew; 216 } 217 218 // それ以外の時は以下を実行する 219 else { 220 221 // 先頭からnumber-1ノード分先を探し現ノードとする 222 // (ポインタpの参照先を先頭ノードから開始して次ノードへnumber-1回移動する) 223 Node* p = head; 224 for (int i = 1; i < number; i++) { 225 226 // 次ノードが末尾のダミーノードならループを抜ける 227 if (p->next == tail) break; 228 229 // 次ノードを現ノードにする 230 p = p->next; 231 } 232 233 // ポインタpの参照するノード(現ノード)の次に新ノードを挿入する 234 pNew->next = p->next; 235 p->next = pNew; 236 } 237} 238 239/**************************************************** 240number番目のノードを削除する 241number番目のノードがない時は何もしない 242****************************************************/ 243void deleteNode(int number) { 244 245 // 番号が負またはゼロなら削除対象ノードがないので戻る 246 if (number <= 0) return; 247 248 // リストが空なら削除対象ノードがないので戻る 249 if (head == tail) return; 250 251 // 先頭から(number-1)ノード分先を探し、現ノードとする 252 // (ポインタpの参照先を先頭ノードから開始して次ノードへnumber-1回移動する) 253 Node* p = head; 254 for (int i = 1; i < number; i++) { 255 256 // 次ノードが末尾のダミーノードなら削除対象ノードがないので戻る 257 if (p->next == tail) return; 258 259 // 次ノードを現ノードとする 260 p = p->next; 261 } 262 263 /*********************************************** 264 以下に、ポインタpが参照するノード(現ノード)を削除するコードを追加する。 265 ただし、削除のためのリンク変更には直前ノードを参照するポインタが必要なので、 266 ここでは、次ノードの内容を現ノードにコピーして、次ノードを削除する方法を取る。 267 ***********************************************/ 268 269 // 次ノードを参照するポインタpNextを作る。 270 Node* pNext= new Node(); 271 272 // 次ノードの内容(valueとnext)を現ノードへコピーする。 273 p->value = pNext->value; 274 p->next = pNext->next; 275 276 // 次ノードが末尾のダミーノードならば、末尾ポインタが現ノードを参照するように設定する。 277 if (p->next == tail) { 278 tail = p; 279 } 280 281 // 次ノードを削除する。 282 delete pNext; 283} 284 285/**************************************************** 286値valueを持つノード番号を探索して表示する 287****************************************************/ 288void searchNode(int value) { 289 290 /***************************************** 291 以下に、引数で渡された値valueをリストから探すコードを追加する。 292 ポインタpの参照を先頭ノードから次々に移動しながら、引数値とノード値を 293 比較し、一致していればノード番号を表示することを、末尾(ダミーノード 294 直前)まで繰り返す。 295 *****************************************/ 296 297 // ノード番号nodeNoを1に設定する。 298 int nodeNo = 1; 299 300 // ポインタpが先頭ノードを参照するように設定する。 301 Node* p = head; 302 303 // ポインタpの参照先(現ノード)が末尾ノードでない間、以下を繰り返す。 304 while (p != tail) { 305 306 // 現ノードの値と引数の値が等しいならノード番号を表示する。 307 if (p->value == value) { 308 cout << nodeNo; 309 } 310 311 // 次ノードを現ノードとする。 312 p = p->next; 313 314 // ノード番号をインクリメントする。 315 nodeNo++; 316 } 317} 318 319/**************************************************** 320値valueをリストの先頭に入れる 321****************************************************/ 322void pushNode(int value) { 323 324 /*********************************************** 325 以下に、引数で渡された値valueをリストの先頭にプッシュするコードを追加する。 326 なお、insertNode()等の関数を呼び出すのではなく、ポインタ操作で行うこと。 327 ***********************************************/ 328 329 // 新ノードの領域を確保し、ポインタpNewにつなぐ 330 Node* pNew = new Node(); 331 332 // 新ノードに引数で渡された値valueを入れる。 333 pNew->value = value; 334 335 // 既存の先頭ノードを新ノードの後につなぎ、先頭ポインタheadに新ノードをつなぐ 336 pNew->next = head; 337 head = pNew; 338 339} 340 341 342/**************************************************** 343リストの先頭の値を削除して返す 344****************************************************/ 345void popNode(void) { 346 347 /********************************************** 348 以下に、ポップのコードを追加する。 349 なお、ここでポップとは、先頭の値を表示して削除することである。 350 deleteNode()等の関数を呼び出すのではなく、ポインタ操作で行うこと。 351 ***********************************************/ 352 353 // リストが空ならば(headとtailが同じノードを指していれば)、エラーを表示して戻る。 354 if(head==tail){ 355 cout << "★番号が不正です"; 356 return; 357 } 358 359 // それ以外は以下を実行する。 360 else { 361 362 // 先頭ノードの値を表示する 363 cout << head->value; 364 365 // 先頭ポインタheadを退避用のポインタ変数pSaveにコピーして、先頭ポインタheadを次ノードに移動する。 366 Node* pSave = head; 367 head->next = head; 368 369 // 待避したポインタpSaveが参照するノードを削除する。 370 delete pSave; 371 } 372} 373 374/***************************************************** 375値valueを持つノードをリストの末尾に追加する 376*****************************************************/ 377void addNode(int value) { 378 379 /************************************************ 380 以下に、引数で渡された値をリストの末尾に付け加えるコードを追加する。 381 既存のダミーノードに値を設定し、その次に新規のダミーノードを付加する方法を取る。 382 *************************************************/ 383 384 // 新ノードの領域を確保し、ポインタpNewにつなぐ(これが新規のダミーノードとなる)。 385 Node* pNew = new Node(); 386 387 // 既存のダミーノードに引数で渡された値valueを設定する。 388 tail->value = value; 389 390 // 既存のダミーノードの次に新ノードをつなぐ。 391 tail->next = pNew; 392 393 // ポインタpNewが参照する新ノードを末尾ポインタtailにつなぐ。 394 tail = pNew; 395 396 // 新ノードの次ノード参照ポインタはNULLとする。 397 pNew->next = NULL; 398}

このコードで実行すると,正しく出力されない点が2つあります
・削除:2 を入力すると,指定したノード番号の値が0になって,プログラムが終了してしまいます.指定したノードが削除され,再度,命令番号のメニューが表示されるには,現在のコードをどのように修正したらよいでしょうか?
・ポップ:5を入力すると,ノード番号1の値が-572662307となり他のノードがすべて消えて,プログラムが終了してしまいます.先頭のノードだけが削除され,再度,命令番号のメニューが表示されるには,現在のコードをどのように修正したらよいのでしょうか?
以上の2点を教えてください.よろしくお願いします.

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

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

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

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

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

fana

2019/11/04 04:34

「相互利用が可能な場合…」は意味的に同じことを数回書けば達成できるわけですから, (中身読んでませんが)仮にinsertNode()が妥当に動くコードなのであれば,少なくもと「プッシュ」と「追加」はそれをコピペしてくれば作れますよね.それすらやらないのは「わからない」じゃなく単に「自分でやりたくない」に見えてしまいます.
episteme

2019/11/04 06:55

> 整数を要素とする1次元1方向連結リスト構造の基本的操作を行うプログラム作っています. 目的は? > STLは使用しないこととします. なぜ?
退会済みユーザー

退会済みユーザー

2019/11/04 06:57

ポインタと動的メモリの基本操作を学習するためにプログラムを作っているので,STLは使用しません.
guest

回答1

0

ベストアンサー

削除

A→B→C→... というノードの並びからBを削除した場合に A→C→... となるようにA->Nextを更新してやれば良いです.
新しいノードをnewで作ったりする必要はないハズです.

ポップ

上記「削除」の削除対象が先頭である場合です.


  • このプログラムでは「リストの先頭のノードをheadが指し示す」ルールになっていますから,

先頭のノードを削除する場合には,新たに先頭となったノードを指すようにheadの値を更新せねばなりません.

  • tail側も同様です.
  • 要素数が1個しか無い状態で削除操作を行う場合はheadとtailの両方を更新する必要があります.

冷静に

text

1head tail 2 ↓ ↓ 3[A]→[B]→[C]→[D]

みたいな絵でも描いて,各処理後に{head,tail,各要素のnext}がそれぞれどうなっているべきなのかを考えれば良いかと思います.

投稿2019/11/04 08:19

編集2019/11/04 08:24
fana

総合スコア11990

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

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

退会済みユーザー

退会済みユーザー

2019/11/04 08:23

具体的にどのようにコードを修正すればよいでしょうか?教えてください。 よろしくお願いします。
fana

2019/11/04 08:27

記述を追記しました. この(A~Dの例で)ポップについて考えれば, 「headの指し示す先をB(すなわちA.next)に更新した後で,Aを削除」すれば良いことがわかるかと思います.
退会済みユーザー

退会済みユーザー

2019/11/04 09:04

次ノードの内容を現ノードにコピーして、次ノードを削除する方法を取るには,具体的にコードをどのように修正したらよいでしょうか?
fana

2019/11/04 09:26

> 次ノードの内容を現ノードにコピーして、次ノードを削除する これがちょっと何言ってるかわからないです. 「次ノード」と「現ノード」って具体的にどれのことですか? 例えばこのA~Dの例で言えばどれになるんですか?
fana

2019/11/04 09:39 編集

ああ,「2番目を削除しろ」言われた時にBを削除するんじゃなくて代わりにCを削除するって話ですか. あなたのdeleteNode()で言えば,「現ノード」とはpが指すノードであり,「次ノード」はp->nextが指すノードってことですか. Node *pDeleteTgt = p->next; //削除対象は「次ノード」 p->value = p->next->value; //「次ノード」の内容を「現ノード」にコピー p->next = p->next->next; //「次ノード」の内容を「現ノード」にコピー delete pDeleteTgt; //削除対象を削除 とかで良いんじゃないですか? ただし, ・「次のノード」が存在しないパターン ・「次のノード」がtailである場合はtailを更新 とかを考える必要があります.
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.36%

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

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

質問する

関連した質問