C++で単方向リンクリストをXORリンクリストに変換する方法
はじめに
このチュートリアルでは、単方向リンクリスト(片方向連結リスト)をXORリンクリストに変換するプログラムについて解説します。
単方向リンクリストが与えられたとき、その要素を保持したまま、各ノードのnextポインタを「前のノードのアドレスと次のノードのアドレスのXOR値」に書き換えることで、XORリンクリストへと変換するのが目的です。
XORリンクリストとは
XORリンクリストは、通常の双方向リンクリストで必要となるprevポインタとnextポインタを1つのポインタにまとめた、メモリ効率に優れたデータ構造です。各ノードには「前のノードのアドレス XOR 次のノードのアドレス」のみを格納し、走査時には直前に訪れたノードのアドレスを利用して次のノードのアドレスを復元します。
アルゴリズムの流れ
- 現在のノード(curr)と前のノード(prev)を用意し、curr->nextから次のノード(next)を取得します。
- curr->nextをXOR(prev, next)の結果で上書きします。
- prev = curr、curr = next として更新し、リストの末尾まで繰り返します。
C++での実装例
#include <bits/stdc++.h>
using namespace std;
// リンクリストのノード構造体
struct Node {
int data;
struct Node* next;
};
// 新しいノードの作成
Node* newNode(int data){
Node* temp = new Node;
temp->data = data;
temp->next = NULL;
return temp;
}
// 単方向リンクリストの出力
void print(Node* head){
while (head) {
cout << head->data << " ";
head = head->next;
}
cout << endl;
}
// XOR値の計算
Node* XOR(Node* a, Node* b){
return (Node*)((uintptr_t)(a) ^ (uintptr_t)(b));
}
// 単方向リンクリストの変換
void convert(Node* head){
Node* curr = head;
Node* prev = NULL;
Node* next = curr->next;
while (curr) {
next = curr->next;
curr->next = XOR(prev, next);
prev = curr;
curr = next;
}
}
// XORリンクリストの出力
void printXOR(Node* head){
Node* curr = head;
Node* prev = NULL;
while (curr) {
cout << curr->data << " ";
Node* temp = curr;
curr = XOR(prev, curr->next);
prev = temp;
}
cout << endl;
}
int main(){
Node* head = newNode(1);
head->next = newNode(2);
head->next->next = newNode(3);
head->next->next->next = newNode(4);
cout << "Before Conversion : " << endl;
print(head);
convert(head);
cout << "After Conversion : " << endl;
printXOR(head);
return 0;
}出力結果
Before Conversion : 1 2 3 4 After Conversion : 1 2 3 4
コードのポイント
XOR関数では、ポインタをuintptr_t型にキャストしてからXOR演算を行い、その結果を再びNode*型にキャストして返しています。これにより、アドレス同士を安全にビット演算できます。
printXOR関数では、直前に参照したノードのアドレス(prev)と各ノードに格納されたXOR値を組み合わせることで、次のノードのアドレスを順に復元しながら走査しています。出力結果から、変換後もデータが同じ順序(1 2 3 4)で保持されていることが確認できます。
-
C++で二分木を単一リンクリストに変換するプログラム
二分木が与えられたとき、それをその場(in-place)で単一リンクリストに変換することを考えます。ここでの「その場」とは、追加のノードを生成せず、既存のノードのポインタを付け替えるだけで変換を行うことを意味します。例えば、次のような二分木が入力として与えられた場合:出力は以下のように、すべてのノードが右側のポインタだけで連結されたリンクリストになります:解法のアプローチこの問題を解くために、以下の手順に従います。ポインタ prev を null で初期化します。これは「直前に処理したノード」を保持するためのものです。ルートを引数にとる再帰関数 solve() を定義します。ルートが null
-
C++で単一リンクリスト内のすべての素数ノードの積を求める方法
単一リンクリストが与えられたとき、値が素数になっているノードをすべて見つけ出し、それらの値の積を計算して出力するのが本稿のテーマです。ここで「素数ノード」とは、データ部分に素数を格納しているノードを指します。 入力例 85 → 6 → 7 → 2 → 10 出力例 14 説明 リストを先頭から順に調べると、85 は 5×17 に分解できるため素数ではなく除外されます。6 も 2×3 であり除外、続く 7 は素数なので採用、2 も素数なので採用、最後の 10 は 2×5 であるため除外されます。したがって積は 7 × 2 = 14 となります。 解決のた