使用C++库算法 第6章心得

1 常用的库算法

1.1 头文件

除特殊说明,下面的函数的头文件都是<algorithm>

1.2 copy函数(带模版)

模版代码:

template<class In, class Out>
Out copy(In begin, In end, Out dest){
    while (begin != end)
        *dest++ = *begin++;
    return dest;
}

泛型算法(不属于任何特定容器的算法)。

copy(begin, end, out);

三个参数都是迭代器。

将迭代器在区间[begin, end)内的全部元素复制到从一连串一out开始的元素中,并且在有必要的时候对out所属的容器进行扩展。

一般out常用back_inserter(容器),back_inserte为迭代适配器。

back_inserter一般以容器作为参数,生产一个迭代器,在生产迭代器被用于一个目的地的时候,会向容器末端添加数值。

上面的代码等同于

while(begin != end){
	*out++ = *begin++;
}

示例代码:

复制向量v的值到v2

vector<int> v;
vector<int> v2;
copy(v.begin(), v.end(), back_inserter(v2));

下面这种写法是错误的,但是可以通过编译。错在v2.end()没有元素。copy要做的第一件事,就是复制一个值给v2.end(),但是此位置不存在元素,也就是此元素的地址也不存在,由于不能给一个空地址赋值(赋值:先删除元素原来的内容,后复制),于是copy操作无法完成。

vector<int> v;
vector<int> v2;
copy(v.begin(), v.end(), v2.end());

同理下面的写法也是错的:

vector<int> v;
vector<int> v2;
copy(v.begin(), v.end(), v2.begin());

1.3 equal函数(带模版)

模版函数:

template <class In, class Out>
bool equal(In begin, In end, Out dest){
    while(begin != end){
        if(*begin++ != *dest++){
            return false;
        }
    }
    return true;
}

调用格式

equal(begin1, end, begin2);

第一、二两个值为第一个序列的头尾迭代器,第三个值为第二个序列的起点。

equal假设第二个序列的长度和第一个相同,因此并不需要一个结尾迭代器。

示例:
判断回文串:

bool is_palindrome(const string& s){
	return equal(s.begin(), s,end(), s.rbegin());
}

rbegin()一个迭代器,返回容器的最后一个元素的开始。

1.4 transform函数(带模版)

模版函数:

template <class In, class Out,class Pre>
void transform2(In begin, In end, Out dest, Pre f){
    while(begin != end){
        *dest++ = f(*begin++);
    }
}

调用格式:

transform(begin, end,  out, func);

开头两个迭代器为带转换元素的区间,第三个迭代器是一个目的地,将保存函数的运行结果。第四个参数为一个函数,将这个函数应用于输入序列的每一个元素以获得输出序列中对应的元素。

示例:

int func(int x){
	return x + 1;
}
vector<int> v;
vector<int> res;
transform(v.begin(), v.end(), back_inserter(res), func);

1.5 accumulate函数(带模版)

模版函数:

template <class In, class Out>
Out accumulate(In begin, In end, Out dest){
    while(begin != end){
        dest = dest + *begin;
        begin++;
    }
    return dest;
}

使用格式:

accumulate(begin, end, val);

头文件为:
<numeric>
头两个参数为一个区间,第三个参数为求和结果的初值。和的种类就是第三个参数的类型。
示例:
将vector<string>对象中的全部元素连接起来。

   vector<string> v = {"i", "love", "you"};
   string str;
   str = accumulate(v.begin(), v.end(), str);
   cout << str;

1.6 remove_copy_if函数(带模版)

模版函数:

template <class In, class Out, class Pre>
Out remove_copye_if(In begin, In end, Out dest, Pre f){
    while(begin != end){
            if(!f(*begin)){
                *dest++ = *begin;//不满足谓词的元素复制到开头
            }
            begin++;
        }
    return dest;
}

使用格式:

remove_copy_if(begin, end, out, func);

开头两个迭代器为带转换元素的区间,第三个迭代器是一个目的地,将保存函数的运行结果。最后一个是一个返回bool类型的函数,对区间内每个元素进行判断。

函数的作用为,将不满足谓词的(不满足条件函数)的元素复制到out指定的容器。

示例:

bool func(int x){
	return  x < 60;
}
vector<int> v;
vector<int> res;
//就是复制及格的都复制到res中
remove_copy_if(v.begin(), v.end(), back_inserter(res), func);

1.7 remove_if函数(带模版)

函数模版:

template <class In, class Pre>
In remove_if(In begin, In end, Pre f){
        In i = begin;
        while(i != end){
            if(!f(*i)){
                *begin++ = *i;//不满足谓词的元素复制到开头
            }
            i++;
        }
    return begin;
}

使用格式:

remove_copy_if(begin, end, func);

开头两个迭代器为带转换元素的区间,第三个迭代器是一个返回bool类型的函数,对区间内每个元素进行判断。

函数作用为将不满足谓词的(不满足条件函数)的元素复制到序列的开头,返回一个迭代器,这个迭代器指向最后一个不满足条件的元素的后面那个位置。

示例:

bool func(int x){
	return  x < 60;
}
vector<int> v;
//删除满足条件的元素(就是不及格的都删除)
v.erase(remove_if(v.begin(), v.end(), func), v.end());

1.8 partition函数与stable_partition函数(带模版)

模版函数:

template <class In, class Pre>
In partition(In begin, In end, Pre f){
    In i = begin;//记录前面部分满足条件的最后一个元素的位置
    while(begin != end){
        if(f(*begin)){//满足条件,与前面的元素交换位置
            std::swap(*begin, *i++);
        }
        begin++;
    }
    return i;
}

使用格式:

stable_partition(begin, end, func);

开头两个迭代器为带转换元素的区间,第三个迭代器是一个返回bool类型的函数,对区间内每个元素进行判断。

函数作用为:将每个满足谓词(条件函数)的元素排在那些不满足谓词的元素之前。返回第一个不满足谓词的迭代器,如果所有元素都满足谓词,则返回end。

partition函数与stable_partition的区别在于:

  • partition可以能会在每种类内部重新排列元素;
  • stable_partition除了划分区域以外,还会让各个区域内的元素的相互顺序保持不变(相对位置不变)。

1.9 find_if函数(带模版)

模版函数:

template <class In, class Pre>
In find_if(In begin, In end, Pre f){
    while (begin != end && !f(*begin)){
        ++begin;
    }
    return begin;
}

使用格式:

find_if(begin, end, func);

开头两个迭代器为带转换元素的区间,第三个迭代器是一个返回bool类型的函数,对区间内每个元素进行判断。

根据谓词对区间内的每个元素进行检查,如果查找的值存在,则返回一个序列中第一次出现这个值的迭代器;如果没有找到,则返回第二个参数。

1.10 search函数(带模版)

模版函数(自写,使用的朴素算法,可以使用带nextval的KMP会是结果更优)

template <class In, class Out>
In search(In begin, In end, Out begin2, Out end2){
    In i;
    while(begin != end && begin2 != end2){
        i = begin;//记录开始文本串开始匹配为位置
        Out j = begin2;
        if(*begin == * begin2){//相等继续往后走
            while(*begin == *begin2 && begin != end && begin2 != end2){
                begin++;
                begin2++;
            }
        }
        //不想等,模式串回到开头,文本串位置加1
        if(*begin != * begin2 && begin != end && begin2 != end2){
            begin = ++i;
            begin2 = j;
        }
    }
    if(begin2 == end2){//完全匹配
        return i;
    }else{
        return end;
    }
}

使用格式:

search(begin1, end1, begin2, end2);

参数为两对迭代器,第一对是要查找的序列,第二对则指向一个序列(为这个序列定位)。

如果查找失败,返回第二个参数;如果成功,会返第一次找到序列的位置前一个的迭代器。

1.11 unique函数

使用格式:

unique(begin,end);

两个参数都是迭代器。处理区间为[begin,end)。

作用是:把重复的元素移到后面去,然后返回不重复元素的最后一个元素的迭代器。

1.12 distance 函数

头文件:<iterator>
使用格式:

distance(begin, end);

两个参数都是迭代器。处理区间为[begin,end)。

作用是:返回迭代器区间内的元素个数。

1.13 rotate函数

使用格式:

rotate(begin, begin1, end);

三个参数都是迭代器,第一和第三个参数为区间的开始和结尾迭代器,第二个参数必须是在这个区间内的迭代器。

作用:把区间内的元素,类似于循环左移的方式在区间内移动,然后直到第二个参数的迭代器作为区间新的第一个元素
函数,返回原始第一个元素所在的新位置(新的迭代器)。

2 总结

2.1 sort、remove_if、partition区别

sort、remove_if、partition都会将基本容器中的元素移动到新的位置,但是并没有改变容器的长度。

例如remove_if不会改变它所操作的容器长度,仅是在容器内部的不同位置复制元素。

2.2 迭代器适配器

概念:是产生迭代器的函数。
头文件:
<iterator>
常见的:
back_inserter©;
作用:在容器c尾部插入元素。

容器c必须支持链表、向量以及字符串类型都会支持的push_back()操作。

front_inserter©;
作用:在容器头部插入。
容器c必须支持push_front操作(如链表)。

inserter(c,it);
作用:在迭代器it之前插入元素。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

繁星蓝雨

如果觉得文章不错,可以请喝咖啡

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值