C++ STL学習(1) - コンテナ

C++ STL学習メモ(1) - コンテナ

トリビア

 Blue Bridge Cup の準備をするには、C++STL の部分を学習する必要があります。これにより、時間を大幅に節約できます。このメモは、ステーション B のダークホース プログラマー コースを視聴するときに覚えておくためのものです。

ダークホース プログラマーの創意工夫|0 から 1 エントリーのプログラミングまでの C++ チュートリアル、プログラミングの学習はもう難しくありません

1. STL の概要

1.1 STLの基本概念

  • STL(標準テンプレートライブラリ、標準テンプレートライブラリ)
  • STLは大きく分けて、 ①コンテナ(container) ②アルゴリズム(algorithm) ③イテレータ(iterator) に分かれます。
  • コンテナとアルゴリズムはイテレータを介して接続されます
  • STL のほとんどすべてのコードは、テンプレート クラスまたはテンプレート関数を使用します。

1.2 STL の 6 つのコンポーネント

STLはコンテナ、アルゴリズム、イテレータ、ファンクタ、アダプタ(アダプタ)、空間コンフィギュレータの6種類に大別されます。

  1. コンテナ: データの保存に使用されるさまざまなデータ構造 (ベクトル、リスト、デキュー、セット、マップなど)
  2. アルゴリズム: ソート、検索、コピーなど、一般的に使用されるさまざまなアルゴリズム
  。 3. イテレーター:コンテナとアルゴリズム コネクタ間
  4. ファンクター: アルゴリズムの特定の戦略として、動作は関数に似ています。
  5. アダプター: コンテナー、ファンクター、またはイテレーター インターフェイスを変更するために使用されます。
  6. スペース コンフィギュレーター: スペースの構成と管理を担当します。

1.3 STL のコンテナ、アルゴリズム、イテレータ

1.3.1 コンテナ

コンテナ: データを配置する
 STL コンテナは、最も広く使用されているデータ構造の 1 つです。一般的に使用される
 データ構造: 配列、リンク リスト、ツリー、キュー、コレクション、マッピング テーブルです。これらのコンテナは、シーケンシャル コンテナ連想コンテナの
2 つのタイプ  に分けられます順次コンテナ: 値の順序を重視し、各要素には固定位置の連想コンテナがあります。バイナリ ツリー構造。厳密な物理的順序関係はありません。
  
  

1.3.2 アルゴリズム

アルゴリズム: 論理的/数学的問題を解決するための限られたステップ
 アルゴリズムは次の 2 つに分類されます: 質的変更アルゴリズム、非質的変更アルゴリズム
 質的変更: 要素の内容を変更するアルゴリズム、コピーの削除
 非質的変更: 操作によって要素の内容が変更されない、カウント検索

1.3.3 イテレータ

イテレータ: アルゴリズムはコンテナ内のデータにアクセスするためにイテレータを使用する必要があります。
 各コンテナには独自のイテレータがあります。
用法类似于指针

一般的なイテレータのタイプは、双方向イテレータ、ランダム アクセス イテレータです。

1.4 コンテナアルゴリズムイテレータの概要

 STL コンテナ アルゴリズム イテレータの概念を理解した後、コードを使用して、
 最も一般的に使用されるコンテナであるVectorについての理解を深めます。これは、デモ用の配列として理解できます。

1.4.1 ベクターストアの組み込みデータ型

 コンテナ:vector
 アルゴリズム:for_each
 イテレータ:vector< int>::iterator

#include<iostream>
#include<vector>
#include<algorithm>
using namespace std;

void myPrint(int val){
    
    
	printf("%d\n",val);
}
void test01(){
    
    
	vector<int> v;//创建vector容器对象,通过模板参数指定容器中存放的数据类型 
	
	v.push_back(10); //放入数据 
	v.push_back(20);
	v.push_back(30);
	
	/* 第一种遍历
	 * v.begin()返回指向容器中第一个数据的迭代器
	 * v.end()返回指向容器中最后一个数据下一位的迭代器
	 * vector<int>::iterator 是vector<int>类型的迭代器
	 */
	vector<int>::iterator itBegin = v.begin();	//itBegin指向第一个元素 
	vector<int>::iterator itEnd = v.end();		//itEnd指向最后一个元素的下一位 
	while(itBegin != itEnd){
    
    
		cout<<*itBegin<<endl;
		itBegin++;
	}
	
	/*第二种遍历*/ 
	for(vector<int>::iterator it = v.begin();it!=v.end();it++){
    
    
		cout<<*it<<endl;
	}
	
	/*第三种遍历:利用STL提供的遍历算法*/
	for_each(v.begin(),v.end(),myPrint); 
	
}
int main(){
    
    
	test01();
	return 0;
} 

1.4.2 ベクターはカスタム データ型を保存します

(*it)到最后是什么类型,可以直接看迭代器尖括号里面的东西即可
就像下面的
函数1,(*it)是Person类型
函数2,(*it)是Person * 类型
#include<iostream>
#include<vector>
#include<algorithm>
#include<string>
using namespace std;

class Person{
    
    
	public: 
		Person(string name, int age){
    
    
			this->name = name;
			this->age = age;
		}
		string name;
		int age;
}; 

void test01(){
    
    
	vector<Person> v;
	
	Person p1("zhao",1);
	Person p2("qina",2);
	Person p3("swun",3);
	
	//存放数据 
	v.push_back(p1);
	v.push_back(p2);
	v.push_back(p3);
	
	//遍历数据 
	for(vector<Person>::iterator it=v.begin();it!=v.end();it++){
    
    
		cout<<(*it).name<<" "<<(*it).age<<endl;
	}
}

void test02(){
    
    
	vector<Person*> v;
	
	Person p1("zhao",1);
	Person p2("qina",2);
	Person p3("swun",3);
	
	//存放数据 
	v.push_back(&p1);
	v.push_back(&p2);
	v.push_back(&p3);
	
	//遍历数据 
	//*在这里*it是Person类型的指针*/ 
	for(vector<Person*>::iterator it=v.begin();it!=v.end();it++){
    
    
		cout<<(*it)->name<<" "<<(*it)->age<<endl;
	}
}

int main(){
    
    
	test01();
	test02();
	return 0;
} 

1.4.3 ベクターコンテナのネストされたコンテナ

学習目標: コンテナ内でコンテナをネストし、すべてのデータ出力
例を走査します。

#include<iostream>
#include<vector>
using namespace std;

//容器嵌套容器 
void test01(){
    
    
	vector< vector<int> >v;	

	vector<int> v1;
	vector<int> v2;
	vector<int> v3;

	for(int i = 0;i<3;i++){
    
    
		v1.push_back(i);
		v2.push_back(i+1);
		v3.push_back(i+2);		
	}
	
	//将小容器插入到大容器中 
	v.push_back(v1); 
	v.push_back(v2); 
	v.push_back(v3); 
	
	//通过大容器,将数据遍历
	for(vector<vector<int> >::iterator it=v.begin();it!=v.end();it++){
    
    
		//(*it) ----------容器 vector<int> 
		for(vector<int>::iterator vit=(*it).begin();vit != (*it).end();vit++){
    
    
			cout<< *vit <<" "; 
		}
		cout<<endl;
	} 
}
int main(){
    
    
	test01();
	return 0;
}


2. STL で一般的に使用されるコンテナ

2.1 文字列コンテナ

2.1.1 文字列の基本概念

自然:

 - string是C++风格的字符串,而string本质上是一个类
文字列と文字 * の違い:
 - char *是一个指针
 - string是一个类,类内部封装了char*,是char*型的容器

特徴:

 - string类内部封装了许多成员方法(例如:find,copy,delete)
 - string管理char*所分配的空间,不用担心下标越界

2.1.2 文字列コンストラクター

コンストラクターのプロトタイプ:

 - string();				//创建空的字符串
 - string(const char* s);	//使用字符串s初始化
 - string(const string& str);//使用字符串对象来初始化另一个string对象
 - string(int n,char c);	//使用n个字符c初始化
/*example*/
#include<iostream>
#include<vector>
using namespace std;

//string初始化 
void test01(){
    
    
	string str1;
	string str2("字符串2");
	string str3(str2);
	string str4(6,'a');

	cout << str1 << endl; 
	cout << str2 << endl;
	cout << str3 << endl;
	cout << str4 << endl;
}
int main(){
    
    
	test01();
	return 0;
}

2.1.3 文字列代入操作

機能の説明:

 - 给string字符串赋值(= 或者assign)

代入演算プロトタイプ関数

赋值操作一共有两种:一种是直接用等号=,原型如下
 - string& operator=(const char* s);//char* 类型字符串,赋值给当前字符串
 - string& operator=(const string &s);//把字符串赋值给当前的字符串
 - string& operator=(char c);//字符赋值给当前的字符串

另一种是assign()
 - 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赋给当前字符
/*example*/
#include<iostream>
using namespace std;

//string初始化 
void test01(){
    
    
	string str1;
	string str2;
	string str3;
	string str4;
	string str5;
	string str6;
	string str7;
	
	/*用等号来赋值*/
	str1 = "hello world"; 
	str2 = str1;
	str3 = "a";
	
	str4.assign("helloworld");
	str5.assign("string5",3);
	str6.assign(str1);
	str7.assign(5,'a');
	
	cout<<str1<<endl;
	cout<<str2<<endl;
	cout<<str3<<endl;
	cout<<str4<<endl;
	cout<<str5<<endl;
	cout<<str6<<endl;
	cout<<str7<<endl;
}
int main(){
    
    
	test01();
	return 0;
}

要約:
 文字列に値を代入する方法はたくさんありますが、operator= を使用するのがより実用的な方法です。

2.1.4 文字列の連結

機能の説明:

 - 实现在字符串的末尾拼接字符串

関数プロトタイプ:

 - 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); //同operator+=(const string& str)
 - string& append(const string &s, int pos, int n);//字符串s中从pos开始的n个字符连接到字符串结尾
/*exanmple*/
	string str1 = "I";
	string str2 = "you,li ming";
	string str3 = "Life";
	
	str1 += "love";	//追加字符串
	str1 += " ";	//追加单个字符
	str1 += str2;	//拼接字符串对象
	cout<<str1<<endl;//Ilove you
	
	str3.append(" is ");
	str3.append("movieasdfasdf",5);
	str3.append(str2,0,3);
	cout<<str3<<endl;//Life is movieyou

要約:

如果使用append(const string &s, int pos, int n)函数,
应当弄明白字符的位置是从0开始的

2.1.5 文字列の検索と置換

機能の説明:

查找:查找指定字符串是否存在
替换:在指定的位置替换字符串

関数プロトタイプ:

 - 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=0,int n) const; 	从pos位置查找s的前n个字符第一次位置
 - int find(const char c,int pos=0)  const; 		从pos位置查找字符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

rfind和find的区别:find默认从左往右查找,而rfind则代表从右往左查;
find找到字符串后返回查找到的字符串的第一个字符的下标,找不到则返回-1;
replace替换时要指定从哪儿个位置开始起,其后有多少个字符,替换成什么样的字符串。

  ヒント: C++ で関数を宣言する場合、その後に const が続くのは、関数の型を定数メンバー関数に制限するためであり、定数メンバー関数はメンバー変数の値を変更できない関数を指します。たとえば、「double d() const;」の場合、その中の「const」は、d() 関数が、それが属するオブジェクトのメンバー変数の値を変更する関数を持つことができないことを制限します。また、ある場合は、コンパイル段階でエラーが報告されます。その主な機能は、メンバー関数の意味を明確にすることであり、オブジェクトを変更しないメンバー関数の関数プロトタイプに const 記述を追加できます。この形式は、可読性を高め、論理エラーを減らす必要がある場合に使用できます。

/*查找举例*/
void test01(){
    
    
	string str1 = "zainashandenaoyouyiqunljl";
	int pos = str1.find("i");
	if (pos == -1)
		cout << "未找到" << endl;
	else
		cout << pos << endl;
	pos = str1.rfind("i");
	cout<<pos<<endl;
}
void test02(){
    
    
	string str1 = "zainashandenaoyouyiqunljl";
	/*从一号字符起3个字符用1111替换 */
	str1.replace(1,3,"1111") ;
	cout<<str1<<endl;
}

2.1.6 文字列の比較

比較する基準:

比较字符的ASCII码值
	= return 0
	> return 1
	< return -1

関数プロトタイプ:

在string类内部有这两个操作:
int compare(const string &s) const; //与string对象字符串s比较
int compare(const char *s) const; //与字符串s比较
/*example*/
string str1 = "hello!";
string str2 = "hillo!";
if (str1.compare(str2) == 0){
    
    
	cout << "str1和str2相同!" << endl;
}else if(str1.compare(str2) ==-1){
    
    
	cout << "str1小于str2!" << endl;
}else
	cout<<"str1大于str2"<<endl;

要約:

一般用来比较字符串是否相等

2.1.7 文字列文字アクセス

文字列内の単一の文字にアクセスするには 2 つの方法があります

在string类内部有这两个操作:
    char& operator[](int n); //通过[]方式取字符
    char& at(int n); //通过string类内部at方法获取字符
/*example*/
string str = "hello world";
cout<<str[1]<<endl;
for(int i=0;i<str.size();i++)
	cout<<str.at(i)<<endl;
/*修改*/
str[0] = 'x';
str.at(1) = 'x';
cout<<str<<endl;

2.1.8 文字列の挿入と削除

関数プロトタイプ:

在string类内部有这两个操作:
	string& insert(int pos, const char* s);//通过指向字符常量区域的指针对调用该成员函数的对象来插入字符
	string &insert(int pos,const string &str); //通过string类型的对象插入字符
	string &insert(int pos,int n,char c); //在指定位置插入n个字符c
	string &erase(int pos,int n=npos); //删除从pos开始的n个字符 
str.insert(1,"ag")

要約する

	通常情况下直接str.insert(1,"ag")就行;

2.1.8 文字列部分文字列の取得

関数プロトタイプ:

string substr(int pos = 0;int n=npos) const;
/*useful exanmple:输入邮箱,自动获取邮箱账号*/
void test02(){
    
    
	string str;
	cin >> str;
	string userName = str.substr(0,str.find("@"));
	cout<<userName<<endl;
}

次に、2 番目のタイプのコンテナーを示します: ベクトル

2.2 vector容器

2.2.1 ベクトルの基本概念

機能:
  ベクトル データ構造は、シングルエンド配列としても知られる配列に非常に似ています。
ベクトルと通常の配列の違い:
  違いは、配列が静的空間であるのに対し、ベクトルは動的に拡張できることです。
動的拡張:
  ① 元の空間の後に新しい空間を追加する代わりに、より大きなメモリ空間を見つけて、元のデータを新しい空間にコピーして元の空間を解放します。
  ②ベクターコンテナのイテレータはランダムアクセス対応のイテレータである

2.2.2 ベクトルコンストラクター

関数プロトタイプ:

vector<T> v; //采用模板实现类实现,默认构造函数
vector(v.begin(), v.end()); //将v[begin(), end()]区间中的元素拷贝给本身
vector(n, elem); //构造函数将n个elem拷贝给本身
vector(const vector &vec); //拷贝构造函数
vector<int>v1;  					 // 1.默认构造
vector<int> v2(v1.begin(), v1.end());//2.区间方式进行构造
vector<int> v3(10, 100);			 //3.n个elem方式构造
vector<int> v4(v3);					 //拷贝构造

2.2.3 ベクトル代入演算

関数プロトタイプ:

vector &operator = (const vector &vec); //重载等号操作符
assign(begin,end);//将[ begin, end ]区间的数据拷贝赋值给本身
assign(n,elem); //将n个elem拷贝赋值给本身 

例:

vector<int>v1 = v;
vector<int>v2;
v2.assign(v.begin(),v.end());
vector v3;
v3.assgin(12,1001);

2.2.4 ベクトルの容量とサイズ

関数プロトタイプ:

empty(); //判断容器是否为空
capacity(); //容器的容量
size(); //返回容器中元素的个数
resize(int num); //重新指定容器的长度为num,若容器变长,则以默认值0填充新位置。
​ 				 //如果容器变短,则末尾超出容器长度的元素被删除。
resize(int num, elem); //重新指定容器的长度为num,若容器变长,则以elem值填充新位置。
​ 					   //如果容器变短,则末尾超出容器长度的元素被删除

总结:
 - 判断是否为空--- empty()
 - 返回元素个数--- size()
 - 返回容量个数--- capacity()
 - 重新指定大小--- resize()

例:

#include<iostream>
#include<vector>
using namespace std;

void printVector(vector<int>& v)
{
    
    
	for (vector<int>::iterator it = v.begin(); it != v.end(); ++it)
	{
    
    
		cout << *it << " ";
	}
	cout << endl;
}
/*exanmple*/
void test02(){
    
    
	vector<int>v;
	for(int i=0;i<10;i++){
    
    
		v.push_back(i);
	}
	cout<<v.empty()<<endl;
	cout<<v.capacity()<<endl;
	cout<<v.size()<<endl;
	v.resize(6);
	printVector(v);
	v.resize(126,9);
	printVector(v);
}
int main(){
    
    
	test02();
	return 0;
}

2.2.5 ベクトルの挿入と削除

関数プロトタイプ:

push_back(ele) //尾部插入元素
pop_back() 	   //删除尾部元素
insert(const_iterator pos,ele) //迭代器指向位置pos插入ele
insert(const_iterator pos,int count,ele) //迭代器指向pos插入count个元素ele
erase(const_iterator start,const_iterator end) //删除迭代器从start到end之间的元素
clear() //删除容器中所有元素
概要: 末尾の挿入、反復子による要素の挿入、反復子による範囲内の要素の挿入、末尾の削除の削除、反復子による要素の削除、反復子による範囲内の要素の削除、要素を空にする。

例:

v.push_back(12);
v.pop_back();
v.insert(v.begin(),100);
v.insert(v.begin(),2,1000);
v.erase(v.begin());
v.erase(v.begin(),v.begin()++);
v.clear();

2.2.6 ベクターコンテナデータアクセス

関数プロトタイプ:

at(int idx); //返回索引idx所指的数据
operator[]; //返回索引idx所指的数据
front(); //返回容器中第一个数据元素
back(); //返回容器中最后一个数据元素

例:

for(int i = 0;i < v.size();i++){
	cout << v[i] << endl;
	cout << v.at(i) <<endl;
}
v.front();
v.back();

2.2.6 ベクトルスワップコンテナ

関数プロトタイプ:

swap(vec): //将vec与本身的元素互换

例:

v1.swap(v2);

魔法の効果:

有一说一,这个里面的那个利用匿名对象来收缩空间的方法胎牛皮了!!!!!!
#include<iostream>
#include<vector>
using namespace std;
 
void printvector(vector<int> &v)
{
    
    
	for(vector<int>::iterator it=v.begin();it!=v.end();it++)
		cout<<*it<<" ";
	cout<<endl;
}
 
 
void test1()
{
    
    
	cout<<"交换之前的两个容器:"<<endl;
	vector<int> v1;
	for(int i=0;i<10;i++)
		v1.push_back(i);
	printvector(v1);
 
	vector<int> v2;
	for(int i=9;i>=0;i--)
		v2.push_back(i);
	printvector(v2);
	
	cout<<"交换之后的两个容器:"<<endl;
	v1.swap(v2);
	printvector(v1);
	printvector(v2);
 } 
 
 
 void test2() //容器互换应用实例
 {
    
    
 	vector<int> v;
	for(int i=0;i<10000;i++)
		v.push_back(i); 
	cout<<"v的容量为:"<<v.capacity()<<" v的大小为: "<<v.size()<<endl;
	
	v.resize(5); //重新指定大小之后,容量不变,大小改变 
	cout<<"v的容量为:"<<v.capacity()<<" v的大小为: "<<v.size()<<endl;
	
	//利用swap收缩内存
	vector<int>(v).swap(v); //vector<int>(v): 匿名对象 
	cout<<"v的容量为:"<<v.capacity()<<" v的大小为: "<<v.size()<<endl;
 } 
 
int main()
{
    
    
	test1();
	test2();
	return 0;
}
 
/*
打印结果:
交换之前的两个容器:
0 1 2 3 4 5 6 7 8 9
9 8 7 6 5 4 3 2 1 0
交换之后的两个容器:
9 8 7 6 5 4 3 2 1 0
0 1 2 3 4 5 6 7 8 9
v的容量为:16384 v的大小为: 10000
v的容量为:16384 v的大小为: 5
v的容量为:5 v的大小为: 5
*/

2.2.6 ベクトル予約スペース

機能の説明:

减少vector在动态扩展容量时的扩展次数

関数プロトタイプ:

reserve(int len);  
容器预留len个元素长度,预留位置不初始化,元素不可访问

例:

v.reserve(100000);


以下はデックです

2.3 デックコンテナ

2.3.1 dequeコンテナの基本概念

特性:

ヘッドエンドで操作を挿入および削除できる両端配列。
両端キュー コンテナのイテレータはランダム アクセスもサポートしています。
使用する場合は、ヘッダー ファイルをインクルードする必要があります。#include<deque>

ベクトルとの違い:

vector对于头部的插入删除效率低,数据量越大,效率越低
deque相对而言,对头部的插入删除速度回比vector快
vector访问元素时的速度会比deque快,这和两者内部实现有关

内部deque の内部動作原理:

deque内部有个中控器,维护每段缓冲区中的内容,缓冲区中存放真实数据
中控器维护的是每个缓冲区的地址,使得使用deque时像一片连续的内存空间

中央コントローラー



2.3.2 deque コンストラクターとイテレーター

関数プロトタイプ:

deque<T> deqT;            默认构造形式
deque(beg,end);           构造函数将[beg,end)区间中元素拷贝给本身
deque(n,elem);            构造函数将n个elem拷贝给本身
deque(const deque &deq);  拷贝构造函数

例 1:

deque<int>dl;
for(int i=0;i<10;i++)
	dl.push_back(i);
deque<int>d2(dl.begin(),dl.end());
deque<int>d3(10,100);
deque<int>d4=d3;

反復子:

const変更せずに走査のみを行う場合は、エラーが報告されないように、キーワード型
constのコンテナにはconst_iteratorイテレータが必要であることを追加する必要があります。

例 2:

void printDeque(const deque<int>&d){
    
    
	for(deque<int>::const_iterator it = d.begin();it!=d.end();it++){
    
    
		cout<<*it<<endl;
	}
}

2.3.3 デキュー代入操作

関数プロトタイプ:

deque& operator=(const deque &deq);      重载等号操作符
assign(beg,end);                         将[beg,end)区间中的数据拷贝赋值给本身
assign(n,elem);                          将n个elem拷贝赋值给本身

例:

deque<int>d2;
d2=dl;

//assign赋值
deque<int>d3;
d3.assign(dl.begin(),dl.end());

deque<int>d4;
d4.assign(10,100);

2.3.4 デキューサイズの操作

注意点:

deque容器是没有容量这个概念的,
所以不像vector中有capacity函数

関数プロトタイプ:

deque.empty();            判断容器是否为空
deque.size();             返回容器中元素的个数
deque.resize(num);        重新指定容器的长度为num,若容器变长,则默认值填充新位置,
                          若容器变短,则末尾值超出容器长度的元素被删除
deque.resize(num,elem);   重新指定容器的长度为num,若容器边长,则以elem值填充新位置,
                          如果容器变短,则末尾超出容器长度的元素被删除

要約:

判断是否为空 --- empty
返回元素个数 --- size
重新指定个数 --- resize

2.3.5 deque の挿入と削除

関数プロトタイプ:

 两端插入操作: 
 push_back(elem);             在容器尾部添加一个数据
 push_front(elem);            在容器头部插入一个数据
 pop_back();                  删除容器最后一个数据
 pop_front();                 删除容器第一个数据
 
指定位置操作:
insert(pos,elem);             在pos位置插入一个elem元素的拷贝,返回新数据的位置
insert(pos,n,elem);           在pos位置插入n个elem数据,无返回值
insert(pos,beg,end);          在pos位置插入[beg,end)区间的数据,无返回值
clear();                      清空容器的所有数据
erase(beg,end);               删除[beg,end)区间的数据,返回下一个数据的位置
erase(pos);                   删除pos位置的数据,返回下一个数据的位置

例:

d.push_back(10);
d.pop_front();

2.3.6 データアクセスのデキュー

関数プロトタイプ:

at(int idx);        返回索引idx所指的数据
operator[];         返回索引idx所指的数据
front();            返回容器中第一个数据
back();             返回容器中最后一个数据

例:

for(i=0; i<d.size() ;i++);{
    
    
	cout<<d[i]<<" ";
	cout<<d.at(i)<<" ";
}

2.3.7 デックソート

知らせ:

注意包含头文件<algorithm>;
sort算法默认升序;
对于支持随机访问的迭代器的容器,都可以利用sort算法直接对其进行排序;

アルゴリズム:

sort(iterator beg, iterator end);

例:

sort(d1.begin(), d1.end());


以下はスタックです

2.4スタックコンテナ

2.4.1 スタックの基本概念

概念:スタックは先入れ先出し(先入れ先出し) データ構造であり、
  出口が 1 つだけあり、
 スタックの最上位要素のみにアクセスできます。
 stack はトラバーサル関数もイテレータも提供しません。
 プッシュpush
 ・ポップ・pop
代替

2.4.2 スタック共通インターフェース

関数プロトタイプ:

stack构造函数
	stack<T> stkT;//stack采用模板类实现, stack对象的默认构造形式:
	stack(const stack &stk);//拷贝构造函数

stack赋值操作
	stack& operator=(const stack &stk);//重载等号操作符

stack数据存取操作
	push(elem);//向栈顶添加元素
	pop();//从栈顶移除第一个元素
	top();//返回栈顶元素

stack大小操作
	empty();//判断堆栈是否为空
	size();//返回堆栈的大小

例:

s.top();//查看栈顶元素
s.pop();//出栈


以下はクエリです

2.5キューコンテナ

2.5.1 quequeの基本概念

コンセプト:

キューは、先进先出2 つの出口を持つ (先入れ先出し、FIFO) データ構造です。キュー
コンテナでは、一方の端から要素を追加し、もう一方の端から要素を削除できます。外部ではキュー
内の合計のみが使用できるため、キューでは許可されていません トラバーサル動作では、キュー内のデータが呼び出されます -キューからのデータが呼び出されます -队头 front()队尾 back()
入队 push
出队 pop
代替

2.5.2 クエリ共通インターフェース

构造函数:
queue<T> que; //queue采用模板类实现,queue对象的默认构造形式
queue(const queue &que); //拷贝构造函数

赋值操作:
queue& operator=(const queue &que); //重载等号操作符

数据存取:
push(elem); //往队尾添加元素
pop(); //从队头移除第一个元素
back(); //返回最后一个元素
front(); //返回第一个元素

大小操作:
empty(); //判断堆栈是否为空
size(); //返回栈的大小

要約:

キューに入る:push
キューから出る:pop
キューの先頭の要素を返す キューの
最後尾の要素を返す:back
チームが空かどうかの判定:empty
キューのサイズを返す:size

2.5.3 クエリの例

#include <queue>
#include <string>
class Person
{
    
    
public:
	Person(string name, int age)
	{
    
    
		this->m_Name = name;
		this->m_Age = age;
	}

	string m_Name;
	int m_Age;
};

void test01() {
    
    

	//创建队列
	queue<Person> q;

	//准备数据
	Person p1("唐僧", 30);
	Person p2("孙悟空", 1000);
	Person p3("猪八戒", 900);
	Person p4("沙僧", 800);

	//向队列中添加元素  入队操作
	q.push(p1);
	q.push(p2);
	q.push(p3);
	q.push(p4);

	//队列不提供迭代器,更不支持随机访问	
	while (!q.empty()) {
    
    
		//输出队头元素
		cout << "队头元素-- 姓名: " << q.front().m_Name 
              << " 年龄: "<< q.front().m_Age << endl;
        
		cout << "队尾元素-- 姓名: " << q.back().m_Name  
              << " 年龄: " << q.back().m_Age << endl;
        
		cout << endl;
		//弹出队头元素
		q.pop();
	}
	cout << "队列大小为:" << q.size() << endl;
}

int main() {
    
    
	test01();
	system("pause");
	return 0;
}


以下はリストです

2.6 リスト

2.6.1 リストの基本概念

优缺点:

利点:
 要素は任意の位置にすばやく挿入または削除できます。
欠点:
 コンテナの走査速度は配列ほど速くなく、
 配列よりも多くのスペースを占有します。

STL中的链表

STL のリンク リストは双方向の循環リンク リストであり、イテレータは前方および後方の移動のみをサポートします。双向迭代器
代替

概要: STL で最もよく使用される 2 つのコンテナーは List と Vector であり、それぞれに独自の長所と短所があります。

2.6.2 リストコンストラクタ

関数プロトタイプ

list<T> lst; //list采用采用模板类实现,对象的默认构造形式;
list(beg,end); //构造函数将[beg, end)区间中的元素拷贝给本身。
list(n,elem); //构造函数将n个elem拷贝给本身。
list(const list &lst); //拷贝构造函数。

例:

list<int> l1; //默认构造
list<int> l2(l1.begin(), l1.end()); //区间方式构造(也属于拷贝)
list<int> l3(l2); //拷贝构造
list<int> l4(10, 999); //10个999(也属于拷贝)

3.7.3 リストの割り当てと交換

関数プロトタイプ:

  • assign(begin, end);//範囲 [beg, end) 内のデータのコピーをそれ自体に割り当てます。
  • assign(n, elem);// n 個の要素のコピーをそれ自体に割り当てます
  • list& operator=(const list &lst);// 等号演算子をオーバーロードします
  • swap(lst);// lst を独自の要素と交換します。

list<int>l1;
l2 = l1;
l3.assign(l2.begin(),l2.end());
l4.assign(10,100);
l4.swap(l3);

3.7.4 リストサイズの操作

関数プロトタイプ

size();//コンテナ内の要素数を返す
empty();//コンテナが空かどうかを判断
resize(num);//コンテナの長さをnumに再指定し、コンテナが長くなった場合は新しい位置をデフォルト値で埋めます。コンテナーが短くなると、コンテナーの長さを超える最後の要素が削除されます。
resize(num, elem);//コンテナの長さを num として再指定します。コンテナが長くなった場合は、新しい位置を elem の値で埋めます。コンテナーが短くなると、コンテナーの長さを超える最後の要素が削除されます。

#include<iostream>
#include<string>
#include<list>
#include<algorithm>
using namespace std;

class Person//容器中要存放的数据类型
{
    
    
public:
	Person() {
    
    }
	Person(string name, int age)
	{
    
    
		m_name = name;
		m_age = age;
	}

	string m_name;
	int m_age;
};


void PrintList(const list<Person> &l)//打印容器中的数据
{
    
    
	for (list<Person>::const_iterator it = l.begin(); it != l.end(); it++)
	{
    
    
		cout << it->m_name << " " << it->m_age << endl;//用*it访问也可以,用指针也可以
	}
	cout << endl;
}

/*
size();                     //返回容器中元素的个数

empty();                    //判断容器是否为空

resize(num);                //重新指定容器的长度为num,若容器变长,则以默认值填充新位置。

​							//如果容器变短,则末尾超出容器长度的元素被删除。

resize(num, elem);			//重新指定容器的长度为num,若容器变长,则以elem值填充新位置。

							//如果容器变短,则末尾超出容器长度的元素被删除。

*/

void test01(){
    
    //list大小操作
	list<Person> l;

	string Name = "ABC";
	for (int i = 0; i < 3; i++){
    
    //往容器里边插入三个数据
		string name = "李";
		name += Name[i];
		Person p(name, i + 20);
		l.push_back(p);
	}

	if (!l.empty()){
    
    
		cout << "容器不为空,大小为:"<<l.size() << endl;
	}
	else
		cout << "容器为空" << endl;	

	Person p("默认", 100);
	l.resize(10,p);
	l.resize(1);
	PrintList(l);

}

int main(){
    
    
	test01();
	return 0;
}

2.7.5 リストの挿入と削除

関数プロトタイプ:

* push_back(elem);			//在容器尾部加入一个元素
* pop_back();				//删除容器中最后一个元素
* push_front(elem);			//在容器开头插入一个元素
* pop_front();				//从容器开头移除第一个元素
* insert(pos,elem);			//在pos位置插elem元素的拷贝,返回新数据的位置。
* insert(pos,n,elem);		//在pos位置插入n个elem数据,无返回值。
* insert(pos,beg,end);		//在pos位置插入[beg,end)区间的数据,无返回值。
* clear();					//移除容器的所有数据
* erase(beg,end);			//删除[beg,end)区间的数据,返回下一个数据的位置。
* erase(pos);				//删除pos位置的数据,返回下一个数据的位置。
* remove(elem);				//删除容器中所有与elem值匹配的元素。

2.7.6 リストデータアクセス

関数プロトタイプ:

l.front();コンテナの最初の要素を返します。
l.back();コンテナの最後の要素を返します
。 注:

[] を使用してリスト コンテナーの要素にアクセスすることはできません
at() を使用してリスト コンテナーの要素にアクセスすることはできません
理由は次のとおりです。リストは本質的にリンク リストであり、連続線形空間にデータを格納するのには適していません。反復子はランダム アクセスをサポートせず (it = it+1 エラー)、双方向アクセス (it–) をサポートします。

l1.front();
l2.back();

2.7.7 リストの反転とソート

関数プロトタイプ:

reverse();反転リンク リスト
sort()の並べ替え (メンバー関数、デフォルトの昇順、ファンクターを使用して降順を実装できます)

重要なヒント:

ランダム アクセス イテレータをサポートしないすべてのコンテナは、標準アルゴリズムを使用できません。
ランダム アクセス イテレータをサポートしないコンテナは、内部的にいくつかのアルゴリズムを提供します。リストに
付属するソート アルゴリズムは、デフォルトで小さいものから大きいものへの昇順になります。コールバック関数またはファンクタは、降順を実装します(ここではコールバック関数)

/*example*/
#include <iostream>
#include <list>
using namespace std;

template<class T>
void printList(const list<T>& L)
{
    
    
	for (list<T>::const_iterator it = L.begin(); it != L.end(); it++)
	{
    
    
		cout << *it << '\t';
	}
	cout << endl;
}

bool myCompare(int v1, int v2)
{
    
    
	//降序 让 第一个数 > 第二个数
	return v1 > v2;
}

//排序
void test2()
{
    
    
	list<int>L1;
	L1.push_back(20);
	L1.push_back(10);
	L1.push_back(50);
	L1.push_back(40);
	L1.push_back(30);

	cout << "排序前:" << endl;
	printList(L1);

	L1.sort();  //默认升序
	cout << "排序后:" << endl;
	printList(L1);

	L1.sort(myCompare);
	printList(L1);
}

int main()
{
    
    
	test2();
}

2.7.8 リストソートの場合

#include<iostream>
#include<string>
#include<sstream>
#include<list>
using namespace std;

/***/
class Person{
    
    
public:
	Person(string name,int age,int height){
    
    
		this->m_Name = name; 
		this->m_Age = age;
		this->m_Hight = height;
	}
	
	string printInfo()
    {
    
    
        stringstream temp;
        temp << "姓名:" << this->m_Name << "\t年龄:" << this->m_Age << "\t身高:" << this->m_Hight;
        return temp.str();
    }
	
	string m_Name;
	int m_Age;
	int m_Hight;
	
}; 
//指定排序规则
bool comparePerson(Person &p1, Person &p2){
    
    
	if(p1.m_Age == p2.m_Age){
    
    
		return p1.m_Hight < p2.m_Hight;
	}
	return p1.m_Age < p2.m_Age;
} 

void test01(){
    
    
	list<Person>L;
	
	Person p1("刘备", 35, 175);
    Person p2("曹操", 45, 180);
    Person p3("孙权", 40, 170);
    Person p4("赵云", 25, 190);
    Person p5("张飞", 35, 160);
    Person p6("关羽", 35, 200);
    
    L.push_back(p1);
    L.push_back(p2);
    L.push_back(p3);
    L.push_back(p4);
    L.push_back(p5);
    L.push_back(p6);
    
    for(list<Person>::iterator it = L.begin();it != L.end();it++){
    
    
		cout<< it->printInfo()<<endl;
    } 
    cout<<"----------------------------"<<endl; 
    L.sort(comparePerson);
    for(list<Person>::iterator it = L.begin();it != L.end();it++){
    
    
		cout<< it->printInfo()<<endl;
    }
    
}

int main(){
    
    
	test01(); 
	return 0;
}

 カスタム データ型の場合、並べ替えルールを指定する必要があります。指定しないと並べ替え方法がわかりません。
 高度な並べ替えは、並べ替えルールに論理ルールを再度指定するだけであり、複雑ではありません。

2.8 set/multiset容器

2.8.1 集合の基本概念

はじめに:すべての要素は挿入時に自動的にソートされます
本質: set/multiset は連想コンテナーであり、基礎となる構造はバイナリ ツリーで実装されます
違い: set では重複要素は許可されず、multiset では重複要素が許可されます

2.8.2 セットの構築と代入

コンストラクター:
set< T> st;//デフォルトのコンストラクター:
set(const set &st);//コピーコンストラクター

割り当て:
set& operator=(const set &st);//等号演算子をオーバーロードします
データを挿入します:
insert();

set<int> s2(s1);
set<int> s3;
s3 = s2;

2.8.3 コンテナのサイズとスワップの設定

関数プロトタイプ:
size(); //コンテナ内の要素数を返す
empty();//コンテナが空かどうかを判断
swap(st);//2つのコレクションコンテナを交換

2.8.4 コンテナの挿入と削除の設定

関数プロトタイプ:
insert(elem); //コンテナに要素を挿入します。
clear();//すべての要素をクリア
erase(pos);//pos イテレータが指す要素を削除し、次の要素のイテレータを返します。
erase(beg, end);//区間 [beg, end) 内のすべての要素を削除し、次の要素のイテレータを返します。
erase(elem);//コンテナ内の値が elem である要素を削除します。

s1.erase(s1.begin());
s1.erase(30);

2.8.5 セットルックアップと統計

関数プロトタイプ:
find(key); //キーが存在するかどうかを確認し、存在する場合はキーの要素のイテレータを返し、存在しない場合は set.end() を返します;
count(key);//キー要素の数の統計、0 のみセットの場合は 1、マルチセットの場合は 1 より大きい値にすることができます。

set<int>::iterator pos = s1.find(12);
if(pos != s1.end())
	cout << "找到元素" << endl;
else
	cout << "未找到元素" << endl;

2.8.6 セットとマルチセットの違い

違い:

 Set では重複データを挿入できませんが、multiset では
 set でデータを挿入し、挿入が成功したかどうかを示す挿入結果を返すことができます。Multiset は
 データを検出しないため、重複データを挿入できます

2.8.7 ペアペアの作成

機能紹介:

ペアで表示されるデータの場合、ペア グループを使用すると 2 つのデータを返すことができます。最初のデータが 1 番目、2 番目のデータが 2 番目になります。

関数プロトタイプ:

pair<type, type> p ( value1, value2 );
pair<type, type> p = make_pair( value1, value2 );

例:

 //test func of pair
void test4() {
    
    
    pair<string, int> p(string("tom"), 20);
    cout << "name: " << p.first << " " << " age: " << p.second << endl;

    pair<string, int> p2 = make_pair("jerry", 10);
    cout << "name: " << p2.first << " " <<  " age: " << p2.second << endl;
}

2.8.8 コンテナのソートを設定する

 設定したコンテナのデフォルトのソートルールは小から大までであり、ファンクタを使用してソートルールを変更することができます
 データを入れた後にソート方法を指定することはできません ソート方法は作成時に指定する必要があります

例: MyCompare クラスを作成し、関数呼び出し演算子をオーバーロードし、セット コンテナーの作成時にクラス名を 2 番目のパラメーターとして使用します。

class myCompare{
    
    
public:
	bool operator()(int v1, int v2){
    
    
		return v1 > v2;
	}
};

set<int, myCompare>s1;
下面插入的时候就会按照从大到小排列


  
   

2.9 マップ/マルチマップコンテナ

C++STL マップ コンテナ: 非常に良い記事が見つかりました

(1) 地図の基本的な考え方

導入:

 マップ内のすべての要素はペアです。
 ペアの最初の要素はキー (キー値) のインデックスとして機能し、2 番目の要素は値 (値) です。すべての
 要素は要素のキー値に従って自動的に並べ替えられます

自然:

 map/multimap は連想コンテナであり、基礎となる構造はバイナリ ツリーで実装されます。

アドバンテージ:

キー値に従って値をすぐに見つけることができます

マップとマルチの違い:

マップはコンテナ内で重複するキー値要素を許可しません
マルチマップはコンテナ内で重複するキー値要素を許可します

他の

カスタム データ型の場合、マップはセット コンテナーと同じ照合順序を指定する必要があります。

(2) マップ共通機能

コンストラクタ

map<T1, T2> mp;		//map默认构造函数: 
map(const map &mp);	//拷贝构造函数

譲渡と交換

map& operator=(const map &mp);//重载等号操作符
swap(mp);			//交换两个集合容器

マップサイズの操作

size();//返回容器中元素的数目
empty();//判断容器是否为空

マップ挿入操作

4 番目の方法が推奨されないのはなぜですか?
 4 番目の方法を使用して存在しないキーを検索すると、新しいキーと値のペアが値 0 で自動的に作成されます。そのため、この方法で出力する場合は、次のようにする必要があります。キーと値のペアがすでに存在していることを確認してください

map.insert(...); 
	//往容器插入元素,返回pair<iterator,bool>
//1 map的四种插入方法
void MapInsert(map<int, int> &m) {
    
    
	//1 通过模板pair对组.返回一个对组对象.其中:对组对象的模板参1为:被插入容器的(此处为map)迭代器类型;模板参2为:布尔类型,用于判断是否插入成功.
	std::pair<map<int,int>::iterator,bool> pairIt = m.insert(std::pair<int,int>(1,1));
	if(pairIt.second == false){
    
    
		std::cout << "1 insert map failed" << std::endl;
		return;
	}

	//2 通过make_pair()函数.同样返回一个对组对象
	pairIt = m.insert(std::make_pair(2, 2));
	if (pairIt.second == false) {
    
    
		std::cout << "2 insert map failed" << std::endl;
		return;
	}

	//3 通过map模板类中的value_type()函数.同样返回一个对组对象
	pairIt = m.insert(map<int, int>::value_type(3, 3));
	if (pairIt.second == false) {
    
    
		std::cout << "3 insert map failed" << std::endl;
		return;
	}

	//4 下标法插入.注:map中,key不存在,以默认值0插入map;key存在,修改该key的值.
	m[4] = 4;
	m[5];//默认为0.
	std::cout << m[6] << std::endl;//下标打印时不存在的key会默认被初始化为0.且会被插入到map中

	//所以此时map中共有6个元素
}

消去

clear();//删除所有元素
erase(pos);//删除pos迭代器所指的元素,返回下一个元素的迭代器。
erase(beg,end);//删除区间[beg,end)的所有元素 ,返回下一个元素的迭代器。
erase(keyElem);//删除容器中key为keyElem的对组。

統計の検索

find(key);//查找键key是否存在,若存在,返回该键的元素的迭代器;
		  //若不存在,返回map.end();
count(keyElem);
		 返回容器中key为keyElem的对组个数。
		 对map来说,要么是0,要么是1。
		 对multimap来说,值可能大于1lower_bound(keyElem);//返回第一个key>=keyElem元素的迭代器。
upper_bound(keyElem);//返回第一个key>keyElem元素的迭代器。
equal_range(keyElem);//返回容器中key与keyElem相等的上下限的两个迭代器。

分類する

マップ コンテナーはデフォルトで昇順にソートされます。マップ コンテナーのソート方法を変更するにはファンクターを使用します。

class myCompare{
    
    
public:
	bool operator()(int v1, int v2){
    
    
			//降序:
			return v1 > v2;
			//升序
			//return v1 < v2;
	}
};
map<int, int, myCompare>m;//降序排列

おすすめ

転載: blog.csdn.net/Stanford_sun/article/details/122673045