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

C++のstd::list(リスト)徹底解説:双方向リンクリストの特徴と主要メンバ関数一覧

C++のlist(リスト)とは

listは、データを順次格納するコンテナの一種で、要素に対して連続しない(非連続)メモリ領域を割り当てる点が大きな特徴です。C++におけるlistは双方向リンクリスト(doubly linked list)として実装されており、先頭と末尾の両端から要素の挿入・削除が可能です。そのため、リストを前後どちらの方向からでも走査できます。

なお、単方向リンクリストを使用したい場合は、C++ STLで提供されている forward_list を利用します。

listをvectorの代わりに使うメリット

イテレータが正しい位置に差し掛かっていれば、listコンテナへの要素の挿入・削除はvectorよりも高速に行えます。これは、要素の移動や再配置が不要だからです。

listを使うデメリット

listでは、位置を指定して要素へ直接アクセスすることが困難です。例えば4番目の要素を取得したい場合、4番目の要素へ直接ジャンプすることはできず、イテレータを先頭または末尾から順に進めて目的の位置まで到達する必要があります。

listの主なメンバ関数一覧

要素の追加・挿入

  • push_front(element):リストの先頭に要素を挿入します。
    構文:listName.push_front(要素)
    引数:挿入する値を1つ指定します。
    戻り値:なし。
  • push_back(element):リストの末尾に要素を挿入します。
    構文:listName.push_back(要素)
    引数:挿入する値を1つ指定します。
    戻り値:なし。
  • insert():指定した位置に要素を挿入します。
    構文:listName.insert(position, total, element)
    引数は3つあります。
    • position:要素を挿入する位置
    • total:挿入する要素の総数
    • element:挿入する要素
    戻り値:新しく挿入された要素の先頭を指すイテレータ。
  • emplace(position, value):指定した位置に新しい要素を直接構築して挿入します。
    構文:listName.emplace(position, value)
    引数:挿入位置と、挿入する要素の値の2つを指定します。
    戻り値:新しく挿入された要素を指すイテレータ。
  • emplace_front(element):リストの先頭に新しい要素を直接構築して挿入します。
    構文:listName.emplace_front(要素)
    引数:挿入する値を1つ指定します。
    戻り値:なし。
  • emplace_back(element):リストの末尾に新しい要素を直接構築して挿入します。
    構文:listName.emplace_back(要素)
    引数:挿入する値を1つ指定します。
    戻り値:なし。

要素の削除

  • pop_front():リストの先頭から要素を削除します。
    構文:listName.pop_front()
    引数:なし。
    戻り値:なし。
  • pop_back():リストの末尾から要素を削除します。
    構文:listName.pop_back()
    引数:なし。
    戻り値:なし。
  • clear():リストからすべての要素を削除し、サイズを0にリセットします。
    構文:listName.clear()
    引数:なし。
    戻り値:なし。
  • remove(element):引数で渡した要素と一致するすべての要素を削除します。
    構文:listName.remove(要素)
    引数:リストコンテナから削除する要素を1つ指定します。
    戻り値:なし。
  • remove_if(関数ポインタ/関数オブジェクト):引数で渡した条件に基づいて、条件に一致するすべての要素を削除します。
    構文:listName.remove_if(関数ポインタ/関数オブジェクト)
    引数:関数ポインタまたは関数オブジェクトを1つ指定します。
    戻り値:すべての要素が削除されるとtrueを返します。
  • erase():引数に応じて、単一の要素または複数の要素を消去します。
    構文:iterator listName.erase(iterator position)iterator listName.erase(iterator first_ele, iterator last_ele)
    引数:1つ目の構文では、削除する要素の位置(position)を指定します。2つ目の構文では、削除範囲の先頭要素と末尾要素を指定します。
    戻り値:最後に削除した要素の次を指すイテレータ。
  • unique():連続する重複要素をすべて削除します。
    構文:listName.unique(2つの値を同一とみなす述語)
    引数:省略可能な述語を指定します。2つの要素を同一とみなす場合にtrueを返します。
    戻り値:なし。

要素へのアクセス・情報取得

  • front():リストの先頭要素を取得します。
    構文:listName.front()
    引数:なし。
    戻り値:先頭要素への直接参照。
  • back():リストの末尾要素を取得します。
    構文:listName.back()
    引数:なし。
    戻り値:末尾要素への直接参照。
  • size():リスト内の要素の総数を取得します。
    構文:listName.size()
    引数:なし。
    戻り値:リスト内の要素の総数。
  • max_size():リストが保持できる最大要素数を取得します。
    構文:listName.max_size()
    引数:なし。
    戻り値:リストが保持できる最大要素数。
  • empty():リストが空かどうかを判定します。
    構文:listName.empty()
    引数:なし。
    戻り値:
    • true:リストが空の場合
    • false:リストが空でない場合

サイズ変更

  • resize():リストの要素数を変更します。
    構文:listName.resize(int resized_number, value(省略可))
    引数は2つあります。
    • resized_number:コンテナのサイズを増減させる正確な数
    • value(省略可):指定した場合、その値を要素の末尾に追加します
    戻り値:なし。

イテレータ関連

  • begin():リストの最初の要素を指すイテレータを返します。
    構文:listName.begin()
    引数:なし。
    戻り値:最初の要素を指すイテレータ。
  • end():リストの終端(最後の要素の次)を指すイテレータを返します。
    構文:listName.end()
    引数:なし。
    戻り値:終端を指すイテレータ。
  • rbegin():リストの最後の要素を指す逆イテレータを返します。
    構文:listName.rbegin()
    引数:なし。
    戻り値:末尾の要素を指す逆イテレータ。
  • rend():リストの先頭より前の位置を指す逆イテレータを返します。
    構文:listName.rend()
    引数:なし。
    戻り値:先頭位置を指す逆イテレータ。
  • cbegin():リストの先頭を指す定数イテレータを返します。
    構文:listName.cbegin()
    引数:なし。
    戻り値:先頭を指す定数イテレータ。
  • cend():リストの終端を指す定数イテレータを返します。
    構文:listName.cend()
    引数:なし。
    戻り値:終端を指す定数イテレータ。
  • crbegin():リストの末尾を指す定数逆イテレータを返します。
    構文:listName.crbegin()
    引数:なし。
    戻り値:末尾を指す定数逆イテレータ。
  • crend():リストの先頭より前の位置を指す定数逆イテレータを返します。
    構文:listName.crend()
    引数:なし。
    戻り値:先頭位置を指す定数逆イテレータ。

その他の操作

  • reverse():リスト内の全要素の並びを反転させます。
    構文:listName.reverse()
    引数:なし。
    戻り値:なし。
  • operator(=):あるリストの内容を別のリストの内容で置き換えます。
    構文:listName_1 = listName_2
    引数:なし。
    戻り値:なし。
  • swap():同じ型の別のリストと内容を入れ替えます。
    構文:listName_1.swap(listName_2)
    引数:なし。
    戻り値:なし。
  • merge():2つのリストの要素をマージ(併合)します。
    構文:listName_1.merge(listName_2)
    引数:なし。
    戻り値:なし。

まとめ

C++のlistは双方向リンクリストとして実装されており、両端からの高速な挿入・削除が強みです。一方でランダムアクセスが苦手というトレードオフがあるため、用途に応じてvectorやdequeとの使い分けが重要です。本記事で紹介した各メンバ関数を活用すれば、listを効率的に操作できるようになります。

  1. C++でリンクリストをフラット化する方法【ソート済みリストの統合】

    この問題では、right と down という2つのポインタを持つノードで構成されるリンクリストが与えられます。 rightポインタ: メインとなるリンクリストをつなぐためのポインタです。 downポインタ: そのノードから始まるサブリンクリストをつなぐためのポインタです。 すべてのリンクリストはそれぞれソート済みであるものとします。求められているのは、これらの複数のリンクリストを1本のリストにまとめる(フラット化する)プログラムを作成することです。そして、結果として得られるリストもソート済みの状態になっていなければなりません。 問題の例 入力: 出力: 1-> 9->

  2. C++のstd::list::sort()でリストをソートする方法

    C++標準ライブラリによるソートの概要この記事では、C++の標準ライブラリを活用して配列や連結リスト(リンクリスト)をソートする方法について解説します。C++にはさまざまな用途に対応する多数のライブラリが標準で用意されており、ソート機能もその一つです。std::list::sort()は、リストの要素を昇順に並べ替えるメンバ関数です。この関数は安定ソート(stable sort)であるため、値が等しい要素同士の相対的な順序は保持されます。要素の比較には、デフォルトでoperator<が使用されます。サンプルコード#include <iostream> #include <li