C++ STL(第二十二篇:算法-- 单纯的数据处理算法)

1、概述

前面整理了 STL 最重要的 排序算法,以及 有序区间算法,还有copy、及简单的算术算法等。但是 STL 还有一些单纯的数据处理算法,接下来两节会对这部分内容进行整理。部分算法比较简单,就不整理代码了,只做一个简单的介绍。

2、数据处理算法

adjacent_find:找出第一组满足条件的相邻元素。默认条件是“两元素相等”,可传入自定义二元仿函数。

count:统计在 [first, last) 区间内的每一个与指定值相等的元素个数。

count_if:跟上面一样的功能,只不过传入一个仿函数,来判断是否跟传入值相等。

find: 根据 equallity 操作符,在 [first, last) 区间内,找出第一个匹配 “等同条件” 者。

find_if:跟上面的功能一样,只不过 equality 操作符,改成传入一个仿函数。

find_end:在序列一 [first1, last1) 所涵盖的区间中,查找序列二 [first2, last2) 的最后一次出现点。如果序列一之内不存在“完全匹配序列二”的子序列,便返回迭代器 last1。

find_first_of:以 [first2, last2) 区间内的某些元素作为查找目标,寻找他们在 [first1, last1) 区间内的第一次出现地点。比如:第二序列为 aeiou,第一序列为 synesthesia,则返回第一个 e。底层就是两层嵌套循环。

for_each:将仿函数 f 施行于 [first, last) 区间内的每一个元素身上。 f 不可改变元素内容,如果想更改,使用transform。

generate:将仿函数 gen 的运算结果填写在 [first, last) 区间内的所有元素身上。所谓填写,用的是迭代器所指元素的 assignment 操作符。代码如下:

template<class ForwardIterator, clas Generator>
void generate(ForwardIterator first, ForwardIterator last, Generator gen)
{
	for( ; first != last; ++first)
		*first = gen();
}

generate_n:将仿函数 gen 的运算结果填写在从迭代器 first 开始的 n 个元素身上。

max_element:返回一个迭代器,指向序列中数值最大的元素。比较方法可通过仿函数传入。

min_element:和max_element 相反,返回的迭代器,指向序列中数值最小的元素。

replace:将 [first, last) 区间内的所有 old_value 都以 new_value 取代。

replace_copy:与 replace 类似,唯一不同的是新序列会被复制到 result 所指的容器中。

replace_if:将 [first, last) 区间内所有 被仿函数 pred 评估为 true 的元素,都以new_value 取代。

replace_copy_if:行为与 replace_if 类似,但是新序列会被复制到 result 所指区间内。

partition:paritition 会将区间 [first, last) 中的元素重新排列。所有被一元条件运算判定为true 的元素,都会被放在区间的前端,被判定为 false 的元素,都会被放在区间后段。这个算法并不保留元素的原始相对位置。如果需要保留,使用 stable_partition。这个算法非常的重要,前面介绍的 partition_sort 和 Quick_sort 都是用的这个思想,而且一堆数据中取第 K大的数也可以用类似的算法。代码如下:

//所有被 pred 判定为 true 的元素,都被放到前段
//被 pred 判定为 false 的元素,都被放到后段,不保证保留元素的相对位置。
template<class BidirectionalIterator, class Predicate>
BidirectionalIterator partition(BidirectionalIterator first, BidirectionalIterator last, Predicate pred)
{
	while(true)
	{
		while(true)
		{
			if( first == last )		//头指针等于尾指针
				return first;		//所有操作结束
			else if( pred(*first))	//头指针所指的元素符合不移动条件
				++first;			//说明元素放置是对的,检查后面的元素,直到第一个不符合条件
			else
				break;
		}
		--last;						//尾指针回溯
		while( true )
		{
			if( first == last )		//头指针等于尾指针
				return first;
			else if( !pred(*last))
				--last;				//说明元素放置是对的,检查前面的元素,直到第一个不符合条件
			else
				break;
		}
		iter_swap(first, last);		//交换头节点 和 尾节点 互不满足条件的元素,然后进行向下遍历
		++first;
	}
}

在这里插入图片描述
remove:移除(但不删除)[first,last) 中所有与 value 相等的元素。将每一个不与 value 相等的元素轮番赋值给 first 之后的空间。返回值 ForwardIterator 标示出重新整理后的最后元素的下一个位置。

template<class ForwardIterator, class T>
ForwardIterator remove(ForwardIterator first, ForwardIterator last, const T& value)
{
	first = find(first, last, value);	//查找出第一个相等元素
	ForwardIterator next = first;		//以 next 标示出来
	//利用 “remove_copy() 允许新旧容器重叠 ”  的性质,进行移除操作
	return first == last ? first : remove_copy(++next, last, first, value);
}

remove_copy:移除 [first, last) 区间内所有与 value 相等的元素。而将结果复制到一个以 result 标示起始位置的容器身上。

template<class InputIterator, class OutputIterator, class T>
OutputIterator remove_copy(InputIterator first, InputIterator last, OutputIterator result, const T& value)
{
	for(; first != last; ++first)
	{
		if( *first != value)
			*result++ = *first;
	}
	return result;
}

remove_if:和前面的 remove 操作差不多,就是 等于操作 改为 传入仿函数pred,pred判定为true 的元素,删除掉。

remove_copy_if:和 remove_copy 差不多,就是 等于操作 改为 传入仿函数pred,pred判定为true 的元素,删除掉。

reverse:将序列 [first, last) 的元素在原容器中颠倒重排。迭代器的双向或随机定位能力,决定了这个算法的效率。代码如下:

template<class BidirectionalIterator>
inline void reverse( BidirectionalIterator first,  BidirectionalIterator last)
{
	__reverse(first, last, iterator_category(first));
}

//reverse  的双向迭代器版本
template<class BidirectionalIterator>
void __reverse( BidirectionalIterator first,  BidirectionalIterator last, bidirectional_iterator_tag)
{
	while( true)
	{
		if( first == last || first == --last)
			return;
		else
			iter_swap(first++,last);
	}
}

//reverse 的随机地址访问迭代器的版本
template<class RandomAccessIterator>
void __reverse(RandomAccessIterator first,  RandomAccessIterator last, random_access_iterator_tag)
{
	//头尾两两互换,然后头部累进一个位置,尾部累退一个位置,两者交错时停止
	while( first < last )
	{
		iter_swap(first++,--last);
	}
}

reverse_copy:行为类似 reverse(),但产生出来的新序列会被置于以 result 指出的容器中。返回值 OutputIterator 指向新产生的最后元素的下一位置。

swap_ranges:将 [first, last) 区间内的元素与 “从 first2 开始、个数相同”的元素互相交换。如果第二序列的长度小于第一序列,或者两序列在同一容器中且彼此重叠,执行结果未可预期。

transform: transform() 的第一版本以仿函数 op 作用于 [first, last) 中的每一个元素身上,并以其结果产生出一个新序列。第二版本以仿函数 binary_op 作用于一双元素身上,并以其结果产生出一个新序列。两个版本都把执行结果放在迭代器 result 所标示的容器中。

template<class InputIterator, class OutputIterator, class UnaryOperation>
OutputIterator transform( InputIterator first, InputIterator last, OutputIterator result, UnaryOperatio op)
{
	for( ;first != last; ++first)
		*result = op(*first);
	return result;
}

template<class InputIterator1, class InputIterator2, class OutputIterator, class BinaryOperation>
OutputIterator transform(InputIterator1 first1, 
							InputIterator1 last1, 
							InputIterator2 first2, 
							InputIterator2 last2, 
							OutputIterator result, 
							BinaryOperation binary_op)
{
	for( ; first1 != last1; ++first1, ++first2, ++result)
		*result = binary_op(*first1, *first2);
	return result;
}

还有一部分,下一节给整理完。

感谢大家,我是假装很努力的YoungYangD(小羊)。

参考资料:
《STL源码剖析》

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值