Cプログラミング
 Computer >> コンピューター >  >> プログラミング >> Cプログラミング

連結リストで表された2つの数値を加算する方法をC++で解説

この記事では、別々の連結リスト(リンクリスト)に格納された2つの数値を加算する方法について解説します。連結リストでは、数値の各桁が1つのノードとして格納されます。例えば、512という数値は以下のように表現されます。

512 = (5)-->(1)-->(2)-->NULL

このような形式の2つのリストが与えられたとき、それらを足し合わせて合計を求めるのが課題となります。ここでは、C++のSTLに含まれるstd::list(双方向連結リスト)を使用します。まず、処理の流れをつかむためにアルゴリズムから見ていきましょう。

アルゴリズム

addListNumbers(l1, l2)

Begin
    短い方のリストの先頭に0を追加し、l1とl2の桁数を揃える
    carry(繰り上がり) := 0
    res := 空のリスト
    l1の各ノードに対して以下を繰り返す
        item := (l1.item + l2.item + carry) mod 10
        res の先頭に item を挿入する
        carry := (l1.item + l2.item + carry) / 10
    繰り返し終了
    もし carry が 0 でなければ
        res の先頭に carry を追加する
    end if
    return res
End

C++による実装例

#include<iostream>
#include<list>
using namespace std;

// 桁数の少ない方の先頭に0を追加し、両リストの長さを揃える
list<int> addListNumbers(list<int> l1, list<int> l2){
    if(l1.size() > l2.size()){
        for(int i = l2.size(); i != l1.size(); i++){
            l2.push_front(0);
        }
    }else if(l1.size() < l2.size()){
        for(int i = l1.size(); i != l2.size(); i++){
            l1.push_front(0);
        }
    }
    list<int>::reverse_iterator it1 = l1.rbegin();
    list<int>::reverse_iterator it2 = l2.rbegin();
    list<int> result;
    int carry = 0;
    while(it1 != l1.rend()){
        result.push_front((*it1 + *it2 + carry) % 10);
        carry = (*it1 + *it2 + carry) / 10;
        it1++; it2++;
    }
    if(carry != 0){
        result.push_front(carry);
    }
    return result;
}

// 整数を各桁の連結リストに変換する
list<int> numToList(int n){
    list<int> numList;
    while(n != 0){
        numList.push_front(n % 10);
        n /= 10;
    }
    return numList;
}

// 連結リスト形式の数値を表示する
void displayListNum(list<int> numList){
    for(list<int>::iterator it = numList.begin(); it != numList.end();
    it++){
        cout<<*it;
    }
    cout << endl;
}

int main() {
    int n1 = 512;
    int n2 = 14578;
    list<int> n1_list = numToList(n1);
    list<int> n2_list = numToList(n2);
    list<int> res = addListNumbers(n1_list, n2_list);
    cout << "First number: "; displayListNum(n1_list);
    cout << "Second number: "; displayListNum(n2_list);
    cout << "Result: "; displayListNum(res);
}

実行結果

First number: 512
Second number: 14578
Result: 15090

アルゴリズムのポイント

この実装の重要なポイントを整理すると、以下の4点になります。

  • 桁数の調整: 加算を単純化するため、短い方のリストの先頭に0を追加して両者の桁数を揃えます。
  • 逆イテレータの活用: rbegin()rend()を使ってリストを後ろから走査することで、一の位から順に加算できます。
  • 繰り上がり処理: 各桁の合計が10以上になった場合は、商をcarryに記録し、次の桁の計算に反映させます。
  • 最終的な繰り上がり: すべての桁を処理した後もcarryが残っている場合は、結果の先頭に追加します。

計算量はO(max(m, n))です。ここでmとnはそれぞれのリストの長さを表します。筆算と同じ考え方をデータ構造上で実現するシンプルな手法なので、連結リストの操作に慣れる練習問題としても最適です。

  1. Pythonで連結リストを使って2つの多項式を加算するプログラムの作り方

    問題の概要 この記事では、連結リストで表現された2つの多項式を加算するPythonプログラムを紹介します。 2つの多項式が与えられ、それらの和を求めることを考えます。多項式は連結リストとして表現し、多項式の各項は連結リストの1つのノードに対応させます。各ノードには「係数」「次数(べき指数)」、そして「次のノードへの参照(ポインタ)」を持たせます。最終的なゴールは、2つの多項式の和を表す新しい連結リストを返すことです。 たとえば、入力が以下の画像のような2つの多項式だった場合を見てみましょう。 1x^1 + 1x^2 = 0 と 2x^1 + 3x^0 = 0 この場合、出力は次のようになりま

  2. Pythonで2つの数値を加算するプログラム:ビット演算による実装方法

    この記事では、2つの数値を加算するという問題に対する解法とアプローチについて詳しく解説します。 問題の概要 2つの大きな数値が与えられ、それらを加算した結果を出力することが求められます。 最も単純なアプローチは、オペランド同士を「+」演算子で結ぶ方法です。また、2つの数値をリストなどのイテラブルに格納し、Python標準ライブラリに用意されている組み込み関数 sum() を利用する方法もあります。 しかし、これらのアプローチでは10進数に対して直接演算を行うため、計算コストが増大するという課題があります。 ビット演算を用いた別のアプローチ そこで次に、数値をビット単位で操作する別のアプローチを