シーケンシャルコンテナ
-
ベクター
-
Deque
-
リスト
-
単一リンクリスト(forward_list)(上記の4つは、論理的に拡張可能な長さの配列と見なすことができます)
-
アレイ
-
要素は直線的に配置されており、指定した位置でいつでも要素を挿入および削除できます。
-
Assignableの概念に準拠している必要があります(つまり、パブリックコピーコンストラクターがあり、「=」で割り当てることができます)。
-
配列オブジェクトのサイズは固定されており、forward_listには特別な追加および削除操作があります。
シーケンシャルコンテナのインターフェイス(単一リンクリスト(forward_list)と配列(array)は含まれません)
-
コンストラクタ
-
代入機能
- 割当
-
挿入機能
- insert、pushfront(listおよびdequeのみ)、pushback、emplace、emplace_front
-
削除機能
- 消去、クリア、ポップフロント(リストと両端キューのみ)、ポップバック、emplace_back
-
最初と最後の要素への直接アクセス
- フロント、バック
-
サイズを変更する
- サイズ変更
シーケンシャルコンテナの基本操作
#include <iostream>
#include <list>
#include <deque>
using namespace std;
//输出指定的顺序容器的元素
template <class T>
void printContainer(const char* msg, const T& s) {
cout << msg << ": ";
copy(s.begin(), s.end(), ostream_iterator<int>(cout, " "));
cout << endl;
}
int main() {
//从标准输入读入10个整数,将它们分别从s的头部加入
deque<int> s;
for (int i = 0; i < 10; i++) {
int x;
cin >> x;
s.push_front(x);
}
printContainer("deque at first", s);
//用s容器的内容的逆序构造列表容器l
list<int> l(s.rbegin(), s.rend());
printContainer("list at first", l);
//将列表容器l的每相邻两个元素顺序颠倒
list<int>::iterator iter = l.begin();
while (iter != l.end()) {
int v = *iter;
iter = l.erase(iter);
l.insert(++iter, v);
}
printContainer("list at last", l);
//用列表容器l的内容给s赋值,将s输出
s.assign(l.begin(), l.end());
printContainer("deque at last", s);
return 0;
}
/*
运行结果如下:
0 9 8 6 4 3 2 1 5 4
deque at first: 4 5 1 2 3 4 6 8 9 0
list at first: 0 9 8 6 4 3 2 1 5 4
list at last: 9 0 6 8 3 4 1 2 4 5
deque at last: 9 0 6 8 3 4 1 2 4 5
/*
シーケンシャルコンテナの特徴
-
シーケンスコンテナ:ベクトル、両端キュー、リスト、単一リンクリスト、配列
-
ベクター
-
容量(容量):実際に割り当てられたスペースのサイズ
-
s.capacity():現在の容量を返します
-
s.reserve(n):容量がn未満の場合は、容量が少なくともnになるようにsを展開します。
-
拡張可能な動的配列
-
ランダムアクセス、要素の挿入または削除を最後にすばやく
-
中央または頭の要素の挿入または削除が遅い
-
特徴
-
-
ベクトル容量
-
Deque
-
両端の要素をすばやく挿入または削除します
-
途中で要素を挿入または削除するのが遅い
-
ランダムアクセスは高速ですが、ベクターコンテナよりも低速です
-
特徴
-
パリティソート
#include<iostream>
#include<vector>
#include<deque>
#include<algorithm>
#include<iterator>
using namespace std;
int main() {
istream_iterator<int> i1(cin), i2; //建立一对输入流迭代器
vector<int> s1(i1, i2); //通过输入流迭代器从标准输入流中输入数据
sort(s1.begin(), s1.end()); //将输入的整数排序
deque<int> s2;
//以下循环遍历s1
for (vector<int>::iterator iter = s1.begin(); iter != s1.end(); ++iter)
{
if (*iter % 2 == 0) //偶数放到s2尾部
s2.push_back(*iter);
else //奇数放到s2首部
s2.push_front(*iter);
}
//将s2的结果输出
copy(s2.begin(), s2.end(), ostream_iterator<int>(cout, " "));
cout << endl;
return 0;
}
リスト
-
特徴
-
任意の位置での要素の挿入と削除は高速です
-
ランダムアクセスをサポートしていません
-
-
スプライス操作
- s1.splice(p、s2、q1、q2):s1のpが指す要素の前に、s2の[q1、q2)を移動します。
#include<iostream>
#include<string>
#include<list>
#include<iterator>
using namespace std;
int main() {
string names1[] = {
"Alice", "Helen", "Lucy", "Susan" };
string names2[] = {
"Bob", "David", "Levin", "Mike" };
//用names1数组的内容构造列表s1
list<string> s1(names1, names1 + 4);
//用names2数组的内容构造列表s2
list<string> s2(names2, names2 + 4);
//将s1的第一个元素放到s2的最后
s2.splice(s2.end(), s1, s1.begin());
list<string>::iterator iter1 = s1.begin(); //iter1指向s1首
advance(iter1, 2); //iter1前进2个元素,它将指向s1第3个元素
list<string>::iterator iter2 = s2.begin(); //iter2指向s2首
++iter2; //iter2前进1个元素,它将指向s2第2个元素
list<string>::iterator iter3 = iter2; //用iter2初始化iter3
advance(iter3, 2); //iter3前进2个元素,它将指向s2第4个元素
//将[iter2, iter3)范围内的结点接到s1中iter1指向的结点前
s1.splice(iter1, s2, iter2, iter3);
//分别将s1和s2输出
copy(s1.begin(), s1.end(), ostream_iterator<string>(cout, " "));
cout << endl;
copy(s2.begin(), s2.end(), ostream_iterator<string>(cout, " "));
cout << endl;
return 0;
}
単一リンクリスト(forward_list)
-
単一リンクリストの各ノードには、次のノードへのポインタしかないため、ノードの先行ノードを取得する簡単な方法はありません。
-
挿入、配置、および消去操作は定義されていませんが、insertafter、emplaceafter、およびerase_after操作が定義されています。パラメーターはリストの挿入、配置、および消去と同じですが、指定された要素を挿入または削除する代わりにイテレータp1によって、p1用になります。動作する要素の後のノードを参照します。
-
サイズ操作はサポートされていません。
アレイ
-
配列は組み込み配列のカプセル化であり、配列を使用するためのより安全で便利な方法を提供します
-
配列オブジェクトのサイズは固定されています。要素タイプを指定するだけでなく、定義時にコンテナサイズも指定する必要があります。
-
コンテナサイズを動的に変更することはできません
シーケンシャルコンテナの比較
-
STLが提供するシーケンシャルコンテナには、それぞれ長所と短所があります。プログラムを作成するときは、コンテナに対して実行する必要のある操作に基づいて、どのコンテナを選択するかを決定する必要があります。
-
多くのランダムアクセス操作を実行する必要があり、コンテナを展開するときにコンテナの最後に新しい要素を追加するだけでよい場合は、ベクトルコンテナベクトルを選択する必要があります。
-
少量のランダムアクセス操作が必要な場合は、コンテナの両端で要素を挿入または削除する必要があります。両端キューの両端キューを選択する必要があります。
-
コンテナへのランダムアクセスを実行する必要はないが、中央の位置で要素を挿入または削除する必要がある場合は、リストコンテナリストまたはforward_listを選択する必要があります。
-
配列が必要な場合、組み込みの配列型と比較して、配列の方が安全で使いやすい配列型です。
シーケンシャルコンテナ用のイテレータとアダプタを挿入します
シーケンシャルコンテナのイテレータを挿入します
-
コンテナのヘッド、テール、または中央の指定された位置に要素を挿入するためのイテレータ
-
フロントインサーター(フロントインサーター)、バックインサーター(バックインサーター)、任意の位置の挿入イテレーター(インサーター)を含む
list<int> s;
back_inserter iter(s);
*(iter++) = 5; //通过iter把5插入s末尾
シーケンスコンテナアダプター
いくつかの一般的に使用されるデータ構造は、シーケンシャルコンテナのカプセル化であるシーケンシャルコンテナに基づいて構築されます
-
スタック:最初にプッシュされた要素が最後にポップされます
-
キュー(キュー):最初に押された要素が最初にポップされます
-
優先キュー(priority_queue):「最大」要素が最初にポップされます
スタックとキューのテンプレート
- スタックテンプレート
template <class T, class Sequence = deque<T> > class stack;
- キューテンプレート
template <class T, class FrontInsertionSequence = deque<T> > class queue;
- スタックは、基本コンテナーとして任意の種類の順次コンテナーを使用でき、キューは、事前に挿入されたコンテナー(両端キューまたはリスト)の使用のみを許可します。
スタックとキューでサポートされる操作
-
s1 op s2 opは、==、!=、<、<=、>、> =のいずれかになり、辞書式順序で2つのコンテナーアダプター間の要素を比較します。
-
s.size()は、sの要素数を返します
-
s.empty()は、sが空かどうかを返します
-
s.push(t)は要素tをsにプッシュします
-
s.pop()は、sから要素をポップします。スタックの場合、毎回プッシュされる要素が最後にプッシュされる要素であり、キューの場合、毎回プッシュされる要素が最初にプッシュされる要素です。
-
イテレータは任意の要素へのアクセスを許可しないため、サポートされていません
スタックとキューでのさまざまな操作
スタック操作
- s.top()は、スタックの最上位要素への参照を返します
キュー操作
-
s.front()head要素への参照を取得します
-
s.back()テール要素の参照を取得します
スタックを使用して出力ワードを反転します
#include<iostream>
#include<stack>
#include<string>
using namespace std;
int main() {
stack<char> s;
string str;
cin >> str; //从键盘输入一个字符串
//将字符串的每个元素顺序压入栈中
for (string::iterator iter = str.begin(); iter != str.end(); ++iter)
s.push(*iter);
//将栈中的元素顺序弹出并输出
while (!s.empty()) {
cout << s.top();
s.pop();
}
cout << endl;
return 0;
}
/*运行结果如下:
congratulations
snoitalutargnoc*/
優先キュー
- 優先キューは、スタックやキューなどの要素のプッシュとポップもサポートしますが、要素がポップされる順序は要素のサイズに関連しており、各ポップは常にコンテナー内の「最大」要素です。
template <class T, class Sequence = vector<T> > class priority_queue;
-
優先キューの基本コンテナは、ランダムアクセスをサポートするシーケンシャルコンテナである必要があります。
-
スタックとキュー、サイズ、空、プッシュ、ポップのいくつかのメンバー関数をサポートし、使用法はスタックとキューと同じです。
-
優先キューは比較操作をサポートしていません。
-
スタックと同様に、優先度付きキューは、ポップされる次の要素(つまり、「最大」要素)への参照を取得するための最上位関数を提供します。
細胞分裂シミュレーション
細胞は生後500〜2000秒以内に2つの細胞に分裂し(つまり、最後の分裂)、各細胞は同じ法則に従って分裂し続けます。
#include<iostream>
#include<queue>
using namespace std;
const int SPLIT_TIME_MIN = 500; //细胞分裂最短时间
const int SPLIT_TIME_MAX = 2000; //细胞分裂最长时间
class Cell;
priority_queue<Cell> cellQueue;
class Cell {
//细胞类
private:
static int count; //细胞总数
int id; //当前细胞编号
int time; //细胞分裂时间
public:
Cell(int birth) : id(count++) {
//birth为细胞诞生时间
//初始化,确定细胞分裂时间
time = birth + (rand() % (SPLIT_TIME_MAX - SPLIT_TIME_MIN))+ SPLIT_TIME_MIN;
}
int getId() const {
return id; } //得到细胞编号
int getSplitTime() const {
return time; } //得到细胞分裂时间
bool operator < (const Cell& s) const //定义“<”
{
return time > s.time; }
void split() {
//细胞分裂
Cell child1(time), child2(time); //建立两个子细胞
cout << time << "s: Cell #" << id << " splits to #" << child1.getId() << " and #" << child2.getId() << endl;
cellQueue.push(child1); //将第一个子细胞压入优先级队列
cellQueue.push(child2); //将第二个子细胞压入优先级队列
}
};
int Cell::count = 0;
int main() {
srand(static_cast<unsigned>(time(0)));
int t; //模拟时间长度
cout << "Simulation time: ";
cin >> t;
cellQueue.push(Cell(0)); //将第一个细胞压入优先级队列
while (cellQueue.top().getSplitTime() <= t) {
cellQueue.top().split(); //模拟下一个细胞的分裂
cellQueue.pop(); //将刚刚分裂的细胞弹出
}
return 0;
}
/*
运行结果如下:
Simulation time: 5000
971s: Cell #0 splits to #1 and #2
1719s: Cell #1 splits to #3 and #4
1956s: Cell #2 splits to #5 and #6
2845s: Cell #6 splits to #7 and #8
3551s: Cell #3 splits to #9 and #10
3640s: Cell #4 splits to #11 and #12
3919s: Cell #5 splits to #13 and #14
4162s: Cell #10 splits to #15 and #16
4197s: Cell #8 splits to #17 and #18
4317s: Cell #7 splits to #19 and #20
4686s: Cell #13 splits to #21 and #22
4809s: Cell #12 splits to #23 and #24
4818s: Cell #17 splits to #25 and #26
*/