【侯捷-SL體系結構內核分析-算法】
目錄:
accumulate
for_each
replace, replace_if, replace_copy
accumulate
源碼
accumulate 的源碼如下。
template<class _InIt,
class _Ty,
class _Fn>
_NODISCARD inline _Ty accumulate(const _InIt _First, const _InIt _Last, _Ty _Val, _Fn _Reduce_op)
{ // return noncommutative and nonassociative reduction of _Val and all in [_First, _Last), using _Reduce_op
_Adl_verify_range(_First, _Last);
auto _UFirst = _Get_unwrapped(_First);
const auto _ULast = _Get_unwrapped(_Last);
for (; _UFirst != _ULast; ++_UFirst)
{
_Val = _Reduce_op(_Val, *_UFirst);
}
return (_Val);
}
template<class _InIt,
class _Ty>
_NODISCARD inline _Ty accumulate(const _InIt _First, const _InIt _Last, _Ty _Val)
{ // return noncommutative and nonassociative reduction of _Val and all in [_First, _Last)
return (_STD accumulate(_First, _Last, _Val, plus<>()));
}
- 它有兩個重載函數,第一個函數參數爲:容器的 begin iterator、容器的 end iterator、計算初值、仿函數或者函數指針。計算初始和容器元素依據傳入的函數方法 _Reduce_op 進行相應累計操作。如下行代碼:
_Val = _Reduce_op(_Val, *_UFirst);
- 第二個函數參數則將函數操作指定爲 plus<>(),即對初值和容器數據進行默認累加操作。
測試代碼
int myFunc(int x, int y)
{
return x + 2 * y;
}
struct myClass
{
int operator()(int x, int y)
{
return x + 3 * y;
}
}myObj;
void test_accumulate()
{
int nInit = 100;
int data[3] = { 10, 20, 30 };
int result = std::accumulate(data, data + 3, nInit);
// 100 + 10 + 20 + 30 = 160
std::cout << result << endl;
result = std::accumulate(data, data + 3, nInit, myFunc);
// 100 + 2 * 10 + 2 * 20 + 2 * 30 = 220
std::cout << result << endl;
result = std::accumulate(data, data + 3, nInit, myObj);
// 100 + 3 * 10 + 3 * 20 + 3 * 30 = 280
std::cout << result << endl;
}
注意點
- accumulate算法和其他算法不一樣,它位於 numeric 文件中。
- 請看如下代碼:
void test_accumulate()
{
int nInit = 0;
float data[3] = { 10.3, 20.4, 30.5 };
float result = std::accumulate(data, data + 3, nInit);
std::cout << result << endl;
}
正確的輸出應該是 61.2,但是實際輸出爲 60,這是爲什麼呢?
可以往前看看 accumulate 的源代碼,可以看到,計算結果的類型會根據傳入初值參數類型進行判斷,與容器數值類型並沒有關係,由於這裏傳入初值 nInit 爲整形,所以每次累加時都會轉換成整型類型,最後輸出60。如果將 nInit 改爲和容器數據類型相同浮點類型,就可以得出正確結果。
for_each
源碼
template<class _InIt,
class _Fn> inline
_Fn for_each(_InIt _First, _InIt _Last, _Fn _Func)
{ // perform function for each element [_First, _Last)
_Adl_verify_range(_First, _Last);
auto _UFirst = _Get_unwrapped(_First);
const auto _ULast = _Get_unwrapped(_Last);
for (; _UFirst != _ULast; ++_UFirst)
{
_Func(*_UFirst);
}
return (_Func);
}
- 它遍歷容器中 [ _First, _Last) 區間的數據,並對每個數據進行 _Func函數操作。類似於C++ 11引進的新操作 range_based for statement:
vector<int> myVec = vector<int>{ 0, 1, 2, 3,4 };
for (auto i : myVec)
{
cout << i << " ";
}
replace, replace_if, replace_copy
replace 源碼
template<class _FwdIt,
class _Ty> inline
void replace(const _FwdIt _First, const _FwdIt _Last, const _Ty& _Oldval, const _Ty& _Newval)
{ // replace each matching _Oldval with _Newval
_Adl_verify_range(_First, _Last);
auto _UFirst = _Get_unwrapped(_First);
const auto _ULast = _Get_unwrapped(_Last);
for (; _UFirst != _ULast; ++_UFirst)
{
if (*_UFirst == _Oldval)
{
*_UFirst = _Newval;
}
}
}
- 它遍歷容器中的每一個元素,噹噹前遍歷的元素與傳入的 _Oldval 相等時,將該 _Oldval 替換成爲 _Newval。
replace_if 源碼
template<class _FwdIt,
class _Pr,
class _Ty> inline
void replace_if(const _FwdIt _First, const _FwdIt _Last, _Pr _Pred, const _Ty& _Val)
{ // replace each satisfying _Pred with _Val
_Adl_verify_range(_First, _Last);
auto _UFirst = _Get_unwrapped(_First);
const auto _ULast = _Get_unwrapped(_Last);
for (; _UFirst != _ULast; ++_UFirst)
{
if (_Pred(*_UFirst))
{
*_UFirst = _Val;
}
}
}
- replace_if 在 replace 的基礎上,會多傳入一個_Pred參數,用於判斷替換條件。也就是代碼中將 _UFirst == _Oldval 判斷條件改爲 _Pred(_UFirst) 條件。
replace_copy源碼
template<class _InIt,
class _OutIt,
class _Ty> inline
_OutIt replace_copy(_InIt _First, _InIt _Last,
_OutIt _Dest, const _Ty& _Oldval, const _Ty& _Newval)
{ // copy replacing each matching _Oldval with _Newval
_Adl_verify_range(_First, _Last);
auto _UFirst = _Get_unwrapped(_First);
const auto _ULast = _Get_unwrapped(_Last);
auto _UDest = _Get_unwrapped_n(_Dest, _Idl_distance<_InIt>(_UFirst, _ULast));
for (; _UFirst != _ULast; ++_UFirst, (void)++_UDest)
{
if (*_UFirst == _Oldval)
{
*_UDest = _Newval;
}
else
{
*_UDest = *_UFirst;
}
}
_Seek_wrapped(_Dest, _UDest);
return (_Dest);
}
- 不同於replace 和 replace_if 會修改源容器的值,replace_copy 會遍歷源容器的元素,當源容器元素與 _Oldval 相等時,則會以新值 _Newval 複製到目標容器相應位置,否則則會複製源容器元素值。