C++で連結リストを逆順に表示する面白い方法:キャリッジリターンを活用した1回走査のテクニック
連結リスト(リンクリスト)とは
連結リストは、データ要素をリンクの形でつなげて格納するデータ構造です。各ノードは「データ要素」と「次のノードへのリンク」を持っています。
連結リストを逆順に表示するという課題
連結リストを逆順に表示することは、アルゴリズムの問題解決において頻出のテーマのひとつです。本記事では、C++を使って連結リストを逆順に表示する、ちょっと変わった興味深い方法を紹介します。
一般的に、連結リストを逆順に表示するには、リストそのものを書き換えるか、複数回の走査(トラバース)を行う必要があります。しかし、今回紹介する方法ではそのような操作は一切不要で、リストの走査もたった1回で済みます。
仕組みの鍵は「キャリッジリターン」
この方法の核心は、キャリッジリターン(復帰文字)を利用して文字を逆順に表示するという発想です。キャリッジリターンとは、カーソル(プリンタの場合は印字位置)を同じ行の先頭に戻すための制御文字です。
具体的なロジックは次のとおりです。
- リストの長さを n とします。
- リストを先頭から順にたどりながら、各要素を表示する位置を確保するため、あらかじめカーソルをスペースで進めておきます。
- 1つ目の要素の前には n−1 個分、2つ目の要素の前には n−2 個分のスペースを用意し、以降も要素を表示するたびにスペースの数を減らしていきます(実装では、要素1つと区切りのスペース1つ分を考慮して 2×(n−j) 個のスペースを出力しています)。
- 各要素を出力した直後にキャリッジリターンを送るとカーソルが行の先頭に戻るため、次の要素はひとつ左の位置から上書きされていきます。
この結果、先頭ノードの値は行の最も右側に、末尾ノードの値は最も左側に配置され、行全体としては連結リストが逆順に表示されるという仕組みです。
サンプルプログラム
それでは、この概念を示すC++プログラムを見てみましょう。
#include<stdio.h>
#include<stdlib.h>
#include<iostream>
using namespace std;
struct Node {
int data;
struct Node* next;
};
void printReverse(struct Node** head_ref, int n) ;
void push(struct Node** head_ref, int new_data) ;
int printList(struct Node* head) ;
int main(){
struct Node* head = NULL;
push(&head, 2);
push(&head, 7);
push(&head, 3);
push(&head, 5);
push(&head, 4);
push(&head, 6);
printf("Given linked list:\n");
int n = printList(head);
printf("\nReversed Linked list:\n");
printReverse(&head, n);
return 0;
}
void printReverse(struct Node** head_ref, int n){
int j = 0;
struct Node* current = *head_ref;
while (current != NULL) {
for (int i = 0; i < 2 * (n - j); i++)
cout<<" ";
cout<<current->data<<"\r";
current = current->next;
j++;
}
}
void push(struct Node** head_ref, int new_data){
struct Node* new_node =
(struct Node*)malloc(sizeof(struct Node));
new_node->data = new_data;
new_node->next = (*head_ref);
(*head_ref) = new_node;
}
int printList(struct Node* head){
int i = 0;
struct Node* temp = head;
while (temp != NULL) {
printf("%d ", temp->data);
temp = temp->next;
i++;
}
return i;
}実行結果
Given linked list: 6 4 5 3 7 2 Reversed Linked list: 2 7 3 5 4 6
注意点
この手法は、ターミナルがキャリッジリターンを正しく解釈することを前提としています。出力をファイルにリダイレクトした場合など、実行環境によっては意図したとおりに表示されないことがあります。また、桁数の異なる数値が混在する場合は、スペース数の計算を調整する必要があります。
-
C++ STLのlist::reverse()関数の使い方と実例解説
本記事では、C++におけるlist::reverse()関数の動作、構文、具体的な使用例について詳しく解説します。STLにおけるlistとはlistは、シーケンス内の任意の位置で定数時間O(1)での要素の挿入・削除を可能にするデータ構造です。listは双方向連結リストとして実装されており、メモリの非連続的な割り当てが可能です。配列、vector、dequeと比較すると、コンテナ内の任意の位置への要素の挿入・抽出・移動において優れたパフォーマンスを発揮します。一方で、要素への直接アクセス(ランダムアクセス)は遅いという特徴があります。listはforward_listと似ていますが、forwar
-
【C++】再帰を使ってリンクリストの交互ノードを出力する方法
リンクリスト(連結リスト)とはリンクリストは、各要素(ノード)をメモリ上の連続しない領域に格納できる線形データ構造です。各ノードにはデータ本体と、次のノードを指すポインタが含まれており、ポインタをつなぐことで一連のリストとして扱うことができます。問題の概要今回は、与えられたリンクリストを走査し、交互(ひとつおき)のノードだけを出力するプログラムを作成します。具体的には、1番目・3番目・5番目…というように、奇数番目の要素のみを順に出力していきます。入出力例入力 : 2 -> 4 -> 1 -> 67 -> 48 -> 90 出力 : 2 -> 1 ->