21- C++ STL アルゴリズム-9 (C++)

10.3 アルゴリズム

10.3.1 ソートアルゴリズム

10.3.1.1 sort() ソート関数

  • sort() 関数はクイックソートに基づいて実装されています。

  • sort() 関数は基礎となる実装によって制限されており、通常の配列と一部の種類のコンテナでのみ機能します。つまり、sort() 関数は、次の条件を満たす通常の配列およびコンテナーでのみ使用できます。

    • コンテナーによってサポートされる反復子の型は、ランダム アクセス反復子である必要があります。これは、sort() が 2 つのコンテナー (vector と deque) のみをサポートすることを意味します。

    • コンテナー内の指定された領域内の要素がデフォルトで昇順に並べ替えられる場合、要素タイプは <未満演算子をサポートする必要があります。同様に、標準ライブラリによって提供される他の並べ替え規則が選択されている場合、要素タイプは演算子もサポートする必要があります。ルールの基礎となる実装で使用される比較演算子

    • sort() 関数が並べ替えを実装する場合、コンテナ内の要素の格納場所を交換する必要があります。この場合、カスタム クラス オブジェクトがコンテナーに格納されている場合、コンストラクターと代入演算子のオーバーロードをクラス内にコピーする必要があります。

    • sort() のソートが不安定

#include <iostream>     // std::cout
#include <algorithm>    // std::sort
#include <vector>       // std::vector
using namespace std;
//以普通函数的方式实现自定义排序规则
bool mycomp(int i, int j) {
    return (i < j);
}
//以函数对象的方式实现自定义排序规则
class mycomp2 {
public:
    bool operator() (int i, int j) {
        return (i < j);
    }
};
int main() {
	int a[] = { 32, 71, 12, 45, 26, 80, 53, 33 };
    vector<int> myvector(a, a+8);
    //调用第一种语法格式,对 32、71、12、45 进行排序
    sort(myvector.begin(), myvector.begin() + 4); //(12 32 45 71) 26 80 53 33
    //调用第二种语法格式,利用STL标准库提供的其它比较规则(比如 greater<T>)进行排序
    sort(myvector.begin(), myvector.begin() + 4, greater<int>()); //(71 45 32 12) 26 80 53 33
   
    //调用第二种语法格式,通过自定义比较规则进行排序
    sort(myvector.begin(), myvector.end(), mycomp2());//12 26 32 33 45 53 71 80
    //输出 myvector 容器中的元素
    for (vector<int>::iterator it = myvector.begin(); it != myvector.end(); ++it) {
        cout << *it << ' ';
    }
    return 0;
}

10.3.1.2steady_sort ()ソートアルゴリズム

  • 安定した_sort()関数はマージソートに基づいて実装されています

  • steady_sort() は安定したソートアルゴリズムです

  • stack_sort() 関数は、sort() 関数と同じように使用されます。

10.3.1.3 Partial_sort() ソート関数

1. はじめに

  • このような状況を想定して、100万個の要素が入ったコンテナがあるのですが、最も値の小さい10個の要素だけを抽出したいのですが、どうすれば実現できるでしょうか?

    • これまでの学習を通じて、sort() またはsteady_sort() ソート関数の使用を考えることができます。つまり、コンテナーに格納されている 100 万個の要素をソートすることで、最小の 10 個の要素をフィルターで除外することができます。しかし、10 個の要素を抽出するためには、まず 100 万個の要素をソートする必要があり、この実装の効率は非常に低いと考えられます。

    • 同様の問題を解決するために、C++ STL 標準ライブラリでは、partial_sort() を使用したより効率的な解決策が提供されています。

  • 部分ソートは直訳すると「部分ソート」となり、指定した領域からデータの一部を抽出して並べ替えることができる機能です。

2. 文法形式

//按照默认的升序排序规则,对 [first, last) 范围的数据进行筛选并排序
void partial_sort (RandomAccessIterator first,
                   RandomAccessIterator middle,
                   RandomAccessIterator last);
//按照 comp 排序规则,对 [first, last) 范围的数据进行筛选并排序
void partial_sort (RandomAccessIterator first,
                   RandomAccessIterator middle,
                   RandomAccessIterator last,
                   Compare comp);
/*
其中,first、middle 和 last 都是随机访问迭代器,comp 参数用于自定义排序规则。
partial_sort() 函数会以交换元素存储位置的方式实现部分排序的。
具体来说,partial_sort() 会将 [first, last) 范围内最小(或最大)的 middle-first 个元素移动到 
[first, middle) 区域中,并对这部分元素做升序(或降序)排序。
*/

Partial_sort()関数は基礎となる実装によって制限されており、通常の配列と部分型コンテナーにのみ適用できることに注意してください。つまり、以下の条件を持つ通常の配列とコンテナのみが、partial_sort() 関数を使用できます。

  • Partial_sort() 関数は、array、vector、および dequeの 3 つのコンテナーにのみ適用できます。

  • デフォルトの昇順並べ替えルールが選択されている場合、コンテナに格納されている要素タイプは <未満演算子をサポートする必要があります。同様に、標準ライブラリによって提供される他の並べ替えルールが選択されている場合、要素タイプは、ルールの基礎となる実装。

  • Partial_sort() 関数の実装中に、特定の要素の格納場所を交換する必要があります。したがって、カスタム クラス オブジェクトがコンテナーに格納されている場合、クラスは移動コンストラクターと移動代入演算子を提供する必要があります。

#include <iostream>     // std::cout
#include <algorithm>    // std::partial_sort
#include <vector>       // std::vector
using namespace std;
//以普通函数的方式自定义排序规则
bool mycomp1(int i, int j) {
    return (i > j);
}
//以函数对象的方式自定义排序规则
class mycomp2 {
public:
    bool operator() (int i, int j) {
        return (i > j);
    }
};
int main() {
    vector<int> myvector{ 3,2,5,4,1,6,9,7};
    //以默认的升序排序作为排序规则,将 myvector 中最小的 4 个元素移动到开头位置并排好序
    partial_sort(myvector.begin(), myvector.begin() + 4, myvector.end());
    cout << "第一次排序:\n";
    for (vector<int>::iterator it = myvector.begin(); it != myvector.end(); ++it)
        cout << *it << ' ';
    cout << "\n第二次排序:\n";
    // 以指定的 mycomp2 作为排序规则,将 myvector 中最大的 4 个元素移动到开头位置并排好序
    partial_sort(myvector.begin(), myvector.begin() + 4, myvector.end(), mycomp2());
    for (vector<int>::iterator it = myvector.begin(); it != myvector.end(); ++it)
        cout << *it << ' ';
    return 0;
}

10.3.1.4 merge() 関数

機能: 2 つのソートされたシーケンスを 1 つのソートされたシーケンスにマージします。

デフォルトの照合順序:

//以默认的升序排序作为排序规则
OutputIterator merge (InputIterator1 first1, InputIterator1 last1,
                      InputIterator2 first2, InputIterator2 last2,
                      OutputIterator result);
//以自定义的 comp 规则作为排序规则
OutputIterator merge (InputIterator1 first1, InputIterator1 last1,
                      InputIterator2 first2, InputIterator2 last2,
                      OutputIterator result, Compare comp);
/*
* firs1t为第一个容器的首迭代器,last1为第一个容器的末迭代器;
* first2为第二个容器的首迭代器,last2为容器的末迭代器;
* result为存放结果的容器,comapre为比较函数(可略写,默认为合并为一个升序序列)。
*/

注: result を使用する場合、vector を使用する場合は、まずリサイズを使用して容量を拡張する必要があります

10.3.1.5 revrese() 関数

関数パラメータ: reverse(first、last)

機能: リバースコンテナ

知らせ:

  • string、vector、および deque は、テンプレート ライブラリ アルゴリズムの反転関数のみを使用できます。

  • リストはアルゴリズムとリスト クラスで逆を使用できます。

  • スタックとキューにはイテレータがないため、当然ながらアルゴリズムで reverse を使用できず、それらのクラスは reverse メンバー関数を提供しません。

  • set と map の要素はキー値に従って並べ替えられ、キー値を変更したり、元に戻すことはできません。

10.3.2 検索アルゴリズム

10.3.2.1隣接検索()

機能: イテレータペア識別要素の範囲内で隣接する繰り返し要素のペアを検索し、見つかった場合は要素ペアの最初の要素を指すイテレータを返します。

vector<int> vecInt;
vecInt.push_back(1);
vecInt.push_back(2);
vecInt.push_back(2);
vecInt.push_back(4);
vecInt.push_back(5);
vecInt.push_back(5);
 
vector<int>::iterator it = adjacent_find(vecInt.begin(), vecInt.end()); //*it == 2

10.3.2.2 binary_search()

機能: 二分探索メソッド。順序付けられたシーケンスで値を検索し、見つかった場合は true を返します。

set<int> setInt;
setInt.insert(3);
setInt.insert(1);
setInt.insert(7);
setInt.insert(5);
setInt.insert(9);
 
bool bFind = binary_search(setInt.begin(),setInt.end(),5);

10.3.2.3 count()

機能: 等号演算子を使用して、フラグ範囲内の要素を入力値と比較し、等しい数値を返します。

vector<int> vecInt;
vecInt.push_back(1);
vecInt.push_back(2);
vecInt.push_back(2);
vecInt.push_back(4);
vecInt.push_back(2);
vecInt.push_back(5);
int iCount = count(vecInt.begin(),vecInt.end(),2); //iCount==3

10.3.2.4 find()

機能: find() 関数は、指定された範囲内でターゲット要素と値が等しい最初の要素を検索するために使用されます。

関数の構文は次のとおりです。

InputIterator find (InputIterator first, InputIterator last, const T& val);

このうち、first と last は入力イテレータ、[first, last) は関数の検索範囲の指定に使用され、val は検索対象の要素です

first と last は入力反復子であるため、この関数はすべての連続したコンテナーで機能します。

この関数は入力反復子を返します。find() 関数の検索が成功すると、[first, last) 領域で見つかった最初のターゲット要素を指します。検索が失敗した場合、反復子は指すと last が同じになります。

find() 関数の基本的な実装は、演算子を使用して val 領域と [first, last) 領域内の要素を 1 つずつ比較することです。これは、範囲 [first, last) 内の要素が演算子をサポートする必要があることも意味します。

#include <iostream>     // std::cout
#include <algorithm>    // std::find
#include <vector>       // std::vector
using namespace std;
int main() {
    //find() 函数作用于普通数组
    char stl[] ="http://c.biancheng.net/stl/";
    //调用 find() 查找第一个字符 'c'
    char * p = find(stl, stl + strlen(stl), 'c');
    //判断是否查找成功
    if (p != stl + strlen(stl)) {
        cout << p << endl;
    }
    //find() 函数作用于容器
    vector<int> myvector{ 10,20,30,40,50 };
    vector<int>::iterator it;
    it = find(myvector.begin(), myvector.end(), 30);
    if (it != myvector.end())
        cout << "查找成功:" << *it;
    else
        cout << "查找失败";
    return 0;
}

10.3.2.5 find_if()

機能: find() 関数と同様に、find_if() 関数も指定された領域で検索操作を実行するために使用されます。違いは、前者では検索する要素の値を明示的に指定する必要があるのに対し、後者ではカスタム検索ルールが許可されることです。

#include <iostream>     // std::cout
#include <algorithm>    // std::find_if
#include <vector>       // std::vector
using namespace std;

//以函数对象的形式定义一个 find_if() 函数的查找规则
class mycomp2 {
public:
    bool operator()(const int& i) {
        return ((i % 2) == 1);
    }
};
int main() {
    vector<int> myvector{ 4,2,3,1,5 };
    //调用 find_if() 函数
    vector<int>::iterator it = find_if(myvector.begin(), myvector.end(), mycomp2());
    cout << "*it = " << *it;
    return 0;
}

10.3.2.5検索()

関数: search() 関数は、シーケンス A 内で最初に出現するシーケンス B を検索するために使用されます。

たとえば、次の 2 つのシーケンスを考えてみましょう。

シーケンス B がシーケンス A に 2 回出現していることがわかります。search() 関数を使用すると、シーケンス A の最初の {1,2,3} を見つけることができます。

search() 関数は、次の 2 つの構文形式を提供します。

//查找 [first1, last1) 范围内第一个 [first2, last2) 子序列
ForwardIterator search (ForwardIterator first1, ForwardIterator last1,
                        ForwardIterator first2, ForwardIterator last2);
//查找 [first1, last1) 范围内,和 [first2, last2) 序列满足 pred 规则的第一个子序列
ForwardIterator search (ForwardIterator first1, ForwardIterator last1,
                        ForwardIterator first2, ForwardIterator last2,
                        BinaryPredicate pred);

このうち、各パラメータの意味は次のとおりです。

  • first1, last1: 両方とも前方反復子であり、組み合わせ [first1, last1) は検索範囲 (つまり、上記の例ではシーケンス A) を指定するために使用されます。

  • first2, last2: どちらも前方反復子であり、組み合わせ [first2, last2) を使用して検索するシーケンス (つまり、上の例ではシーケンス B) を指定します。

  • pred: ルックアップ ルールをカスタマイズするために使用されますこのルールは実際には 2 つのパラメーターと bool の戻り値を持つ関数です (最初のパラメーターは範囲 [first1, last1) の要素を受け取り、2 番目のパラメーターは範囲 [first2, last2)] の要素を受け取ります。関数定義の形式は、通常の関数または関数オブジェクトにすることができます。

search() 関数は前方反復子を返します。関数の検索が成功すると、反復子は見つかったサブシーケンスの最初の要素を指します。それ以外の場合、検索が失敗した場合、反復子は同じ last1 反復子を指します。

#include <iostream>     // std::cout
#include <algorithm>    // std::search
#include <vector>       // std::vector
using namespace std;
//以普通函数的形式定义一个匹配规则
bool mycomp1(int i, int j) {
    return (i%j == 0);
}
//以函数对象的形式定义一个匹配规则
class mycomp2 {
public:
    bool operator()(const int& i, const int& j) {
        return (i%j == 0);
    }
};
int main() {
    vector<int> myvector{ 1,2,3,4,8,12,18,1,2,3 };
    int myarr[] = { 1,2,3 };
    //调用第一种语法格式
    vector<int>::iterator it = search(myvector.begin(), myvector.end(), 
    myarr, myarr + 3);
    if (it != myvector.end()) {
        cout << "第一个{1,2,3}的起始位置为:" << it - myvector.begin() << ",*it = " << *it << endl;
    }
    int myarr2[] = { 2,4,6 };
    //调用第二种语法格式
    it = search(myvector.begin(), myvector.end(), 
    myarr2, myarr2 + 3, mycomp2());
    if (it != myvector.end()) {
        cout << "第一个{2,3,4}的起始位置为:" << it - myvector.begin() << ",*it = " << *it;
    }
    return 0;
}

おすすめ

転載: blog.csdn.net/March_A/article/details/132053290