STL (Standard Template Library) 上級プログラミング vector vector • • • • • #include <vector> が必要 可変長配列 (動的にメモリが確保される) 通常の配列と同様にメモリ上に連続した領域が確保される 超便利! → 今後は積極的に使おう!!! 配列の動的確保で必要なメモリ管理をvectorまかせに出来る <vector オブジェクトの宣言方法> (例1) int 型の vector オブジェクト xvec を宣言 vector<int> xvec; (例2) stringクラスのvectorオブジェクト vst を宣言 vector<string> vst; (例3) 自作クラス myClass のvector オブジェクト mc を宣言 vector<myClass> mc; • C++の非常に便利なクラステンプレート集 • ヘッダーファイルのincludeで即座に使える • CでなくC++を使う理由はSTLがあるからといっ ても過言ではない • vector も STL に含まれる vectorのコンストラクタ 以下では T のところに int, double, string, 自作クラス名 などが入ると思えばよい. • vector<T>() 中身が空の T 型 vector オブジェクトを生成 • vector<T>(size_type num) 大きさが num の T 型 vector オブジェクトを生成 ※ size_type は必ず0以上の値を取る整数型だと思えばよい • vector<T>(const vector<T>& vin) vinと全く同じ内容の T 型 vector オブジェクトを生成 (コピーコンストラクタ) ※ vector のコンストラクタは上記3つだけではない! vectorの主要メンバ関数 以下では T のところに int, double, string, 自作クラス名 などが入ると思えばよい. • push_back(const T& data) dataを末尾に追加する • size() 現在確保されている領域のサイズを返す 戻り値は size_type 型である • clear() 現在確保されている領域を全て解放する • operator[] (演算子のオーバーロード) 通常の配列と同様な要素アクセスを可能とする ・pop_back() 末尾のデータを削除する サンプルコード #include <iostream> #include <vector> using namespace std; int main(){ // int型のvectorオブジェクトを宣言 vector<int> xvec; int num; 実行例 % ./a.out 3 5 -4 0 1 -7 9 15 1st: xvec.size() = 3 5 -4 0 1 -7 9 15 2nd: xvec.size() = 3rd: xvec.size() = % // データを繰り返し入力 while(cin >> num){ xvec.push_back(num); // push_back を使ってデータを順次追加 } // データ数をとりあえず見てみる. cout << "1st: xvec.size() = " << xvec.size() << endl; for(unsigned int i = 0; i < xvec.size(); ++i){ cout << xvec[i] << " "; // operator[]によって配列同様の要素アクセス } cout << endl; xvec.pop_back(); // 末尾のデータを削除 // 削除後にデータ数がどうなっているか確認 cout << "2nd: xvec.size() = " << xvec.size() << endl; xvec.clear(); // 全データ削除 cout << "3rd: xvec.size() = " << xvec.size() << endl; return 0; } vector オブジェクトと関数の関係 • vectorオブジェクトは関数の引数に出来る (重要事項) 関数の中でvectorオブジェクトが変更されないとしても 積極的に参照引数を使おう! (理由) 参照引数を使うことでメモリ効率が向上するため (例1) 関数の中で xvec が変更されないとき void func(const vector<double>& xvec); // vector<double> xvec でも問題なく動作するがメモリを無駄に消費する (例2) 関数の中で xvec が変更されるとき(これまで通りの使用法) void func(vector<double>& xvec); • vectorオブジェクトは関数の戻り値の型として使える (vectorオブジェクトを返せる) (例3) 関数の中で生成したvectorオブジェクトを返す場合 vector<double> func(const int num){ // 引数は何でもOK! vector<double> avec; //(avecを使った処理) return avec; } #include <iostream> #include <vector> using namespace std; サンプルコード // データ入力のための関数(xvecは変更される) void input(vector<int>& xvec){ for(int i = 0; i < 6; ++i){ xvec.push_back(i * i); } } // データ出力のための関数(xvecは変更されない) void output(const vector<int>& xvec){ for(unsigned int i = 0; i < xvec.size(); ++i){ cout << xvec[i] << " "; 実行例 } % ./a.out cout << endl; 0 1 4 9 16 25 } % int main(){ vector<int> xvec; input(xvec); // vectorオブジェクト名をそのまま書く output(xvec); // こちらも input と同様にそのまま書く return 0; } 2 9 2 8 0 vectorと配列との関係 • 関数の引数として配列の先頭アドレスなどが要求される場合も vectorを使用可能! (理由1) vector<T>オブジェクトの中身は, 通常の T 型変数で構成されているため (理由2) 通常の配列と同様に,メモリ上で連続した 領域が確保されることが保証されているため (例1) 関数の引数が double* 型を要求している場合 void func(double* avec); // 関数宣言 // vector<double> bvec を使う場合(main関数等における呼び出し) func(&bvec[0]); // bvec[0]はvectorの中身の先頭を意味するため, // &bvec[0]は配列の先頭アドレスとなる 配列 vs. vector • どちらを使っても同様の処理は可能 • new と [ ] を使って配列を動的に確保する場合, メモリ管理を作成者が行う必要あり → 必ず delete [ ] によって解放するのは意外に大変 → vector にメモリ管理を任せれば, 自分がメモリ管理することから解放される! ※ 単にbvecと書いた場合,配列の先頭アドレスにはならない 2次元配列のようなvectorオブジェクト • vector<T> の T に,再度 vector<T> を入れることで,2 次元配列のようなvector オブジェクトを生成可能 (例) double 型の場合 vector<vector<double> > aMat; ここの空白は必ず必要! #include <iostream> #include <vector> using namespace std; サンプルコード 実行例 % ./a.out Input 1-th row --> 5 Input 2-th row --> 2 7 int main(){ Input 3-th row --> 1 0 4 vector<vector<double> > aMat; Input 4-th row --> 9 2 8 4 vector<double> aRow; // 行の入力用 Input 5-th row --> 7 3 0 9 1 for(int i = 0; i < 5; ++i){ 5 cout << "Input “ << i + 1 2 7 << "-th row --> "; 1 0 4 for(int j = 0; j < i + 1; ++j){ 9 2 8 4 int num; 7 3 0 9 1 cin >> num; // データの入力 aRow.push_back(num); // データを順次追加 % } aMat.push_back(aRow); // aMatの要素は vector<double> なのでaRowを入れる aRow.clear(); // 次の行のデータを入れるためにclearしておく } // 入力された結果の表示 for(unsigned int i = 0; i < aMat.size(); ++i){ for(unsigned int j = 0; j < aMat[i].size(); ++j){ cout << aMat[i][j] << " "; } cout << endl; } return 0; } algorithm ヘッダーに含まれる sortを使ってvectorオブジェクトをソート • vector<int>, vector<double>, vector<char> などの 基本型のvector オブジェクトをソート 1. sort(xvec.begin(), xvec.end()); ※ begin() と end() は「イテレータ」に関係するものである (イテレータに関して,ここでは深入りしないことにする) • vector<myClass> のように自作クラスのvector オブジェクトをソート 1. myClass において, bool operator<(const myClass&) const; を適切に定義する(重要事項:最後のconstは必ず必要!) → myClass において何を基準に大小関係を決定するかを定義する 2. sort(xvec.begin(), xvec.end()); ※ sortを使うためには「#include <algorithm>」を書く必要有り 自作クラスのオブジェクトを vectorオブジェクトにpush_back • 先に自作クラスのオブジェクトを作ってから push_backする方法 (例) myClass temp(’A’, 3); vector<myClass> obj; obj.push_back(temp); • コンストラクタを利用してpush_backする方法 (例) vector<myClass> obj; obj.push_back( myClass(’A’, 3) );
© Copyright 2025 ExpyDoc