ホームに戻る
STL(vector)
/*
*
* STL(vector)
*
* C++では配列をポインタで扱うのではなく、
* vectorでイテレータを使うほうが安全であり推奨されています。
*
* vector は要素が増えるとメモリ領域を勝手に拡張する。
* そのやり方は確保したメモリを超える要素の追加があった場合
* 必要量のおよそ2倍の容量を再確保しコピーする方法である。
*
* 宣言
*
* vector<A> v; // サイズは 0
*
* サイズを調べる
*
* v.size(); // メモリのサイズではなく 要素数である
*
* 確保できる要素数を調べる
*
* v.max_size(); // 確保できる最大要素数を返す
*
* メモリが確保された要素数を調べる
*
* v.capacity(); // メモリが確保されている要素数
*
* 最後尾に要素を追加
* 内部でコピーコンストラクタを呼ぶ。
* 追加された要素は vector の終了時に安全に開放される。
* ただし、要素がポインタの vector に new したオブジェクトのポインタを入れる場合は
* vector の終了前に delete を呼んでおく必要がある。
* vector においては最後尾への要素の追加は高速である。
*
* v.push_back(a); // vector に要素を追加
*
* 要素とメモリの確保のされかた
*
* vector<A> v; // size=0 capacity=0
* v.push_back(a); // size=1 capacity=1
* v.push_back(a); // size=2 capacity=2
* v.push_back(a); // size=3 capacity=4
* v.push_back(a); // size=4 capacity=4
* v.push_back(a); // size=5 capacity=8
*
* サイズの変更 要素数をリサイズする
*
* 要素が少なくなる場合は要素を削除
* 要素が多くなる場合はディフォルトコンストラクタの値をコピーコンストラクタでコピー。
* メモリが足りない場合はリサイズの容量を再確保して増量。
*
* v.resize(15);
*
* メモリの予約
* 要素を1つずつ追加する場合、メモリの再確保が頻回に発生する。
* よって事前に capacity の量を予約することができる。
* すでに中身が存在する場合には新たな領域を再確保し、
* すでにある要素をコピーコンストラクタでコピーする。
*
* v.reserve(100); // capacity = 100
*
* メモリを切り詰める
* いちど確保したメモリのサイズを簡単に縮める方法は無い
* よって以下のようなトリッキーな方法を使う。
*
* vector(v).swap(v); // 新しい vector を作成し要素を swap する
*
* メモリが空かどうかを調べる
*
* v.empty(); // 空の場合 true を返す
*
* 要素のクリア (要素数を 0 にする メモリは解放しない)
* メモリを切り詰めたい場合は新たに生成した vector にコピーするしかない
*
* v.clear(); // size=0
*
* 要素の削除
* 削除で抜けた部分はコピー代入演算子によって前に詰められる。
* 末尾を削除すると切り詰めが発生しないので能率が良い。
* 複数の削除はループで1つ1つ削除するより範囲削除のほうが良い。
*
* v.earse(v.begin(), v.begin() + 2); // 先頭の2つの要素を削除
* v.erace(v.begin() + 1); // 先頭の次の要素を削除
*
* 要素の挿入 (考え方は削除と同じ)
*
* v.insert(v.end(), v1.begin(), v1.end()); // v の最後に v2 を挿入
*
* 要素の代入
* 代入先は内部でいったんクリアされるので注意
*
* v.assign(v1.begin(), v1.begin() + 2); // v1 の先頭の2つの要素を v に代入
*
* 要素で埋める
*
* fill(v1.begin(), v1.end(), A()); // すべての要素を A() で埋める。
*
* ソート
* オブジェクトの場合何をもって大きいとするかを定義する関数が必要である。
*
* bool greater(const A &a, const A &b){ // あらかじめ定義する関数
* return a.getNum() > b.getNum();
* }
*
* sort(v.begin(), v.end(), greater);
*
* 部分ソート
* 全体をソートするが正しい結果は指定した範囲にしか入らない。
* 例えば10個の大きな要素を得たい場合に、最大要素が4個で次の要素が8個あった場合、
* 最大要素4個の次に並ぶ次の要素は2個だけ切り捨てられてしまう。
* このときの基準を知りたいところだが、ユーザーには不明である。
*
* partial_sort(v.begin(), v.begin() + 10, v.end(), greater); // 全体をソートするが結果は先頭10個だけ
*
* nth_element
* 部分ソートに似ているが要素を集めるだけでソートしない。
*
* nth_element(v.begin(), v.begin() + 10, v.end(), greater); // 部分ソートに似ているが順番がバラバラ
*
* 要素の分割
* ある条件の要素を前半、それ以外を後半で分割する。
* 分割後の前半の最後のイタレーターを返す。
*
* bool greater3(const A &a){ // あらかじめ定義する関数
* return a.getNum() > 3;
* }
*
* v.erase(partition(v.begin(), v.end(), greater3), v.end()); // 3 以下の要素は削除
*
* 要素の移動
* ある条件の要素以外を前半に移動する。
* 移動後の前半の最後のイタレーターを返す。
*
* v.erase(remove_if(v.begin(), v.end(), greater3), v.end()); // 3 以下の要素を残す
*
* ランダムシャッフル
*
* random_shuffle(v.begin(), v.end());
*
* 計数 条件に合う要素数を返す
*
* count_if(v1.begin(), v1.end(), greater3);
*
* 配列との互換性
*
* v[1] や &v[0] のようにアクセス可能である。
*
*/
#include <iostream>
#include <vector>
#include <algorithm>
class A{
int num;
public:
A(int n = 0){this->num = n;};
void setNum(const int n){this->num = n;}
const int &getNum() const {return this->num;}
};
bool greater(const A &a1, const A &a2){
return a1.getNum() > a2.getNum();
}
bool greater3(const A &a){
return a.getNum() > 3;
}
using namespace std;
void print(vector<A> &v){
cout << "size=" << v.size() << " capacity=" << v.capacity() << endl;
for(vector<A>::iterator i = v.begin(); i != v.end(); i++){
cout << (*i).getNum() << " ";
}
cout << endl;
}
int main(int argc, char* argv[])
{
vector<A> v;
v.reserve(9);
v.push_back(A(5));
v.push_back(A(2));
v.push_back(A(3));
v.push_back(A(7));
v.resize(7);
print(v);
v.erase(remove_if(v.begin(), v.end(), greater3), v.end());
print(v);
sort(v.begin(), v.end(), greater);
print(v);
vector<A>(v).swap(v);
print(v);
v.clear();
print(v);
return 0;
}
結果
size=7 capacity=9
5 2 3 7 0 0 0
size=5 capacity=9
2 3 0 0 0
size=5 capacity=9
3 2 0 0 0
size=5 capacity=5
3 2 0 0 0
size=0 capacity=5