皆さん、またお会いしましょう。今回は、vector の基本的な使い方を説明します。読んで少しでも興味を持っていただけましたら、リンクを 3 つ残してください。あなたの願いがすべて叶いますように。
C 言語コラム:C 言語: 初心者からマスターまで
データ構造列:データ構造
个 人 主 页 :stackY、
C + + 专 栏 :C++
Linux 专 栏 :Linux
目次
1. ベクターの概要
データ構造で説明したシーケンス テーブルに似ています。
- vector は、可変サイズの配列を表すシーケンス コンテナです。
- 配列と同様に、vector も連続記憶域を使用して要素を保存します。これは、添字を使用してベクトルの要素にアクセスできることを意味し、配列と同じくらい効率的です。ただし、配列とは異なり、そのサイズは動的に変更でき、そのサイズはコンテナによって自動的に処理されます。
- 基本的に、vector は要素を格納するために動的に割り当てられた配列を使用します。新しい要素が挿入されると、記憶領域を増やすために配列のサイズを変更する必要があります。これは、新しい配列を割り当て、すべての要素をこの配列に移動することによって行われます。新しい要素がコンテナに追加されるたびにベクトルのサイズが変更されるわけではないため、これは時間の点で比較的高価なタスクです。
- ベクトル割り当てスペース戦略:ベクトルは、ストレージ スペースが実際に必要なストレージ スペースよりも大きいため、増加の可能性に対応するために追加のスペースを割り当てます。ライブラリーが異なれば、スペースの使用量と再割り当てをトレードオフするために異なる戦略が使用されます。ただし、いずれの場合も、最後に要素の挿入が一定時間で完了するように、再割り当ての間隔サイズは対数的に増加する必要があります。
- したがって、Vector は、ストレージ スペースを管理し、効率的な方法で動的に拡張する機能を得るために、より多くのストレージ スペースを必要とします。
- 他の動的シーケンス コンテナー (deque、list、forward_list) と比較して、vector は要素にアクセスする際の効率が高く、最後の要素の追加と削除も比較的効率的です。最後ではない他の削除および挿入操作の場合、効率はさらに低くなります。 list と forward_list の統一されたイテレータと参照よりも優れています
2. ベクトルの使用
Vector を学習する際は必ず学習してくださいドキュメントを表示する:Vector 公式ドキュメント リファレンス< a i=4>, ベクトルは実際には非常に重要です。実際には、一般的なインターフェイスに精通しているだけで済みます。以下に、どのインターフェイスに注目する必要があるかを示します。
2.1 ベクトルの定義
コンストラクター宣言 | インターフェースの説明 |
ベクター() | 引数なしの構築 |
ベクトル(size_type n, const value_type& val = 値の種類()) | n 個の値を構築して初期化する |
ベクトル (const ベクトル& x) | コピー構築 |
ベクトル (InputIterator が最初、InputIterator が最後) | イテレータを使用した初期化 |
ベクターを使用する前に、ベクターに対応するヘッダー ファイルをインクルードする必要があります。#include <vector>
#include <vector> //定义测试 void test_vector1() { //1. 无参 vector<int> v1; //2. n个val构造 vector<int> v2(10, 0); //3. 使用迭代器区间 vector<int> v3(v2.begin(), v2.end()); //4. 使用其他容器的迭代器区间 string str = "Hello World!"; vector<int> v4(str.begin(), str.end()); //拷贝构造 vector<int> v5(v2); }
2.2ベクトル反復子
イテレータの使用 | インターフェースの説明 |
開始 + 終了 |
最初のデータ位置の iterator/const_iterator を取得し、最後のデータの次の位置の iterator/const_iterator を取得します |
r開始+終了 | 最後のデータ位置の reverse_iterator を取得し、最初のデータの前の位置の reverse_iterator を取得します reverse_iterator |
//迭代器 void test_vector2() { vector<int> v2(10, 0); for (size_t i = 0; i < v2.size(); i++) { //vector也可以使用[] cout << v2[i] << " "; } cout << endl; //迭代器的使用 //vector<int>::iterator it = v2.begin(); auto it = v2.begin(); while (it != v2.end()) { cout << *it << " "; it++; } cout << endl; //范围for for (auto e : v2) { cout << e << " "; } cout << endl; }
2.3ベクトル空間の成長
容量スペース | インターフェースの説明 |
サイズ | データ数を取得する |
容量 | 容量サイズの取得 |
空の | 空かどうかを判断する |
サイズ変更 | ベクトルのサイズを変更する |
予約する | ベクターの容量を変更する |
- 容量コードを vs および g++ でそれぞれ実行すると、vs では容量が 1.5 倍、g++ では 2 倍増加することがわかります。この問題はよく調査されていますが、ベクター容量が 2 倍に増加すると固く信じてはいけません。具体的な増加は特定のニーズに基づいて定義されます。 vs は PJ バージョン STL、g++ は SGI バージョン STL です。
- リザーブはスペースを開くことのみを担当します。必要なスペースがどのくらいか確実にわかっている場合、リザーブはベクトル展開のコストの問題を軽減できます。
- サイズを変更すると、スペースを開くときに初期化も行われるため、サイズに影響します。
// 测试vector的默认扩容机制 void TestVectorExpand() { size_t sz; vector<int> v; sz = v.capacity(); cout << "making v grow:\n"; for (int i = 0; i < 100; ++i) { v.push_back(i); if (sz != v.capacity()) { sz = v.capacity(); cout << "capacity changed: " << sz << '\n'; } } }
vs:実行結果:vs 以下で使用する STL は基本的に 1.5 倍の方法で容量
foo を拡張します:
容量変更: 1 変更された容量: 94 変更された容量: 63 変更された容量: 42 変更された容量: 28 変更された容量: 19 変更された容量: 13 変更された容量: 9 変更された容量: 6 変更された容量: 4 変更された容量: 3
変更された容量: 2変更された容量: 141
g++ の実行結果: Linux で使用される STL は基本的に 2 倍に拡張されます。
foo が大きくなります:
容量の変更: 1< a i=3> 変更された容量: 2 変更された容量: 4 変更された容量: 8 変更された容量: 16 変更された容量: 128 変更された容量: 64 変更された容量: 32
ベクトルに格納する要素のおおよその数が決まっている場合は、事前に十分なスペースを設定 (reserve()) することができます。
挿入しながら拡張します。
サイズ変更と予約に焦点を当てましょう。
ベクトルを初期化したい場合は、まずスペースを作成してから初期化する必要があるため、ここではサイズ変更またはサイズ変更する必要があります。 a>予約しますか?
サイズ変更で変更されるのはベクトルのサイズであり、サイズは有効な要素の数を表します。予約はベクトルの容量を変更し、容量は有効なスペースを表すため、ベクトルを初期化するにはサイズ変更が必要です。
//容量 void test_vector3() { vector<int> v; //v.reserve(100); // size == 0 capacity == 100 v.resize(100); // size == 100 capacity == 100 //初始化 for (size_t i = 0; i < v.size(); i++) { v[i] = i; } for (auto e : v) { cout << e << " "; } cout << endl; }
2.4ベクターの追加、削除、確認、変更
ベクターの追加、削除、確認、修正 | インターフェースの説明 |
プッシュバック | テールプラグ |
ポップバック | 末尾削除 |
探す | 探す。 (これはアルゴリズム モジュールの実装であり、vector のメンバー インターフェイスではないことに注意してください) |
入れる | 位置の前に val を挿入 |
消す | 位置データの削除 |
スワップ | 2 つのベクトルのデータ空間を交換する |
演算子[ ] | 配列のようなアクセス |
1. 終端挿入、終端削除
void test_vector4() { vector<int> v; //尾插 v.push_back(1); v.push_back(2); v.push_back(3); v.push_back(4); v.push_back(5); for (auto e : v) { cout << e << " "; } cout << endl; //尾删 v.pop_back(); v.pop_back(); for (auto e : v) { cout << e << " "; } cout << endl; }
2. 挿入、削除、検索
検索アルゴリズムはベクターのインターフェースに属しません (挿入および削除に便利です)
//插入、删除 void test_vector5() { vector<int> v; v.push_back(1); v.push_back(2); v.push_back(3); v.push_back(4); v.push_back(5); //头插 v.insert(v.begin(), 0); //头删 v.erase(v.begin()); //在pos位置插入 v.insert(v.begin() + 2, 30); //删除pos位置 v.erase(v.begin() + 2); //在pos位置插入n个val v.insert(v.begin() + 1, 5, 10); //找到5个10并删除 for (size_t i = 0; i < 5; i++) { v.erase(find(v.begin(), v.end(), 10)); } }
2.4.1 イテレータの無効化
挿入および消去操作にベクトルを使用する場合、ベクトルのイテレータは無効になります。
void test_vector7() { vector<int> v; v.push_back(1); v.push_back(2); v.push_back(3); v.push_back(4); v.push_back(5); vector<int>::iterator it = v.begin(); while (it != v.end()) { cout << *it << ' '; v.insert(v.begin() + 2, 7); //造成迭代器失效 it++; } } void test_vector8() { vector<int> v = { 1,2,3,4,5,6,7,8,9,10 }; vector<int>::iterator it = v.begin(); //删除偶数 while (it != v.end()) { if (*it % 2 == 0) { v.erase(it); } it++; } }
同じ文字列の挿入と消去を行うと、反復子も失敗します。
void TestString() { string s("hello"); auto it = s.begin(); // 放开之后代码会崩溃,因为resize到20会string会进行扩容 // 扩容之后,it指向之前旧空间已经被释放了,该迭代器就失效了 // 后序打印时,再访问it指向的空间程序就会崩溃 //s.resize(20, '!'); while (it != s.end()) { cout << *it; ++it; } cout << endl; it = s.begin(); while (it != s.end()) { it = s.erase(it); // 按照下面方式写,运行时程序会崩溃,因为erase(it)之后 // it位置的迭代器就失效了 // s.erase(it); ++it; } }
イテレータの失敗に対する解決策: 使用する前にイテレータを再割り当てしてください。
3. クリアして縮小 (shrink_to_fit)
clear:データのみをクリアし、スペースは解放しません。
shrink_to_fit:容量をサイズに合わせる
void test_vector6() { vector<int> v; v.push_back(1); v.push_back(2); v.push_back(3); v.push_back(4); v.push_back(5); for (auto e : v) { cout << e << " "; } cout << endl; cout << v.size() << endl; cout << v.capacity() << endl; //清理 v.clear(); cout << v.size() << endl; cout << v.capacity() << endl; //缩容 v.shrink_to_fit(); cout << v.size() << endl; cout << v.capacity() << endl; }
友人の皆さん、楽しい時間はいつも短いです。この号での共有はここで終わりです。次に何が起こるかを知りたい場合は、次のエピソードを聞いてください~。読み終わった後は、大切な人を残すことを忘れないでください。ありがとうございました。あなたのサポート!