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

【C++】連結リスト内で指定した数Kで割り切れる最大要素と最小要素を求める方法

連結リストとは

連結リスト(リンクリスト)は、要素同士がポインタで連結された線形データ構造です。各要素(ノード)は「データ部分」と「次の要素を指すリンク(ポインタ)」を持ち、メモリ上の連続していない場所に配置されることもあります。

【C++】連結リスト内で指定した数Kで割り切れる最大要素と最小要素を求める方法

本記事では、データ部分と次ノードへのリンクを持つ片方向連結リストと、整数Kが与えられます。目的は、連結リスト内の要素のうち「Kで割り切れる」要素の最大値と最小値を見つけることです。線形連結リストは一方向にしか走査できないため、ヘッド(先頭)ノードから順に各ノードを訪問し、そのデータ部分がKで割り切れるかどうかを判定します。現在のノードの値が、それまでに見つかった最大値・最小値よりも適していれば、変数MaxD(最大値)・MinD(最小値)を更新していきます。

入力例1

SList : 5-->2-->10-->12-->3-->20-->7、K=5

出力例1

Kで割り切れる最大要素 : 20
Kで割り切れる最小要素 : 5

解説 − ヘッドノードから順に走査し、各ノードのデータをKで割って、余りが0(完全に割り切れる)かどうかを確認します。

この例では、5・10・20だけが5で割り切れ、そのうち最小は5、最大は20です。

入力例2

SList : 12-->2-->5-->18-->3-->144-->7、K=4

出力例2

Kで割り切れる最大要素 : 144
Kで割り切れる最小要素 : 12

解説 − 同様にヘッドノードから走査し、各ノードのデータがKで割り切れるか(余りが0か)を確認します。

この例では、12と144だけが4で割り切れ、そのうち最小は12、最大は144です。

プログラムのアプローチ

  • 連結リストのノードを作成します。ここでは、データ部(info)と次ノードへのポインタ(next)を持つクラスSLLnodeを定義しています。
  • 連結リスト本体を作成します。SLLnodeオブジェクトをメンバーに持つクラスSLListを定義し、SLListはSLLnodeによって構成されます。
  • 関数addtohead(int)は、リストの先頭に新しいノードを追加します。
  • SLListオブジェクトLISTに対してaddtohead(int)を呼び出すことで、リストへ要素を追加していきます。
  • リストの構築が完了したら、先頭ノードと整数Kを引数に取る関数Divisible(SLLnode*, int)を呼び出します。
  • Divisible関数内では、Kで割り切れる最大値・最小値を格納するための変数maxDとminDを用意します。
  • maxDは-1、minDは9999で初期化します。これは入力値がこの範囲内にあると想定した初期値です。
  • forループで、先頭ノードから連結リストを走査します。変数startが現在のノードを指します。
  • 各ノードのinfoとmaxD・minDを比較しながら、Kで割り切れるかどうかを判定します。現在のノードの値がKで割り切れ、かつminDより小さければ、minDを現在の値で更新します。
  • 現在のノードの値がKで割り切れ、かつmaxDより大きければ、maxDを現在の値で更新します。
  • 最後に、minDとmaxDに求まった結果を出力します。

なお、リスト内にKで割り切れる要素がひとつも存在しない場合は、maxD=-1・minD=9999のままとなるため、実用上は「該当する要素なし」の判定処理を追加しておくとより安全です。

サンプルコード

以下は、上記のアルゴリズムをC++で実装した例です。最新の標準C++環境でそのままコンパイルできるよう、ヘッダや入出力の記述を現代的なスタイルに整理しています。

#include <iostream>
using namespace std;

// 連結リストのノード
class SLLnode {
public:
    int info;          // データ部分
    SLLnode *next;     // 次ノードへのポインタ
    SLLnode(int el, SLLnode *ptr = 0) {
        info = el;
        next = ptr;
    }
};

// 連結リスト本体
class SLList {
public:
    SLLnode *head;
    SLList() { head = 0; }
    void addtohead(int);
};

// 先頭にノードを追加
void SLList::addtohead(int el) {
    head = new SLLnode(el, head);
}

// Kで割り切れる最大値・最小値を求める
void Divisible(SLLnode* head, int K) {
    int minD = 9999;
    int maxD = -1;
    SLLnode* start = head;
    for (; start != NULL; start = start->next) {
        if ((start->info < minD) && (start->info % K == 0))
            minD = start->info;
        if ((start->info > maxD) && (start->info % K == 0))
            maxD = start->info;
    }
    cout << "Kで割り切れる最大要素: " << maxD << endl;
    cout << "Kで割り切れる最小要素: " << minD << endl;
}

// ドライバーコード
int main() {
    // 空のリストから開始
    SLList LIST;
    LIST.addtohead(50);
    LIST.addtohead(21);
    LIST.addtohead(32);
    LIST.addtohead(45);
    LIST.addtohead(11);
    LIST.addtohead(23);
    LIST.addtohead(90);
    LIST.addtohead(56);

    int K = 5;
    Divisible(LIST.head, K);
    return 0;
}

出力結果

上記のコードを実行すると、以下の出力が得られます −

Kで割り切れる最大要素: 90
Kで割り切れる最小要素: 45

addtoheadは常に先頭へ挿入するため、リストの実際の並びは 56→90→23→11→45→32→21→50 となります。このうち5で割り切れるのは90・45・50であり、最大値は90、最小値は45です。計算量はリストを一度走査するだけなので、要素数をNとするとO(N)で効率的に求められます。

  1. C++で循環片方向リンクリストから最小値と最大値を求める方法

    本記事では、C++を使って循環片方向リンクリスト(単一循環リンクリスト)から最小値と最大値を検索する方法を解説します。 循環リンクリストの基本構造 循環リンクリストは、最後のノードのnextポインタが先頭ノードを指すデータ構造です。これにより、リスト全体がリング状につながります。また、startポインタによって先頭ノードの位置も管理されます。 新しい要素を挿入するときは、末尾ノードのnextに新ノードをつなぎ、新ノードのnextにstartノードのアドレスを設定します。これで循環構造が維持されます。 最小値・最大値を求めるアルゴリズム 考え方はとてもシンプルです。手順は以下の通りです。 変数

  2. C++で連結リスト内の最小値・最大値の素数を求める方法

    問題文n個の正の整数からなる連結リストが与えられます。このリストの中から、値が最小の素数と最大の素数を見つける必要があります。例えば、次のようなリストが与えられた場合 −10 -> 4 -> 1 -> 12 -> 13 -> 7 -> 6 -> 2 -> 27 -> 33この場合、最小の素数は 2、最大の素数は 13 となりますアルゴリズム1. 与えられた数の中から最大値を求める(これを maxNumber と呼ぶ)2. 1 から maxNumber までの素数を生成し、動的配列に格納する3. 連結リストを走査し、動的配列を参照して最小値・