連結リストでランレングス符号化(RLE)を実装するC++プログラム
はじめに
本記事では、連結リスト(Linked List)を用いてランレングス符号化(Run Length Encoding:RLE)を実装するC++プログラムについて解説します。
連結リストが与えられたとき、その各要素をランレングス符号化の手法で変換することが課題となります。
例えば、連結リストの要素が「a → a → a → a → a」と並んでいる場合、ランレングス符号化ではこれが「a → 5」に置き換えられます。これは、同じ値が連続して現れる区間を「値 + 連続回数」の組み合わせで表現することで、データ量を削減できるシンプルかつ効果的な圧縮手法です。
アルゴリズムの流れ
- 連結リストを先頭から順に走査し、現在のノードと次のノードのデータを比較します。
- 同じ値が連続している間は、カウントを1ずつ増やしていきます。
- 異なる値が現れた時点で、それまでの「文字」と「連続回数」を結果のリストに追加します。
- 連続回数が2桁になった場合は、十の位と一の位に分けて個別のノードとして追加します。
- リストの終端まで到達したら、最後の文字とその連続回数を忘れずに追加します。
C++による実装例
#include <bits/stdc++.h>
using namespace std;
//連結リストのノード構造体
struct Node {
char data;
struct Node* next;
};
//新しいノードを作成
Node* newNode(char data){
Node* temp = new Node;
temp->data = data;
temp->next = NULL;
return temp;
}
//リストにノードを追加
void add_node(struct Node* head_ref, char new_data){
struct Node* new_node = newNode(new_data);
struct Node* last = head_ref;
if (head_ref == NULL) {
head_ref = new_node;
return;
}
while (last->next != NULL)
last = last->next;
last->next = new_node;
return;
}
//連結リストの内容を出力
void print_llist(Node* node){
while (node != NULL) {
cout << node->data << " ";
node = node->next;
}
}
//与えられたリストを符号化
void llist_encode(Node* head){
Node* p = head;
Node* temp = newNode(p->data);
char c = p->data;
p = p->next;
int count = 1;
while (p != NULL) {
char x = p->data;
if (c == x)
count++;
else {
if (count > 1) {
if (count > 9)
add_node(temp, '0' + (count / 10));
add_node(temp, '0' + (count % 10));
}
count = 1;
add_node(temp, x);
c = x;
}
p = p->next;
}
if (count != 0)
add_node(temp, '0' + count);
print_llist(temp);
}
int main(){
Node* head = newNode('a');
head->next = newNode('a');
head->next->next = newNode('b');
head->next->next->next = newNode('b');
head->next->next->next->next = newNode('r');
head->next->next->next->next->next = newNode('r');
llist_encode(head);
return 0;
}
出力
a 2 b 2 r 2
コードの解説
- newNode():新しいノードを生成し、データと次ノードへのポインタを初期化する関数です。
- add_node():リストの末尾に新しいノードを追加する関数です。
- print_llist():連結リストの全要素を先頭から順番に出力する関数です。
- llist_encode():符号化処理の中核となる関数です。リストを走査しながら連続する同一文字の数を数え、「文字 + 回数」の形式で結果のリストを構築します。
まとめ
このように、連結リストを一度走査するだけでランレングス符号化を実現できます。計算量はリストの長さをNとするとO(N)となり、非常に効率的です。ランレングス符号化はデータ圧縮の基礎となる手法であり、画像フォーマットなど幅広い分野で実際に応用されています。ぜひ本記事のコードを参考に、ご自身でも動作を確認してみてください。
-
C++プログラム:再帰呼び出しを使って文字列の長さを求める方法
文字列が与えられたとき、その長さを求めるのが本記事のテーマです。文字列の長さは、ユーザー定義関数または組み込み関数を使って計算できます。 文字列の長さを求める方法は、主に以下の2通りがあります。 ユーザー定義関数を使う方法 − 文字列の先頭から末尾まで走査し、終端文字「\0」が見つかるまで、再帰呼び出しを行いながらカウントを1ずつ増やしていきます。 組み込み関数を使う方法 − ヘッダーファイル「<cstring>」(C言語では「string.h」)に定義されているstrlen()関数を利用します。この関数は文字列へのポインタを引数として1つ受け取り、文字列の長さを整数値(siz
-
C++の連結リストを使って2つの多項式を加算する方法
この概念をより深く理解するために、まず必要な基本事項をおさらいしましょう。連結リスト(Linked List)とは連結リストは、各要素を「ノード」と呼ばれるオブジェクトとして格納するデータ構造です。各ノードは、データ部分と次のノードへのリンクの2つの要素で構成されています。多項式(Polynomial)とは多項式とは、変数と係数から構成される数学的な式のことです。例えば、x2 − 4x + 7 のようなものが該当します。多項式を表す連結リスト多項式連結リストでは、多項式の係数と指数がリストのデータノードとして定義されます。連結リストとして格納された2つの多項式を加算するには、同じ次数(べき乗)