C++Primer 5 th Chap 10 Generic Algorithms(未完)

13966 ワード

ほとんどのアルゴリズム定義はヘッダファイルalgorithmであり、ヘッダファイルnumericで数値汎用アルゴリズムが定義されている.
findアルゴリズムを例にとると、コンテナの2つの反復器で指定された範囲を巡り、特定の値を検索します.
 1 int val=44; 2 auto result=find(ivec.begin(),ivec.end(),val); 3 cout< 
反復器はアルゴリズムをコンテナに依存させないが、アルゴリズムは要素タイプの操作に依存する.
アルゴリズムはコンテナの操作を実行せず、反復器の操作のみを実行します.
読み取り専用アルゴリズム:
範囲内の要素のみが読み込まれ、要素は変更されません.
findアルゴリズムに加えて、たとえばaccumulateアルゴリズム(numericヘッダファイルで定義)は、範囲内の要素の和+を返して初期値を指定します.
    cin>>sum;
    accumulate(ivec.cbegin(),ivec.cend(),sum);(stringタイプの場合はstringを接続します)
読み取り専用アルゴリズムの場合は、反復器としてcbeginとcendを選択することが望ましい.
2つのシーケンスを操作するアルゴリズムequalを例に挙げます.(2つのシーケンスのすべての対応する要素が同じ場合はtrueを返し、そうでなければfalseを返します)
    equal(ivec1.cbegin(),ivec1.cend(),ivec2.cbegin());
equalアルゴリズムでは、==で比較できる限り、2つのシーケンス要素のタイプが厳密に一致する必要はありません.
この例に基づいて、2番目のシーケンスのみを与える単一反復器のアルゴリズムでは、2つのシーケンスが等長であると仮定する(少なくとも1番目より短くはならない).
書き込み要素アルゴリズム:
コンテナ自体のサイズが書き込み要素の数より少なくとも小さくないことを確認する必要があります(アルゴリズムはコンテナのサイズを変更できないため)
例えば、fill(ivec.begin()、ivec.end(),val);コンテナの各値をvalに割り当てる
     fill_n(ivec.begin(),ivec.size(),val);コンテナの各値をvalに割り当てる
注:空のコンテナにfill_を使用する場合n長さを指定するとエラーが発生します
  back_Inserter(iteratorヘッダファイルで定義)
コンテナの末尾に要素を追加するために使用される反復器
     1 vector ivec; 2 auto it =back_inserter(ivec); 3 *it=23; 
これにより、コンテナの末尾に要素が追加され、値は23です.
結合fill_n使用:(val値の要素をivecに10個追加)
     1 vector ivec; 2 fill_n(back_inserter(ivec),10,val); 
コピーアルゴリズム:
       1 auto ret=copy(begin(arr1),end(arr1),arr2); 
このようにarr 1シーケンスの値をarr 2にコピーし(arr 2は少なくともarr 1と等長であることが要求される)、end(arr 2)を返す
copyアルゴリズムと同様に、replaceもこのような置換効果を備えています.
     1 replace(ilst.begin(),ilst.end(),search_value,new_value); 
これによりilstシーケンスのすべての値がsearch_になります.valueの要素はnew_に割り当てられますvalue
元のシーケンスを変更しない場合は、要素を置換したシーケンスを別のコンテナに保存します.
     1 replace_copy(ilst.begin(),ilst.end(),back_inserter(ivec),search_value,new_value);
このようにreplace_を借りてcopy関数とback_Inserterは新しいilstをivecに保存し、元のilstは変わらない
要素の再配置アルゴリズム:
  
 1 #include
 2 #include
 3 #include
 4 #include
 5 #include<string>
 6 #include
 7 using namespace std;
 8 void elimDups(vector<string> &vec){
 9     //          
10     sort(vec.begin(),vec.end());
11     //  unique      ,              
12     //
13     auto end_unique=unique(vec.begin(),vec.end());
14     //  erase         
15     vec.erase(end_unique,vec.end());
16 }
17 int main(){
18     string str;
19     vector<string> svec;
20     while(getline(cin,str)){
21         svec.push_back(str);
22     }
23     for(const auto &i:svec){
24         cout<" ";
25     } 
26     elimDups(svec);
27     cout<<endl;
28     for(const auto &j:svec){
29         cout<" ";
30     }
31     
32 }
33 /*output:
34 the
35 quick
36 red
37 fox
38 jumps
39 over
40 the
41 slow
42 red
43 turtle
44 ^Z
45 the quick red fox jumps over the slow red turtle
46 fox jumps over quick red slow the turtle*/

カスタムアクション:
例えばsortに3番目のパラメータを受け入れさせ、このパラメータは述語(呼び出し可能な式、戻り値は条件とすることができる)であり、元のsortは
  
1 bool isShorter(const string &s1,const string &s2){
2     return  s1.size()<s2.size();}
3 sort(svec.begin(),svec.end(),isShorter);

ここでは、辞書順ではなく長さで文字列を比較します.
等しい文字列を辞書順に比較する場合は、次のようになります.
 1 void elimDups(vector<string> &vec){
 2     //          
 3     sort(vec.begin(),vec.end());
 4     //  unique      ,              
 5     //
 6     auto end_unique=unique(vec.begin(),vec.end());
 7     //  erase         
 8     vec.erase(end_unique,vec.end());
 9 }
10 int main(){
11     elimDups(svec);
12     stable_sort(svec.begin(),svec.end(),isShorter);
13     }

述語を提供するstable_を使用します.sort関数は、等長の要素間の辞書シーケンスを維持します.
Lambda式:(c++11)形式:[capture list](parameter list)->return type{function body}
ここでcapture listは、関数で定義されているローカル変数のリストです(通常は空です).
呼び出しオブジェクトを作成するときに、リスト(パラメータが空の場合に相当)と戻りタイプ(関数ボディに戻り文が存在しない限り、デフォルトはvoid)を省略できます.
     1 auto f = [ ]{return 23;};   f(); 
通常の関数とは異なり、lambdaにはデフォルトのパラメータはありません.
たとえば、上記isShorter関数に等価なlambda:
               [](const string &s1,const string &s2){  return s1.size() 
[]内は空です.lambdaは関数内のローカル変数を使用しません.
capture listが空でない場合、関数体はcapture listの変数を使用できます.
     [sz](const string&s1){ return s1.size() 
完全なbiggies関数:find_を含むif関数とfor_each関数
 void biggies(const string &s1,const string::size_type sz){
    elimDups(svec);
    stable_sort(svec.begin(),svec.end(),[](const string &s1,const string &s2){
        return s1.size()<s2.size();});
    auto wc=find_if(svec.begin(),svec.end(),[sz](const string &s){
        return s.size()>=sz});
    auto count = svec.end()-wc;
    for_each(wc,svec.end(),[](const string &s){cout<' ';});
    }

ここでfind_if関数は、所与のパラメータszよりも長い最初の要素を指す反復器を返す
ここでfor_each関数は呼び出し可能なオブジェクトを受け入れ、出力シーケンスの各要素がこのオブジェクトを呼び出す
Lambdaのキャプチャとリターン:
lambdaを定義するたびに、コンパイラは名前のないクラスタイプを自動的に生成します.
関数にlambdaを渡すたびに、新しいタイプとそのタイプのオブジェクトが定義されます.
関数呼び出しパラメータと同様にlambdaのcapture listは値キャプチャであっても参照キャプチャであってもよい(その効果は関数パラメータと変わらない)
(注意:リファレンスキャプチャまたはポインタキャプチャはできるだけ避け、必要に応じてlambdaが呼び出されたときにキャプチャされたオブジェクトの値が有効であることを確認する必要があります)
明示的なキャプチャに対応して、暗黙的なキャプチャを使用することもできます.
[=]は暗黙的な値取得を表し、[&]は暗黙的な参照取得を表す
[=,&]は呼び出し順で、1つ目は値取得、2つ目は参照取得を表します(残りの組合せはこのようにします).
可変lambda:
取得した変数の値を変更するには、パラメータリストの先頭にキーワードmutableを付ける必要があります.
     auto f = [sz] () mutable{return++sz;};可変lambdaのパラメータリストは省略できます
Lambdaの戻りタイプを指定します.
例:transform(ivec.begin()、ivec.end(),ivec.begin(),[](int i)->int{return i<0?i:-1});  
ここでtransform関数は、元のシーケンスの各要素の値を絶対値に置き換えます(最初のパラメータと3番目のパラメータは同じ==呼び出しと入力シーケンスの最初は同じ位置です).
以上、lambdaの使用方法について説明したが、一般的に簡単な操作はlambdaを使用するのに適しており、複雑で繰り返しの操作であれば関数を呼び出すのが適切である.
パラメータバインド:
標準ライブラリbind関数:(c++11)(ヘッダーファイルfunctional)
関数を書き,lambdaの代わりにこの関数を用いることを望む場合,bindを用いてszパラメータへの伝達パラメータの問題を解決する
bindを呼び出すフォーマット:auto newCallable=bind(callable,args_list);
(args_listに_1,_2などの名前が含まれている場合、newCallableの対応する位置を表すパラメータ)
具体的な使用例:
1 bool check_size(const string &s1,string::size_type sz){
2     return s1.size()>=sz;}
3 auto check2=bind(check_size,_1,2);

ここで1 check 2を表す最初のパラメータ(唯一)は(check_sizeの最初のパラメータ)const string&、2はsz=2を表す
check 2:string str="HELL"を呼び出します.  bool b2=check2(str);(check_size(str,6)の呼び出しと同等)
bind文はlambdaの代替品として使用できます
上記の文の中で名前のようです_1,_2など使用する前に名前空間を宣言する必要があります:using std::placeholders:1;などの文
(using namespace std::placeholders;)
bindパラメータと関数の関係:
    auto g=bind(f,a,b,_2,c,_1);
g(_1,_2)を呼び出す.呼び出しf(a,b,_2,c,_1)に等しい.
(呼び出しg(X,Y)が呼び出しf(a,b,Y,c,X)に等しい場合)
bindに参照パラメータparameterを渡す場合は、ref(parameter)またはcref(parameter)を使用する必要があります.
 
反復器再プローブ:
反復の挿入:
サポートされるアクション:it=t;itで指定された位置に値tを挿入する
    back_inserter(value);push_を使用する作成backの反復器
    front_inserter(value);push_を使用する作成frontの反復器
    inserter(value,pos);pos反復器の前の位置にvalueの値を持つ要素を挿入
    
 
    
 
 
    
 
転載先:https://www.cnblogs.com/hfut-freshguy/p/11556707.html