[C++] vectorの使い方について詳しく解説
C++のvector
は、動的配列を提供するSTL(標準テンプレートライブラリ)のコンテナです。
サイズが自動的に調整され、要素の追加や削除が容易です。
イテレータを使って要素を操作することもできます。
vectorとは何か
C++のvector
は、標準テンプレートライブラリ(STL)の一部であり、動的配列を実現するためのコンテナです。
vector
は、要素の追加や削除が容易で、サイズが自動的に調整されるため、メモリ管理が簡単です。
以下に、vector
の主な特徴を示します。
特徴 | 説明 |
---|---|
動的サイズ | 要素の追加や削除に応じてサイズが変化する |
ランダムアクセス | インデックスを使用して要素にアクセス可能 |
メモリ管理 | 自動的にメモリを管理し、必要に応じて再割り当てを行う |
STLとの互換性 | 他のSTLアルゴリズムやコンテナと組み合わせて使用可能 |
vector
は、特に要素数が不明な場合や、頻繁に要素の追加・削除が行われる場合に非常に便利です。
次のセクションでは、vector
の基本操作について詳しく解説します。
vectorの基本操作
vector
の基本操作には、要素の追加、削除、アクセス、サイズの取得などがあります。
以下に、これらの操作を示すサンプルコードを紹介します。
#include <iostream>
#include <vector>
int main() {
// vectorの宣言
std::vector<int> numbers;
// 要素の追加
numbers.push_back(10); // 10を追加
numbers.push_back(20); // 20を追加
numbers.push_back(30); // 30を追加
// 要素へのアクセス
std::cout << "最初の要素: " << numbers[0] << std::endl; // 10を表示
std::cout << "2番目の要素: " << numbers.at(1) << std::endl; // 20を表示
// サイズの取得
std::cout << "要素の数: " << numbers.size() << std::endl; // 3を表示
// 要素の削除
numbers.pop_back(); // 最後の要素を削除
// 削除後のサイズの取得
std::cout << "削除後の要素の数: " << numbers.size() << std::endl; // 2を表示
return 0;
}
最初の要素: 10
2番目の要素: 20
要素の数: 3
削除後の要素の数: 2
基本操作の解説
- 要素の追加:
push_back
メソッドを使用して、vector
の末尾に要素を追加します。 - 要素へのアクセス: インデックス演算子
[]
やat
メソッドを使用して、特定の要素にアクセスできます。
at
メソッドは範囲外アクセス時に例外を投げるため、安全性が高いです。
- サイズの取得:
size
メソッドを使用して、現在の要素数を取得できます。 - 要素の削除:
pop_back
メソッドを使用して、vector
の末尾の要素を削除します。
これらの基本操作を理解することで、vector
を効果的に活用できるようになります。
次のセクションでは、vector
の応用操作について解説します。
vectorの応用操作
vector
は基本操作に加えて、さまざまな応用操作が可能です。
ここでは、要素の挿入、削除、ソート、検索、クリアなどの操作を紹介します。
以下にサンプルコードを示します。
#include <iostream>
#include <vector>
#include <algorithm> // sort関数を使用するために必要
int main() {
// vectorの宣言と初期化
std::vector<int> numbers = {30, 10, 20, 50, 40};
// 要素の挿入
numbers.insert(numbers.begin() + 2, 25); // インデックス2に25を挿入
// 要素の削除
numbers.erase(numbers.begin() + 1); // インデックス1の要素を削除
// ソート
std::sort(numbers.begin(), numbers.end()); // 昇順にソート
// 検索
auto it = std::find(numbers.begin(), numbers.end(), 25); // 25を検索
if (it != numbers.end()) {
std::cout << "25は見つかりました。" << std::endl;
} else {
std::cout << "25は見つかりませんでした。" << std::endl;
}
// vectorの内容を表示
std::cout << "vectorの内容: ";
for (const auto& num : numbers) {
std::cout << num << " "; // 各要素を表示
}
std::cout << std::endl;
// vectorのクリア
numbers.clear(); // すべての要素を削除
// クリア後のサイズの取得
std::cout << "クリア後の要素の数: " << numbers.size() << std::endl; // 0を表示
return 0;
}
25は見つかりました。
vectorの内容: 10 25 20 30 40 50
クリア後の要素の数: 0
応用操作の解説
- 要素の挿入:
insert
メソッドを使用して、指定した位置に要素を挿入できます。
位置はイテレータで指定します。
- 要素の削除:
erase
メソッドを使用して、指定した位置の要素を削除できます。 - ソート:
std::sort
関数を使用して、vector
の要素を昇順または降順にソートできます。 - 検索:
std::find
関数を使用して、特定の要素を検索できます。
見つかった場合は、そのイテレータが返されます。
- クリア:
clear
メソッドを使用して、vector
内のすべての要素を削除できます。
クリア後はサイズが0になります。
これらの応用操作を活用することで、vector
をさらに効果的に利用できるようになります。
次のセクションでは、vector
のパフォーマンスと注意点について解説します。
vectorのパフォーマンスと注意点
vector
は非常に便利なコンテナですが、使用する際にはパフォーマンスや注意点を理解しておくことが重要です。
以下に、vector
のパフォーマンス特性と注意すべき点を示します。
パフォーマンス特性
操作 | 平均時間計算 | 説明 |
---|---|---|
要素の追加 | O(1) | push_back で末尾に追加する場合、平均的には定数時間で済む。 |
要素の削除 | O(1) | pop_back で末尾の要素を削除する場合、定数時間で済む。 |
要素の挿入 | O(n) | 中間に要素を挿入する場合、後ろの要素を移動させる必要があるため、線形時間がかかる。 |
要素へのアクセス | O(1) | インデックスを使用したアクセスは定数時間で行える。 |
ソート | O(n log n) | std::sort を使用する場合、平均的にはO(n log n)の時間がかかる。 |
注意点
- メモリの再割り当て:
vector
は動的にサイズを変更しますが、要素数が増加すると、内部の配列が再割り当てされることがあります。
この際、既存の要素が新しいメモリにコピーされるため、パフォーマンスが低下する可能性があります。
予めreserve
メソッドを使用して、必要なサイズを確保しておくと良いでしょう。
- イテレータの無効化:
vector
の要素を追加・削除すると、イテレータが無効になることがあります。
特に、insert
やerase
を使用した場合、影響を受ける可能性があるため、注意が必要です。
- メモリ使用量:
vector
は、要素数が増えるとメモリを再割り当てするため、メモリの使用量が増加します。
特に、大量のデータを扱う場合は、メモリの効率を考慮する必要があります。
- スレッドセーフではない:
vector
は、複数のスレッドから同時にアクセスされる場合、スレッドセーフではありません。
スレッド間でのデータ競合を避けるために、適切な同期機構を使用する必要があります。
これらのパフォーマンス特性と注意点を理解することで、vector
をより効果的に活用し、プログラムの効率を向上させることができます。
次のセクションでは、他のSTLコンテナとの比較について解説します。
他のSTLコンテナとの比較
C++の標準テンプレートライブラリ(STL)には、vector
以外にもさまざまなコンテナが存在します。
ここでは、vector
と他の主要なSTLコンテナであるlist
、deque
、set
、map
との比較を行います。
各コンテナの特性を理解することで、適切なコンテナを選択する助けになります。
コンテナの比較表
コンテナ名 | 特徴 | 使用例 |
---|---|---|
vector | 動的配列。ランダムアクセスが高速。 | 要素数が不明な場合や、頻繁に追加・削除が行われる場合。 |
list | 双方向リスト。要素の挿入・削除が高速。 | 頻繁に要素の挿入・削除が行われる場合。 |
deque | 両端キュー。両端からの追加・削除が高速。 | 両端からの操作が多い場合。 |
set | 重複を許さない集合。自動的にソートされる。 | 一意な要素を保持したい場合。 |
map | キーと値のペアを保持する連想配列。 | キーに基づいて値を検索したい場合。 |
各コンテナの詳細
- vector:
- メモリを連続的に確保するため、ランダムアクセスが非常に高速です。
要素の追加は末尾でO(1)ですが、中間に挿入する場合はO(n)かかります。
サイズが変更されると、メモリの再割り当てが発生することがあります。
- list:
- 要素の挿入や削除がO(1)で行えるため、頻繁に要素を追加・削除する場合に適しています。
ただし、ランダムアクセスはO(n)かかるため、インデックスを使用したアクセスには向いていません。
- deque:
- 両端からの要素の追加・削除がO(1)で行えるため、キューやスタックとして使用するのに適しています。
vector
と同様にランダムアクセスも可能ですが、メモリの管理が異なります。
- set:
- 自動的にソートされ、重複を許さない集合です。
要素の追加、削除、検索はO(log n)で行えます。
順序を保ちながら一意な要素を管理したい場合に便利です。
- map:
- キーと値のペアを保持する連想配列で、キーに基づいて値を効率的に検索できます。
要素の追加、削除、検索はO(log n)で行えます。
キーの重複を許さないため、一意なキーでデータを管理したい場合に適しています。
これらのコンテナの特性を理解し、用途に応じて適切なコンテナを選択することで、プログラムの効率を向上させることができます。
まとめ
この記事では、C++のvector
について、その基本的な使い方から応用操作、パフォーマンス特性、他のSTLコンテナとの比較まで幅広く解説しました。
vector
は動的配列として非常に便利で、特に要素の追加や削除が頻繁に行われる場合に適していますが、使用する際にはその特性や注意点を考慮することが重要です。
今後は、実際のプログラムでvector
を活用し、さまざまなデータ構造との違いを体験してみてください。