四、c++中的算法--非修改序列算法(非变易算法)

来源:互联网 发布:淘宝闲鱼怎么搜索 编辑:程序博客网 时间:2024/06/11 14:10

四、c++中的算法

标签(空格分隔): c++STL


简介

1.stl的算法一般采用“覆盖(overwrite)”模式而不是“安插(insert)”模式。调用时目标区间必须拥有最够的元素空间。
2.可以传递自定的函数

函数设计的通用:

  • 使用模板了提供通用类型
  • 使用迭代器访问容器

算法库:

  • 非修改式序列算法:不改动容器中元素的次序和值,一般通过input迭代器和forward迭代器完成工作;
  • 修改式序列算法:一般不直接更改元素值或者在复制到另一区间的过程中改变元素值,此算法还包括溢出性质和删除性质的算法。移除一般只是在逻辑上“移除”元素,不改变容器大小和容器中的元素个数。“移除”和“删除”是不同的算法。
  • 排序和相关算法:包含多个排序函数和其他各种函数,包括集合操作等。不能以关联容器作为目标,因为关联容器元素被视为常数,不能变更。
  • 通用数字算法: 一般包括将区间的内容累计,内部乘积,小计,计算相邻对象差等函数。

1.非修改序列算法

不需要使用循环而从序列中寻找出某些东西的基本工具。不会改变序列次序和元素值。

  • for each 算法
  • 元素计数算法
  • 最小值和最大值算法
  • 搜寻算法
  • 区间比较算法

1.for each算法

定义:

for_each(Iterator begin, iterator end , proc op)

for_each 实现对区间[begin,end]中每个元素均调用进程op.

1.最普通的使用for_each算法

template<class T>void InsertValue(T & vec, int first, int last){    if (last > first){        for (int i = first; i < last;++i)            vec.insert(vec.end(), i);    }    else    {        cout << "last<first!" << endl;    }}void printItem(int elem){    cout << elem << "   ";}int main(){    vector<int > vec;    InsertValue(vec, 1, 10);    for_each(vec.begin(),vec.end(), printItem);    cout << endl;}

输出结果为:

1 2 3 4 5 6 7 8 9

2.for_each 中使用仿函数

仿函数:就是一个类使用时对象调用函数,又称为函数对象。其实现类中包含函数operator(),这个类就有了类似函数的行为。是stl六大组件(容器,配置器,迭代器,算法,配接器,仿函数)之一。
接下来使用自定义仿函数:Multiple<T>()

for_each(begin,end, Multiple<int>())

例子:

template<class T>void InsertValue(T & vec, int first, int last){    if (last > first){        for (int i = first; i < last;++i)            vec.insert(vec.end(), i);    }    else    {        cout << "last<first!" << endl;    }}void printItem(int elem){    cout << elem << "   ";}template<class T>class Multiple {private:    T value;public:    Multiple(const T & t) :value(t){}    void operator()(T& elem) const{        elem *= value;    }};int main(){    vector<int > vec;    InsertValue(vec, 1, 10);    for_each(vec.begin(),vec.end(), printItem);    cout << endl;    for_each(vec.begin(), vec.end(), Multiple<int>(2));  //每个元素乘以2    for_each(vec.begin(), vec.end(), printItem);    cout << endl;}

结果为:

1   2   3   4   5   6   7   8   92   4   6   8   10   12   14   16   18

3.for_each的返回值

函数原型为:

template< class InputIt, class UnaryFunction >UnaryFunction for_each( InputIt first, InputIt last, UnaryFunction f );

例子:

template<class InputIt, class UnaryFunction>UnaryFunction for_each(InputIt first, InputIt last, UnaryFunction f){    for (; first != last; ++first) {        f(*first);    }    return f;}

例子:

//前面的部分省略class SUM{private:    long sum_d; public:    SUM() :sum_d(0){}    void operator()(int elem){        sum_d += elem;    }    operator double(){        return static_cast<double>(sum_d);    }};int main(){    vector<int > vec;    InsertValue(vec, 1, 10);    for_each(vec.begin(),vec.end(), printItem);    cout << endl;    for_each(vec.begin(), vec.end(), Multiple<int>(2));  //每个元素乘以2    for_each(vec.begin(), vec.end(), printItem);    cout << endl;    double sum = for_each(vec.begin(), vec.end(), SUM());    cout << "sum: "<<sum<<endl;}

输出结果为:

1   2   3   4   5   6   7   8   92   4   6   8   10   12   14   16   18sum: 90

2.元素计数算法

求元素的总个数。
函数形式为:

count(Iterator begin, Iterator end ,const T& value)count_if(Iterator begin ,Iterator end ,UnaryPredicate op)

说明:
1.在区间中统计值为value的个数
2.只有当op参数为真的时候,bool类型的返回值,才统计元素的个数。

例子:

#include <algorithm>#include <iostream>#include <vector>int main(){    int data[] = { 1, 2, 3, 4, 4, 3, 7, 8, 9, 10 };    std::vector<int> v(data, data+10);    int target1 = 3;    int target2 = 5;    int num_items1 = std::count(v.begin(), v.end(), target1);    int num_items2 = std::count(v.begin(), v.end(), target2);    std::cout << "number: " << target1 << " count: " << num_items1 << '\n';    std::cout << "number: " << target2 << " count: " << num_items2 << '\n';}

输出结果为:

number: 3 count: 2number: 5 count: 0

例子2:

#include <algorithm>#include <iostream>#include <vector>int main(){    int data[] = { 1, 2, 3, 4, 4, 3, 7, 8, 9, 10 };    std::vector<int> v(data, data+10);    int num_items1 = std::count_if(v.begin(), v.end(), [](int i) {return i % 3 == 0;});    std::cout << "number divisible by three: " << num_items1 << '\n';}

输出结果为;

number divisible by three: 3

3.最大值和最小值算法

最小值算法:

Iterator min_element(Iterator beg,Iterator end)Iterator min_element(Iterator beg, Iterator end, compFunc op)

最大值算法:

Iterator max_element(Iterator beg,Iterator end)Iterator max_element(Iterator beg, Iterator end, compFunc op)

上述两个形式参数:
1.第一种形式一“operator<”进行比较。
2.第二种以op(elem1,elem2)进行比较。
例子:

bool Absless(int elem1,int elem2){    return abs(elem1) < abs(elem2);}int main(){    vector<int> v{ 3, 1, 4, 1, 5, 9 ,-3};    vector<int>::iterator result = min_element(v.begin(), v.end());//最小值    cout << "min element at: " << *result << endl;    result = min_element(v.begin(), v.end(),Absless);//最小绝对值    cout << "min element at: " << *result << endl;}

结果为:

min element at: -3min element at: 1

4. 搜寻算法

1.搜寻第一个匹配的元素

函数定义为:

Iterator find(Iterator begin, Iterator end, const T& value)Iterator find_if(Iterator begin, Iterator end, UnaryPredicate op)Iterator find_if_not(Iterator begin, Iterator end, UnaryPredicate op)      [c++11]

说明:
1.第一个形式:返回区间值为value的第一个元素
2.第二个形式:寻找op值为真的第一个元素
3.第三个形式为c++11标准中: 寻找第一个是op返回false的元素

例子:

bool op(int elem1){    return elem1 < 3;}int main(){    int n1 = 3;    int n2 = 5;    std::vector<int> v{ 4,6,8,7,2,4 };    auto result1 = std::find(v.begin(), v.end(), n1);    auto result2 = std::find_if(v.begin(), v.end(), op);//小于3的数    auto result3 = std::find_if_not(v.begin(), v.end(), op);//不小于3的数    if (result1 != v.end()) {        std::cout << "v contains: " << n1 << '\n';    }    else {        std::cout << "v does not contain: " << n1 << '\n';    }    if (result2 != v.end()) {        std::cout << "v 存在小于3的数: " << *result2 << '\n';    }    else {        std::cout << "v 不才在小于3的数: "<< '\n';    }    if (result3 != v.end()) {        std::cout << "v 存在不小于3的数: " << *result3 << '\n';    }    else {        std::cout << "v 不小于3的数 "  << '\n';    }}

结果为:

v does not contain: 3v 存在小于3的数: 2v 存在不小于3的数: 4

2.搜寻前n个匹配的值

函数为:

Iterator search_n(Iterator begin, Iterator end,Size count,constT& value)Iterator search_n(Iterator begin, Iterator end,Size count,constT& value,BinaryPredicate p)

说明:
1.第一个形式: 返回区间中“连续count个值为value”的序列的首位置,如果不存在,返回end
2.第二个形式: 使用区间中的每一个元素和value的比较,返回区间中满足op为真的连续count个元素的序列的开头位置,不满足返回end

例子:

bool op(int elem1,int elem2){    return elem1>elem2;}#include<iterator>int main(){    vector<int> vec = { -3, -2, -2, -2, -1, 0, 1, 2, 2, 3, 3, 3, 3, 4, 5, 6, 7, 7, 7, 7 };    vector<int>::iterator it1,it2;//distance需要不能使用const_iterator    it1 = search_n(vec.begin(), vec.end(),4, 3);//寻找4个等于3的连续序列    it2 = search_n(vec.begin(), vec.end(), 5,3, op);//寻找大于3的5个元素    if (it1 != vec.end())        cout << "4个3的连续序列的起始位置为:" <<std::distance(vec.begin(),it1)<< endl;    else{        cout << "没有4个3的连续序列! " << endl;    }    if (it2 != vec.end())        cout << "大于3的5个元素连续序列的起始位置为:" << std::distance(vec.begin(), it2) << endl;    else{        cout << "没有大于3的5个元素的连续序列! " << endl;    }}

值为:

4个3的连续序列的起始位置为:9大于3的5个元素连续序列的起始位置为:13

3.搜寻第一个子区间

函数定义为:

Iterator search(Iterator1 begin, Iterator1 end, Iterator2 searchchbegin, Iterator2 searchchend)Iterator search(Iterator1 begin, Iterator1 end, Iterator2 searchchbegin, Iterator2 searchchend,BinaryPredicate p)

说明:
1.两个函数返回区间内和子区间完全匹配的子区间开头位置,找不到的话,返回end,若子序列为空,返回begin
2.第二个函数在p为真的时候才执行。
例子:

bool op(int elem1,int elem2){    return elem1>elem2;}#include<iterator>int main(){    vector<int> vec1= {1,2,3,4,5,5,4,3,2,1 };    vector<int> vec2 = { 1,2, 3 };    vector<int>::iterator it1,it2;    it1 = search(vec1.begin(), vec1.end(), vec2.begin(), vec2.end());    cout << "子区间位置为:" << std::distance(vec1.begin(), it1) << endl;//完全匹配    it2 = search(vec1.begin(), vec1.end(), vec2.begin(), vec2.end(),op);    cout << "子区间位置为:" << std::distance(vec1.begin(), it2) << endl;//vec1大于vec2的序列}

输出为:

子区间位置为:0子区间位置为:1

4.搜寻最后一个子区间

函数由:

Iterator find_end(Iterator1 begin,Iterator1,end ,Iterator2 searchchbegin , Iterator2 searchend)Iterator find_end(Iterator1 begin,Iterator1,end ,Iterator2 searchchbegin , Iterator2 searchend,BinaryPredicate p)

说明:
1.两个函数都返回区间【begin,end】中和【searchchbegin,searchchend】匹配的最后一个子区间的开头位置。如果搜索失败,或者为空,返回end.
2.第二个函数只有在p为真的时候才有意义。

例子:

bool op(int elem1,int elem2){    return elem1>elem2;}#include<iterator>int main(){    vector<int> vec1= {1,2,3,4,5,4,3,2,1,2,3 };    vector<int> vec2 = { 1,2, 3 };    vector<int>::iterator it1,it2;    it1 = find_end(vec1.begin(), vec1.end(), vec2.begin(), vec2.end());    cout << "子区间位置为:" << std::distance(vec1.begin(), it1) << endl;//完全匹配    it2 = find_end(vec1.begin(), vec1.end(), vec2.begin(), vec2.end(),op);    cout << "子区间位置为:" << std::distance(vec1.begin(), it2) << endl;//vec1大于vec2的序列}-----------------------------------------输出为;子区间位置为:8子区间位置为:3

5.搜寻某些元素的第一次出现位置

函数为:

Iterator find_first_of(Iterator1 begin, Iterator1 end,Iterator2 searchchbegin,Iterator2 searchchend)Iterator find_first_of(Iterator1 begin, Iterator1 end,Iterator2 searchchbegin,Iterator2 searchchend, BiaryPredicate p)

函数的模板为:

template<class InputIt, class ForwardIt>InputIt find_first_of(InputIt first, InputIt last,                      ForwardIt s_first, ForwardIt s_last){    for (; first != last; ++first) {        for (ForwardIt it = s_first; it != s_last; ++it) {            if (*first == *it) {                return first;            }        }    }    return last;}template<class InputIt, class ForwardIt, class BinaryPredicate>InputIt find_first_of(InputIt first, InputIt last,                      ForwardIt s_first, ForwardIt s_last,                      BinaryPredicate p){    for (; first != last; ++first) {        for (ForwardIt it = s_first; it != s_last; ++it) {            if (p(*first, *it)) {                return first;            }        }    }    return last;}

说明:
1.两个函数都返回子区间[serachbegin,searchend]中任何元素在【begin,end】中出现的第一个位置,如果没有这样字的元素,返回end.
2.第二个函数只有在p为真的时候才有意义

例子:

bool op(int elem1,int elem2){    return elem1>elem2;}#include<iterator>int main(){    std::vector<int> v{ 0, 2, 3, 25, 5 };    std::vector<int> t{ 3, 19, 10, 4 };    auto result1 = std::find_first_of(v.begin(), v.end(), t.begin(), t.end());    auto result2 = std::find_first_of(v.begin(), v.end(), t.begin(), t.end(),op);    if (result1 == v.end()) {        std::cout << "不存在值为 3, 19, 10 or 4\n";    }else {        std::cout << "发现匹配位置: "            << std::distance(v.begin(), result1) << "\n";    }    if (result2 == v.end()) {        std::cout << "不存在大于 3, 19, 10 or 4的值\n";    }else {        std::cout << "发现匹配位置: "            << std::distance(v.begin(), result2) << "\n";    }}------------------------输出:发现匹配位置: 2发现匹配位置: 3

6.搜寻两个连续相等的元素

使用函数adjacent_find():
函数为:

//形式一template<class ForwardIt>ForwardIt adjacent_find(ForwardIt first, ForwardIt last){    if (first == last) {        return last;    }    for (ForwardIt next = first;++next != last; ++first) {        if (*first == *next) {            return first;//一次循环就够了        }    }    return last;//为找到返回last}//形式二template<class ForwardIt, BinaryPredicate p>ForwardIt adjacent_find(ForwardIt first, ForwardIt last,                         BinaryPredicate p){    if (first == last) {        return last;    }    for (ForwardIt next = first;++next != last; ++first) {        if (p(*first, *next)) {//需要满足P            return first;        }    }    return last;}

其中,

ForwardIt adjacent_find( ForwardIt first, ForwardIt last );ForwardIt adjacent_find( ForwardIt first, ForwardIt last, BinaryPredicate p );

说明:ForwardIt 表示迭代器
1.两个函数都是返回迭代器范围内部两个连续的相同元素的位置,没有被找到,返回last.
2.第一个版本使用operator==比较的元素,第二个版本使用给定的二元谓词p.
例子:

#include <algorithm>#include <iostream>int main(){    std::vector<int> v1{0, 1, 2, 3, 40, 40, 5};    std::vector<int>::iterator result;    result = std::adjacent_find(v1.begin(), v1.end());    if (result == v1.end()) {        std::cout << "no matching adjacent elements";    } else {        std::cout << "match at: " << std::distance(v1.begin(), result);    }}--------------------------输出:match at: 4

5.区间比较算法

stl提供了三个比较函数:

  • equal():比较两个容器对象相等
  • mismatch():寻找两个容器对象两两相异的元素,如果找到相异点,将两个点返回一个pair对象;如果没有找到,将第一个元素的end元素和第二对象的对应元素返回成一个pair对象。
  • lexicographical_compare():属于字典比较,元素一一比较:
    (1).如果两个元素不相等,则两个元素的比较结果即为两个序列的比较结果
    (2).如果两个容器中元素数量不相等,则元素较少的序列小于另一个序列,若第一序列较少,比较结果为true
    (2).如果两个序列均没有更多元素比较,即序列相等,返回false

三个函数原型:

template< class InputIt1, class InputIt2 >bool equal( InputIt1 first1, InputIt1 last1, InputIt2 first2 );template< class InputIt1, class InputIt2, class BinaryPredicate >bool equal( InputIt1 first1, InputIt1 last1, InputIt2 first2, BinaryPredicate p );

1.如果区间[first1, last1)和区间[first2, first2 + (last1 - first1)相等,返回true,否则返回false.
2.第一个形式使用operator==判定两个元素是否相等,而重载形式2使用的是给定的谓词函数。
例子:

--省略--void test(const std::string& s){    if(std::equal(s.begin(), s.begin() + s.size()/2, s.rbegin())) {        std::cout << "\"" << s << "\" 是一个回文\n";    } else {        std::cout << "\"" << s << "\" 不是一个回文\n";    }}int main(){    test("radar");    test("hello");}---省略------------输出为:"radar" 是一个回文"hello" 不是是一个回文

mismatch():
函数原型:

template< class InputIt1, class InputIt2 >std::pair<InputIt1,InputIt2> mismatch( InputIt1 first1,InputIt1 last1,InputIt2 first2 );template< class InputIt1, class InputIt2, class BinaryPredicate >std::pair<InputIt1,InputIt2>    mismatch( InputIt1 first1,              InputIt1 last1,              InputIt2 first2,              BinaryPredicate p );

说明:
1.返回第一个不匹配,对两个范围中的元素:一个[first1,last1)和另一个开始在first2的序列。
2. 第一个版本的功能使用operator==来比较元素,第二个版本使用给定的二元谓词p.
3. 返回std::pair对象

例子:

#include<iterator>int main(){    vector<int> vec1= {1,2,3,4,5,6 };    vector<int> vec2 = { 1,2, 3,4,5,6,7 };    vector<int>::iterator it1,it2;    pair<vector<int>::iterator, vector<int>::iterator> s;    s = mismatch(vec1.begin(),vec1.end(),vec2.begin());    cout << "pair first: " << std::distance(vec1.begin(),s.first)<< " second: " <<std::distance(vec2.begin(),s.second) << endl;}

如果未找到相异点,那么返回第一个序列最后一个元素和第二列对应的元素。
【但是】,如果第二列长度小于第一列,当两列元素相同的时候,返回的pair对象第二个参数,即第二列的迭代器就会等于end(),也就是最后一个元素的后面位置,这个位置是无法解引用的,就会报错。

lexicographical_compare():

函数为:

template< class InputIt1, class InputIt2 >bool lexicographical_compare( InputIt1 first1, InputIt1 last1,                              InputIt2 first2, InputIt2 last2 );template< class InputIt1, class InputIt2, class Compare >bool lexicographical_compare( InputIt1 first1, InputIt1 last1,                              InputIt2 first2, InputIt2 last2,                              Compare comp );

说明:
1. 的第一个版本使用operator<比较的元素,第二个版本使用给定的比较函数comp.
2. 第一个不匹配,元素定义的范围是字典“少”或“较大”比其他.
3. 如果一个范围是一个前缀的情况,在较短的范围是字典“小于”比其他.返回true
4. 如果两个范围有等同的元件,并具有相同的长度,则范围是字典“等于”.返回false
5. 空的范围是字典“少”比任何非空的范围内.返回false
6. 两个空的范围是字典“等于”.返回false

例子:

    vector<int> vec1= {1,2,3,4,5,6 };    vector<int> vec2 = { 1,2, 3,4,5,6,7 };    vector<int> vec3;    vector<int> vec4 = {1,2,3,4,5};    vector<int> vec5 = { 2, 2, 3, 4, 5 };    vector<int>::iterator it1,it2;    bool flag;    flag = lexicographical_compare(vec1.begin(), vec1.end(), vec2.begin(), vec2.end());    cout << "vec1 < vec2 :" << flag << endl;    flag = lexicographical_compare(vec1.begin(), vec1.end(), vec3.begin(), vec3.end());    cout << "vec1 < vec3 :" << flag << endl;    flag = lexicographical_compare(vec1.begin(), vec1.end(), vec4.begin(), vec4.end());    cout << "vec1 < vec4 :" << flag << endl;    flag = lexicographical_compare(vec1.begin(), vec1.end(), vec5.begin(), vec5.end());    cout << "vec1 < vec5 :" << flag << endl;—————————————————————输出为:vec1 < vec2 :1vec1 < vec3 :0vec1 < vec4 :0vec1 < vec5 :1
原创粉丝点击