参考記事:https://www.bilibili.com/video/BV1et411b73Z?p=185
C++ STL (標準テンプレート ライブラリ) は C++ 標準ライブラリの一部であり、ベクトル、リンク リスト、ヒープ、スタック、キュー、コレクションなどの一般的なデータ構造とアルゴリズムを実装するための汎用テンプレート クラスと関数のセットを提供します。 maps、sort、find など。STL の設計目標は、効率的で再利用可能で拡張可能なコードを提供し、プログラマーがデータ構造やアルゴリズムの実装の詳細ではなく、問題自体の解決に集中できるようにすることです。STL を使用すると、プログラムの開発効率とコードの保守性が大幅に向上します。
記事ディレクトリ
-
- 2 STLの紹介
- 3 STL-共通コンテナ
-
- 3.1 文字列コンテナ
- 3.2 vector容器
-
- 3.2.1 ベクターの基本的な考え方
- 3.2.2 ベクトルコンストラクタ
- 3.2.3 ベクトル代入演算 (assign)
- 3.2.4 ベクトルの容量とサイズ (empty()、capacity()、size()、resize() (容量の代わりにサイズを変更))
- 3.2.5 ベクターの挿入と削除 (push_back()、pop_back()、insert()、erase()、clear())
- 3.2.6 ベクトルデータアクセス (読み取りと変更) (at()、front()、back())
- 3.2.7 ベクトル スワップ コンテナー (swap()) (無名オブジェクトのメモリを縮小するために swap() を使用できます)
- 3.2.8 ベクトル予約空間 (reserve() 関数) (注: ベクトル配列空間が十分でない場合、メモリ空間が再割り当てされ、元の要素が新しいメモリ空間にコピーされ、元のメモリ空間が解放された; if 最初に、reserve() 関数を使用して十分な大きさのスペースを割り当てます。これにより、容量を動的に拡張するときにベクター拡張の数が減ります)
2 STLの紹介
2.1 STLの誕生
-
ソフトウェアの世界は長い間、再利用可能なものを構築したいと考えてきました
-
C++ のオブジェクト指向およびジェネリック プログラミングのアイデアは、再利用性の向上を目的としています
-
ほとんどの場合、データ構造とアルゴリズムの標準がないため、多くの反復作業が発生します
-
データ構造とアルゴリズムの一連の標準を確立するために、 STL が誕生しました。
2.2 STLの基本概念
- STL (標準テンプレート ライブラリ、標準テンプレート ライブラリ)
- STL は大きく次のように分けられます。コンテナー (コンテナー) アルゴリズム (アルゴリズム) イテレーター (反復子)
- コンテナーとアルゴリズムの間には、 iteratorを介したシームレスな接続があります。
- STL のほとんどすべてのコードは、テンプレート クラスまたはテンプレート関数を使用します。
2.3 STLの6つの主要コンポーネント(コンテナ、アルゴリズム、イテレータ、ファンクター、アダプター(アダプター)、空間コンフィギュレーター)
STLはコンテナ、アルゴリズム、イテレータ、ファンクター、アダプター(アダプター)、スペースコンフィギュレーターの6つの主要なコンポーネントに大別されます
- コンテナー: vector、list、deque、set、map などのさまざまなデータ構造を使用してデータを格納します。
- アルゴリズム: sort、find、copy、for_each など、一般的に使用されるさまざまなアルゴリズム。
- イテレーター: コンテナーとアルゴリズムの間の接着剤として機能します。
- Functor: 関数のように動作し、アルゴリズムのある種の戦略として使用できます。
- アダプター: コンテナーまたはファンクターまたはイテレーター インターフェイスを装飾するために使用されるもの。
- スペース コンフィギュレーター: スペースの構成と管理を担当します。
2.4 STLのコンテナ(シリアルコンテナ、連想コンテナ)、アルゴリズム(定性アルゴリズム、非定性アルゴリズム)、イテレータ
コンテナ:保管場所
STLコンテナーは、最も広く使用されているデータ構造のいくつかを実現するためのものです。
一般的に使用されるデータ構造: 配列、リンク リスト、ツリー、スタック、キュー、コレクション、マッピング テーブルなど。
これらのコンテナは、シーケンシャル コンテナと連想コンテナの2 つのタイプに分けられます。
シリアルコンテナー: 値の並べ替えを強調し、シリアル コンテナー内の各要素の位置は固定されています。
連想コンテナ: 二分木構造、要素間に厳密な物理的順序関係はありません
アルゴリズム: 問題の解決策
論理的または数学的な問題を解決するための限られた手順。この主題をアルゴリズム (アルゴリズム) と呼びます。
アルゴリズムは、質的変化アルゴリズムと非質的変化アルゴリズムに分けられます。
質的変化アルゴリズム: 間隔内の要素の内容が操作中に変更されることを意味します。コピー、置換、削除など。
非定性的アルゴリズム: 検索、カウント、トラバース、極値の検出などの操作中に、区間内の要素の内容が変更されないことを意味します。
イテレーター: コンテナーとアルゴリズムの間の接着剤 (一般的に使用される: 双方向イテレーター、ランダム アクセス イテレーター)
コンテナーの内部表現を公開せずに、コンテナーに含まれる要素への順次アクセスを可能にするメソッドを提供します。
各コンテナには独自のイテレータがあります
イテレータの使用はポインタと非常に似ています. 最初の段階で, イテレータがポインタであることを最初に理解することができます.
イテレータのタイプ:
タイプ | 関数 | サポート操作 |
---|---|---|
入力反復子 | データへの読み取り専用アクセス | 読み取り専用、サポート ++、==、!= |
出力反復子 | データへの書き込み専用アクセス | 書き込みのみ、++ をサポート |
前方反復子 | 読み取りおよび書き込み操作、イテレータを進めることができます | 読み取りと書き込み、サポート ++、==、!= |
双方向反復子 | 読み取りおよび書き込み操作、順方向および逆方向の操作が可能 | 読み取りと書き込み、サポート ++、–、 |
ランダムアクセス反復子 | 読み取りおよび書き込み操作、任意のデータにジャンプ方式でアクセスできる、最も強力な反復子 | 読み取りと書き込み、サポート ++、–、[n]、-n、<、<=、>、>= |
コンテナーで一般的に使用されるタイプの反復子は、双方向反復子とランダム アクセス反復子です。
2.5 コンテナ、アルゴリズム、イテレータの紹介
STLのコンテナ、アルゴリズム、イテレータの概念を理解した上で、コードを使ってSTLの魅力を感じる
STL で最も一般的に使用されるコンテナーは、配列として理解できる Vector です. 次に、このコンテナーにデータを挿入し、このコンテナーをトラバースする方法を学習します。
2.5.1 ベクトルストアの組み込みデータ型
容器:vector
アルゴリズム:for_each
イテレータ:vector<int>::iterator
例: コンテナーをトラバースする 4 つの方法
#include <vector>
#include <algorithm>
#include <iostream>
using namespace std;
void MyPrint(int val)
{
cout << val << endl;
}
void test01()
{
// 创建vector容器对象,并且通过模板参数指定容器中存放的数据的类型
vector<int> v;
// 向容器中放数据
v.push_back(10);
v.push_back(20);
v.push_back(30);
v.push_back(40);
// 每一个容器都有自己的迭代器,迭代器是用来遍历容器中的元素
// v.begin()返回迭代器,这个迭代器指向容器中第一个数据
// v.end()返回迭代器,这个迭代器指向容器元素的最后一个元素的下一个位置
// vector<int>::iterator 拿到vector<int>这种容器的迭代器类型
vector<int>::iterator pBegin = v.begin();
vector<int>::iterator pEnd = v.end();
// 第一种遍历方式:
while (pBegin != pEnd)
{
cout << *pBegin << endl;
pBegin++;
}
cout << "---------------------------" << endl;
// 第二种遍历方式:
for (vector<int>::iterator it = v.begin(); it != v.end(); it++)
{
cout << *it << endl;
}
cout << endl;
cout << "---------------------------" << endl;
// 第三种遍历方式:
// 使用STL提供标准遍历算法 头文件 algorithm
for_each(v.begin(), v.end(), MyPrint);
cout << "---------------------------" << endl;
// 第四种遍历方式:
// 使用 auto
for (auto i : v)
{
MyPrint(i);
}
cout << "---------------------------" << endl;
}
int main()
{
test01();
std::cout << "Press ENTER to continue...";
std::cin.ignore(std::numeric_limits<std::streamsize>::max(), '\n'); // 读取内容直到用户输入enter键
return EXIT_SUCCESS;
}
操作結果:
2.5.2 ベクターはカスタム データ型を格納します
学習目標: カスタム データ型をベクトルに保存して出力する
例:
#include <vector>
#include <algorithm>
#include <iostream>
#include <string>
using namespace std;
// 自定义数据类型
class Person
{
public:
Person(string name, int age)
{
mName = name;
mAge = age;
}
public:
string mName;
int mAge;
};
// 存放对象
void test01()
{
vector<Person> v;
// 创建数据
Person p1("aaa", 10);
Person p2("bbb", 20);
Person p3("ccc", 30);
Person p4("ddd", 40);
Person p5("eee", 50);
v.push_back(p1);
v.push_back(p2);
v.push_back(p3);
v.push_back(p4);
v.push_back(p5);
// for (vector<Person>::iterator it = v.begin(); it != v.end(); it++)
// {
// cout << "Name:" << (*it).mName << " Age:" << (*it).mAge << endl;
// }
for (auto i : v)
{
cout << "Name:" << i.mName << " Age:" << i.mAge << endl;
}
cout << "-----------------------" << endl;
}
// 放对象指针
void test02()
{
vector<Person *> v;
// 创建数据
Person p1("aaa", 10);
Person p2("bbb", 20);
Person p3("ccc", 30);
Person p4("ddd", 40);
Person p5("eee", 50);
v.push_back(&p1);
v.push_back(&p2);
v.push_back(&p3);
v.push_back(&p4);
v.push_back(&p5);
// for (vector<Person *>::iterator it = v.begin(); it != v.end(); it++)
// {
// Person *p = (*it);
// cout << "Name:" << p->mName << " Age:" << (*it)->mAge << endl;
// }
for (auto i : v)
{
cout << "Name:" << i->mName << " Age:" << i->mAge << endl;
}
cout << "-----------------------" << endl;
}
int main()
{
test01();
test02();
std::cout << "Press ENTER to continue...";
std::cin.ignore(std::numeric_limits<std::streamsize>::max(), '\n'); // 读取内容直到用户输入enter键
return EXIT_SUCCESS;
}
操作結果:
2.5.3 ベクターコンテナのネストされたコンテナ (多次元)
学習目標: コンテナーはコンテナー内にネストされ、すべてのデータを走査して出力します
例:
#include <vector>
#include <algorithm>
#include <iostream>
using namespace std;
// 容器嵌套容器
void test01()
{
vector<vector<int>> v;
vector<int> v1;
vector<int> v2;
vector<int> v3;
vector<int> v4;
for (int i = 0; i < 4; i++)
{
v1.push_back(i + 1);
v2.push_back(i + 2);
v3.push_back(i + 3);
v4.push_back(i + 4);
}
// 将容器元素插入到vector v中
v.push_back(v1);
v.push_back(v2);
v.push_back(v3);
v.push_back(v4);
// for (vector<vector<int>>::iterator it = v.begin(); it != v.end(); it++)
// {
// for (vector<int>::iterator vit = (*it).begin(); vit != (*it).end(); vit++)
// {
// cout << *vit << " ";
// }
// cout << endl;
// }
for (auto i : v)
{
for (auto j : i)
{
cout << j << " ";
}
cout << endl;
}
}
int main()
{
test01();
std::cout << "Press ENTER to continue...";
std::cin.ignore(std::numeric_limits<std::streamsize>::max(), '\n'); // 读取内容直到用户输入enter键
return EXIT_SUCCESS;
}
3 STL-共通コンテナ
3.1 文字列コンテナ
3.1.1 文字列の基本概念
自然:
- string は C++ スタイルの文字列であり、string は本質的にクラスです
文字列と文字の違い *:
- char * はポインタです
- string は char* をクラス内にカプセル化し、char* 型のコンテナであるこの文字列を管理するクラスです。
特徴:
文字列クラスは、多くのメンバー メソッドを内部的にカプセル化します。
例: 検索 検索、コピー コピー、削除 削除 置換 置換、挿入 挿入
String は char* によって割り当てられたメモリを管理するため、範囲外のコピーや範囲外の値などを心配する必要はなく、クラスが責任を負います。
3.1.2 文字列コンストラクタ
コンストラクタのプロトタイプ:
string();
// 次のような空の文字列を作成します: string str;
string(const char* s);
// string s で初期化しますstring(const string& str);
//文字列オブジェクトを使用して、別の文字列オブジェクトを初期化しますstring(int n, char c);
// n 文字で初期化 c
例:
#include <vector>
#include <algorithm>
#include <iostream>
using namespace std;
// string构造
void test01()
{
string s1; // 创建空字符串,调用无参构造函数
cout << "str1 = " << s1 << endl;
const char *str = "hello world";
string s2(str); // 把c_string转换成了string
cout << "str2 = " << s2 << endl;
string s3(s2); // 调用拷贝构造函数
cout << "str3 = " << s3 << endl;
string s4(10, 'a');
cout << "str4 = " << s4 << endl;
}
int main()
{
test01();
std::cout << "Press ENTER to continue...";
std::cin.ignore(std::numeric_limits<std::streamsize>::max(), '\n'); // 读取内容直到用户输入enter键
return EXIT_SUCCESS;
}
操作結果:
まとめ: 文字列の複数の構築方法は比較できません。柔軟に使用してください
3.1.3 文字列代入演算(assign())
機能説明:
- 文字列 string に値を割り当てる
割り当ての関数プロトタイプ:
string& operator=(const char* s);
//Char* 型の文字列が現在の文字列に割り当てられますstring& operator=(const string &s);
//文字列 s を現在の文字列に割り当てますstring& operator=(char c);
//現在の文字列への文字割り当てstring& assign(const char *s);
//文字列 s を現在の文字列に割り当てますstring& assign(const char *s, int n);
//文字列 s の最初の n 文字を現在の文字列に割り当てますstring& assign(const string &s);
//文字列 s を現在の文字列に割り当てますstring& assign(int n, char c);
// 現在の文字列に n 文字 c を割り当てます
例:
#include <vector>
#include <algorithm>
#include <iostream>
using namespace std;
// 赋值
void test01()
{
string str1;
str1 = "hello world";
cout << "str1 = " << str1 << endl;
string str2;
str2 = str1;
cout << "str2 = " << str2 << endl;
string str3;
str3 = 'a';
cout << "str3 = " << str3 << endl;
string str4;
str4.assign("hello c++");
cout << "str4 = " << str4 << endl;
string str5;
str5.assign("hello c++", 5);
cout << "str5 = " << str5 << endl;
string str6;
str6.assign(str5);
cout << "str6 = " << str6 << endl;
string str7;
str7.assign(5, 'x');
cout << "str7 = " << str7 << endl;
}
int main()
{
test01();
std::cout << "Press ENTER to continue...";
std::cin.ignore(std::numeric_limits<std::streamsize>::max(), '\n'); // 读取内容直到用户输入enter键
return EXIT_SUCCESS;
}
操作結果:
要約:
文字列の代入方法はいろいろありますが、operator=
こちらの方が実用的です
3.1.4 文字列連結 (append())
機能説明:
- 文字列の端での文字列のスプライシングを実現する
関数プロトタイプ:
string& operator+=(const char* str);
// += 演算子のオーバーロードstring& operator+=(const char c);
// += 演算子のオーバーロードstring& operator+=(const string& str);
// += 演算子のオーバーロードstring& append(const char *s);
// 文字列 s を現在の文字列の末尾に接続しますstring& append(const char *s, int n);
//文字列 s の最初の n 文字を現在の文字列の末尾に接続しますstring& append(const string &s);
//同演算子+=(const string& str)string& append(const string &s, int pos, int n);
//文字列 s の pos から始まる n 文字が文字列の末尾に接続されます
例:
#include <vector>
#include <algorithm>
#include <iostream>
using namespace std;
// 字符串拼接
void test01()
{
string str1 = "我";
str1 += "爱玩游戏";
cout << "str1 = " << str1 << endl;
str1 += ':';
cout << "str1 = " << str1 << endl;
string str2 = "LOL DNF";
str1 += str2;
cout << "str1 = " << str1 << endl;
string str3 = "I";
str3.append(" love ");
str3.append("game abcde", 4);
// str3.append(str2);
str3.append(str2, 4, 3); // 从下标4位置开始 ,截取3个字符,拼接到字符串末尾
cout << "str3 = " << str3 << endl;
}
int main()
{
test01();
std::cout << "Press ENTER to continue...";
std::cin.ignore(std::numeric_limits<std::streamsize>::max(), '\n'); // 读取内容直到用户输入enter键
return EXIT_SUCCESS;
}
操作結果:
要約: ストリングスプライシングには多くのオーバーロードされたバージョンがあります。初心者の段階でいくつか覚えておいてください。
3.1.5 文字列の検索と置換 (find()、rfind()、replace()) (rfind の r は逆方向、逆方向を意味します)
機能説明:
- 検索: 指定した文字列が存在するかどうかを検索します
- 置換: 指定された位置の文字列を置換します
関数プロトタイプ:
int find(const string& str, int pos = 0) const;
// pos から始まる str の最初のオカレンスを検索しますint find(const char* s, int pos = 0) const;
// pos から始めて、s の最初のオカレンスを検索しますint find(const char* s, int pos, int n) const;
//pos 位置から s の最初の n 文字の最初の位置を見つけるint find(const char c, int pos = 0) const;
//最初に出現する文字 c を見つけるint rfind(const string& str, int pos = npos) const;
// pos から始まる str の最後の位置を見つけるint rfind(const char* s, int pos = npos) const;
// pos から始まる s の最後のオカレンスを検索しますint rfind(const char* s, int pos, int n) const;
//pos から s の最初の n 文字の最後の位置を見つけるint rfind(const char c, int pos = 0) const;
//文字 c の最後のオカレンスを見つけるstring& replace(int pos, int n, const string& str);
// pos から始まる n 文字を文字列 str に置き換えますstring& replace(int pos, int n,const char* s);
// pos から始まる n 文字を文字列 s に置き換えます
例:
#include <vector>
#include <algorithm>
#include <iostream>
using namespace std;
// 查找和替换
void test01()
{
// 查找
string str1 = "abcdefgde";
int pos = str1.find("de");
if (pos == -1)
{
cout << "未找到" << endl;
}
else
{
cout << "pos = " << pos << endl;
}
pos = str1.rfind("de");
cout << "pos = " << pos << endl;
}
void test02()
{
// 替换
string str1 = "abcdefgde";
str1.replace(1, 1, "1111");
cout << "str1 = " << str1 << endl;
}
int main()
{
test01();
test02();
std::cout << "Press ENTER to continue...";
std::cin.ignore(std::numeric_limits<std::streamsize>::max(), '\n'); // 读取内容直到用户输入enter键
return EXIT_SUCCESS;
}
操作結果:
要約:
- 検索は左から後ろへ、rfind は右から左へ
- find は、文字列を検索した後に最初に見つかった文字の位置を返し、見つからない場合は -1 を返します。
- 置換するときは、置換する位置、文字数、文字列の種類を指定する必要があります
3.1.6 文字列比較 (compare())
機能説明:
- 文字列の比較
比較:
- 文字列比較は、文字の ASCII コードに基づいています
= 返回 0
> 返回 1
< 返回 -1
関数プロトタイプ:
int compare(const string &s) const;
// 文字列 s と比較int compare(const char *s) const;
// 文字列 s と比較
例:
#include <vector>
#include <algorithm>
#include <iostream>
using namespace std;
// 字符串比较
void test01()
{
string s1 = "hello";
string s2 = "aello";
int ret = s1.compare(s2);
if (ret == 0)
{
cout << "s1 等于 s2" << endl;
}
else if (ret > 0)
{
cout << "s1 大于 s2" << endl;
}
else
{
cout << "s1 小于 s2" << endl;
}
}
int main()
{
test01();
std::cout << "Press ENTER to continue...";
std::cin.ignore(std::numeric_limits<std::streamsize>::max(), '\n'); // 读取内容直到用户输入enter键
return EXIT_SUCCESS;
}
操作結果:
まとめ: 文字列比較は主に 2 つの文字列が等しいかどうかを比較するために使用され、どちらが大きいか小さいかを判断するのはあまり意味がありません
3.1.7 文字列の文字アクセス(文字の読み取りまたは変更)(at())
文字列内の 1 文字にアクセスするには 2 つの方法があります
char& operator[](int n);
//[]で文字を取得char& at(int n);
// at メソッドで文字を取得する
例:
#include <vector>
#include <algorithm>
#include <iostream>
using namespace std;
void test01()
{
string str = "hello world";
for (int i = 0; i < str.size(); i++)
{
cout << str[i];
}
cout << endl;
for (int i = 0; i < str.size(); i++)
{
cout << str.at(i);
}
cout << endl;
// 字符修改
str[0] = 'x';
str.at(1) = 'x';
cout << str << endl;
}
int main()
{
test01();
std::cout << "Press ENTER to continue...";
std::cin.ignore(std::numeric_limits<std::streamsize>::max(), '\n'); // 读取内容直到用户输入enter键
return EXIT_SUCCESS;
}
操作結果:
概要: 文字列内の 1 文字にアクセスするには、[ ]
またはat
3.1.8 文字列の挿入と削除 (insert()、erase())
文字列の挿入は、replace 関数の 2 番目のパラメーターが 0 であること、つまり何もないところから置換することに相当します。
機能説明:
- 文字列 string の文字の挿入と削除
関数プロトタイプ:
string& insert(int pos, const char* s);
//文字列を挿入string& insert(int pos, const string& str);
//文字列を挿入string& insert(int pos, int n, char c);
// 指定位置に n 文字 c を挿入string& erase(int pos, int n = npos);
//Posからn文字削除
string& erase(int pos, int n = npos);
_についてnpos
npos は C++ 標準ライブラリの文字列クラスの静的メンバー変数で、無限値を表し、通常は文字列の終了位置を表すために使用されます。string& erase(int pos, int n = npos) 関数では、n の値が指定されていない場合、位置 pos から文字列の末尾までのすべての文字がデフォルトで削除されます。したがって、ここでの npos の役割は、文字列の末尾の位置を示し、削除の範囲を指定することです。
例:
#include <vector>
#include <algorithm>
#include <iostream>
using namespace std;
// 字符串插入和删除
void test01()
{
string str = "hello";
str.insert(1, "111"); //相当于str.replace(1, 0, "111");
// str.replace(1, 0, "111");
cout << str << endl;
str.erase(1, 3); // 从1号位置开始3个字符
cout << str << endl;
}
int main()
{
test01();
std::cout << "Press ENTER to continue...";
std::cin.ignore(std::numeric_limits<std::streamsize>::max(), '\n'); // 读取内容直到用户输入enter键
return EXIT_SUCCESS;
}
操作結果:
要約: 挿入と削除の開始添字は 0 から始まります
3.1.9 文字列部分文字列 (substr())
機能説明:
- 文字列から目的の部分文字列を取得する
関数プロトタイプ:
string substr(int pos = 0, int n = npos) const;
//pos から n 文字の文字列を返す
注: substr パラメータは、左が開いて右が閉じる間隔です。つまり、[pos, npos)
例:
#include <vector>
#include <algorithm>
#include <iostream>
using namespace std;
// 子串
void test01()
{
string str = "abcdefg";
string subStr = str.substr(1, 3);
cout << "subStr = " << subStr << endl;
string email = "[email protected]";
int pos = email.find("@");
cout << "pos = " << pos << endl;
string username = email.substr(0, pos);
cout << "username: " << username << endl;
}
int main()
{
test01();
std::cout << "Press ENTER to continue...";
std::cin.ignore(std::numeric_limits<std::streamsize>::max(), '\n'); // 读取内容直到用户输入enter键
return EXIT_SUCCESS;
}
操作結果:
まとめ:部分文字列関数を柔軟に使えば、実際の開発で有効な情報が得られる
3.2 vector容器
3.2.1 ベクターの基本的な考え方
関数:
- ベクトル データ構造は配列に非常に似ており、シングル エンド配列としても知られています。
ベクトルと通常の配列の違い:
- 違いは、配列は静的空間であり、ベクトルは動的に拡張できることです
動的拡張の原則:元のスペースの後に新しいスペースを追加する代わりに、より大きなメモリスペースが見つかり、元のデータが新しいスペースにコピーされて元のスペースが解放されます
- ベクターコンテナのイテレータは、ランダムアクセスをサポートするイテレータです
3.2.2 ベクトルコンストラクタ
機能説明:
- ベクター コンテナーを作成する
関数プロトタイプ:
vector<T> v;
// テンプレート実装クラスの実装、デフォルト コンストラクターvector(v.begin(), v.end());
//間隔 v[begin(), end()) 内の要素をそれ自体にコピーします。vector(n, elem);
//コンストラクタは n 個の要素を自分自身にコピーします。(要素数 n の配列を作成)vector(const vector &vec);
// コンストラクターをコピーします。
例:
#include <vector>
#include <algorithm>
#include <iostream>
using namespace std;
void printVector(vector<int> &v)
{
for (vector<int>::iterator it = v.begin(); it != v.end(); it++)
{
cout << *it << " ";
}
cout << endl;
}
void test01()
{
vector<int> v1; // 无参构造
for (int i = 0; i < 10; i++)
{
v1.push_back(i);
}
printVector(v1);
vector<int> v2(v1.begin(), v1.end());
printVector(v2);
vector<int> v3(10, 100); // 创建10个值为100的元素的数组
printVector(v3);
vector<int> v4(v3);
printVector(v4);
}
int main()
{
test01();
std::cout << "Press ENTER to continue...";
std::cin.ignore(std::numeric_limits<std::streamsize>::max(), '\n'); // 读取内容直到用户输入enter键
return EXIT_SUCCESS;
}
参考記事:
まとめ: vector の複数の構築方法は比較できません。柔軟に使用してください
3.2.3 ベクトル代入演算 (assign)
機能説明:
- ベクター コンテナーに値を割り当てる
関数プロトタイプ:
-
vector& operator=(const vector &vec);
// 等号演算子をオーバーロードします -
assign(beg, end);
//間隔 [beg, end) 内のデータのコピーをそれ自体に割り当てます。 -
assign(n, elem);
// n 個の elem のコピーを自分自身に割り当てます。
例:
#include <vector>
#include <algorithm>
#include <iostream>
using namespace std;
void printVector(vector<int> &v)
{
for (vector<int>::iterator it = v.begin(); it != v.end(); it++)
{
cout << *it << " ";
}
cout << endl;
}
// 赋值操作
void test01()
{
vector<int> v1; // 无参构造
for (int i = 0; i < 10; i++)
{
v1.push_back(i);
}
printVector(v1);
vector<int> v2;
v2 = v1;
printVector(v2);
vector<int> v3;
v3.assign(v1.begin(), v1.end());
printVector(v3);
vector<int> v4;
v4.assign(10, 100); // 赋予数组10个值为100的元素
printVector(v4);
}
int main()
{
test01();
std::cout << "Press ENTER to continue...";
std::cin.ignore(std::numeric_limits<std::streamsize>::max(), '\n'); // 读取内容直到用户输入enter键
return EXIT_SUCCESS;
}
まとめ: ベクトルの割り当て方法は比較的単純です。operator= または assign を使用できます。
3.2.4 ベクトルの容量とサイズ (empty()、capacity()、size()、resize() (容量の代わりにサイズを変更))
機能説明:
- ベクター コンテナーの静電容量とサイズの操作
関数プロトタイプ:
-
empty();
// コンテナが空かチェック -
capacity();
//コンテナの容量 -
size();
//コンテナ内の要素数を返す -
resize(int num);
//コンテナーの長さを num として再指定します。コンテナーが長くなった場合は、新しい位置をデフォルト値で埋めます。//コンテナが短くなった場合、コンテナの長さを超える末尾の要素は削除されます。
-
resize(int num, elem);
//コンテナーの長さを num として再指定します。コンテナーが長くなった場合は、新しい位置に elem の値を入力します。// コンテナが短くなった場合、コンテナの長さを超える末尾の要素は削除されます
例:
#include <vector>
#include <algorithm>
#include <iostream>
using namespace std;
void printVector(vector<int> &v)
{
for (vector<int>::iterator it = v.begin(); it != v.end(); it++)
{
cout << *it << " ";
}
cout << endl;
if (v.empty())
{
cout << "v为空" << endl;
}
else
{
cout << "v不为空" << endl;
cout << "v的容量 = " << v.capacity() << endl;
cout << "v的大小 = " << v.size() << endl;
}
}
void test01()
{
vector<int> v1;
for (int i = 0; i < 10; i++)
{
v1.push_back(i);
}
printVector(v1);
cout << "------------------------" << endl;
// resize 重新指定大小 ,若指定的更大,默认用0填充新位置,可以利用重载版本替换默认填充
v1.resize(15, 10); // 以元素10填充
printVector(v1);
cout << "------------------------" << endl;
// resize 重新指定大小 ,若指定的更小,超出部分元素被删除
v1.resize(5);
printVector(v1);
cout << "------------------------" << endl;
}
int main()
{
test01();
std::cout << "Press ENTER to continue...";
std::cin.ignore(std::numeric_limits<std::streamsize>::max(), '\n'); // 读取内容直到用户输入enter键
return EXIT_SUCCESS;
}
要約:
- 空かどうかを判断する - 空
- 要素の数を返します — サイズ
- コンテナーの容量を返します — 容量
- サイズ変更 — サイズ変更
3.2.5 ベクターの挿入と削除 (push_back()、pop_back()、insert()、erase()、clear())
機能説明:
- ベクター コンテナーに対する挿入操作と削除操作
関数プロトタイプ:
push_back(ele);
//末尾に要素eleを挿入pop_back();
// 最後の要素を削除insert(const_iterator pos, ele);
//イテレータは要素 ele を挿入する位置 pos を指します (現在の添字要素の前に挿入されます)insert(const_iterator pos, int count,ele);
//イテレータは位置 pos を指し、count 個の要素 ele を挿入しますerase(const_iterator pos);
// イテレータが指す要素を削除erase(const_iterator start, const_iterator end);
//イテレータから要素を最初から最後まで削除するclear();
// コンテナ内のすべての要素を削除します
例:
#include <vector>
#include <algorithm>
#include <iostream>
using namespace std;
void printVector(vector<int> &v)
{
for (vector<int>::iterator it = v.begin(); it != v.end(); it++)
{
cout << *it << " ";
}
cout << endl;
}
// 插入和删除
void test01()
{
vector<int> v1;
// 尾插
v1.push_back(10);
v1.push_back(20);
v1.push_back(30);
v1.push_back(40);
v1.push_back(50);
printVector(v1);
// 尾删
v1.pop_back();
printVector(v1);
// 插入
v1.insert(v1.begin(), 100);
printVector(v1);
v1.insert(v1.begin(), 2, 1000); // 插入两个1000
printVector(v1);
// 删除
v1.erase(v1.begin());
printVector(v1);
// 清空
v1.erase(v1.begin(), v1.end());
v1.clear();
printVector(v1);
}
int main()
{
test01();
std::cout << "Press ENTER to continue...";
std::cin.ignore(std::numeric_limits<std::streamsize>::max(), '\n'); // 读取内容直到用户输入enter键
return EXIT_SUCCESS;
}
要約:
- テールプラグ — push_back
- テール削除 — pop_back
- insert — 挿入 (位置イテレータ)
- delete — 消去 (位置反復子)
- 空 - クリア
3.2.6 ベクトルデータアクセス (読み取りと変更) (at()、front()、back())
機能説明:
- ベクター内のデータへのアクセス
関数プロトタイプ:
at(int idx);
//インデックス idx が指すデータを返すoperator[];
//インデックス idx が指すデータを返すfront();
//コンテナ内の最初のデータ要素を返しますback();
//コンテナ内の最後のデータ要素を返します
例:
#include <vector>
#include <algorithm>
#include <iostream>
using namespace std;
void test01()
{
vector<int> v1;
for (int i = 0; i < 10; i++)
{
v1.push_back(i);
}
for (int i = 0; i < v1.size(); i++)
{
cout << v1[i] << " ";
}
cout << endl;
for (int i = 0; i < v1.size(); i++)
{
cout << v1.at(i) << " ";
}
cout << endl;
cout << "v1的第一个元素为: " << v1.front() << endl;
cout << "v1的最后一个元素为: " << v1.back() << endl;
}
int main()
{
test01();
std::cout << "Press ENTER to continue...";
std::cin.ignore(std::numeric_limits<std::streamsize>::max(), '\n'); // 读取内容直到用户输入enter键
return EXIT_SUCCESS;
}
要約:
- イテレータを使用してベクター コンテナー内の要素を取得するだけでなく、[ ] と at も使用できます。
- フロントはコンテナの最初の要素を返します
- back はコンテナの最後の要素を返します
3.2.7 ベクトル スワップ コンテナー (swap()) (無名オブジェクトのメモリを縮小するために swap() を使用できます)
機能説明:
- 2 つのコンテナー内の要素の交換を実現するには
関数プロトタイプ:
swap(vec);
// vec を独自の要素と交換
例:
#include <vector>
#include <algorithm>
#include <iostream>
using namespace std;
void printVector(vector<int> &v)
{
for (vector<int>::iterator it = v.begin(); it != v.end(); it++)
{
cout << *it << " ";
}
cout << endl;
}
void test01()
{
vector<int> v1;
for (int i = 0; i < 10; i++)
{
v1.push_back(i);
}
printVector(v1);
vector<int> v2;
for (int i = 10; i > 0; i--)
{
v2.push_back(i);
}
printVector(v2);
// 互换容器
cout << "互换后" << endl;
v1.swap(v2);
printVector(v1);
printVector(v2);
cout << "---------------------" << endl;
}
void test02()
{
vector<int> v;
for (int i = 0; i < 100000; i++)
{
v.push_back(i);
}
cout << "v的容量为:" << v.capacity() << endl;
cout << "v的大小为:" << v.size() << endl;
v.resize(3);
cout << "v的容量为:" << v.capacity() << endl;
cout << "v的大小为:" << v.size() << endl;
// 收缩内存
vector<int>(v).swap(v); // 匿名对象
cout << "收缩内存后:" << endl;
cout << "v的容量为:" << v.capacity() << endl;
cout << "v的大小为:" << v.size() << endl;
cout << "---------------------" << endl;
}
int main()
{
test01();
test02();
std::cout << "Press ENTER to continue...";
std::cin.ignore(std::numeric_limits<std::streamsize>::max(), '\n'); // 读取内容直到用户输入enter键
return EXIT_SUCCESS;
}
概要: swap は 2 つのコンテナーを交換可能にすることができ、メモリを縮小するという実際的な効果を得ることができます。
3.2.8 ベクトル予約空間 (reserve() 関数) (注: ベクトル配列空間が十分でない場合、メモリ空間が再割り当てされ、元の要素が新しいメモリ空間にコピーされ、元のメモリ空間が解放された; if 最初に、reserve() 関数を使用して十分な大きさのスペースを割り当てます。これにより、容量を動的に拡張するときにベクター拡張の数が減ります)
機能説明:
- 容量を動的に拡張する際に vector の展開回数を減らす
関数プロトタイプ:
reserve(int len);
//コンテナは len 要素の長さを予約しており、予約された位置は初期化されておらず、要素にアクセスできません。
例 (ベクトルの拡張戦略は特定の規則に従って拡張することであり、各拡張のサイズは元のサイズの 2 倍です)
注: ベクター内の要素数が現在の容量を超えると、ベクターはメモリ空間を再割り当てし、元の要素を新しいメモリ空間にコピーして、元のメモリ空間を解放します。このプロセスにより、ベクターの最初のアドレスが変更されます。頻繁なメモリの割り当てと解放を避けるために、reserve 関数を使用して一定量のメモリ空間を予約し、ベクトルによる頻繁なメモリ空間の再割り当てを避けることができます。
ベクターの拡張戦略は一定のルールに従って拡張することであり、拡張ごとのスペースは元のサイズの 2 倍になります
#include <vector>
#include <algorithm>
#include <iostream>
using namespace std;
void test01()
{
vector<int> v;
// 预留空间
v.reserve(100000);
int num = 0;
int *p = NULL;
for (int i = 0; i < 100000; i++)
{
v.push_back(i);
if (p != &v[0])
{
p = &v[0];
num++;
}
}
cout << "num:" << num << endl;
}
void test02()
{
vector<int> v;
// 预留空间
v.reserve(10);
int num = 0;
int *p = NULL;
for (int i = 0; i < 100000; i++)
{
v.push_back(i);
if (p != &v[0])
{
p = &v[0];
num++;
}
}
cout << "num:" << num << endl;
}
int main()
{
test01();
test02();
std::cout << "Press ENTER to continue...";
std::cin.ignore(std::numeric_limits<std::streamsize>::max(), '\n'); // 读取内容直到用户输入enter键
return EXIT_SUCCESS;
}
説明:
test02() では、10 個のスペースしか確保していませんが、ループ内で合計 100,000 個の要素を push_back しました. このとき、ベクターは自動的に展開され、展開ごとにより大きなメモリ空間が再割り当てされ、元の要素をコピーしますそのため、メモリを再割り当てする複数の操作が行われます。ただし、ベクトルの拡張戦略は一定の規則に従って拡張するため、各拡張のサイズは元のサイズの 2 倍になるため、メモリの再割り当ての数は実際には制限されます。この例では、最初から 10 個のスペースを予約しているため、最初の push_back で vector がこの 10 個のスペースを使い果たし、次に 20 個のスペースに拡張し、さらに 40 個のスペースに拡張するというように、容量がいっぱいになるまで最後の 131072 スペースに展開されます。したがって、メモリの再割り当て回数は実際には 15 回だけです。
まとめ: データ量が多い場合は、reserve を使用して最初に領域を予約できます