日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程语言 > c/c++ >内容正文

c/c++

从零开始学C++之STL(七):剩下5种算法代码分析与使用示例(remove 、rotate 、sort、lower_bound、accumulate)

發布時間:2023/12/14 c/c++ 20 豆豆
生活随笔 收集整理的這篇文章主要介紹了 从零开始学C++之STL(七):剩下5种算法代码分析与使用示例(remove 、rotate 、sort、lower_bound、accumulate) 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

一、移除性算法 (remove)

C++ Code?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
//?TEMPLATE?FUNCTION?remove_copy
template?<?class?_InIt,
?????????class?_OutIt,
?????????class?_Ty?>?inline
_OutIt?_Remove_copy(_InIt?_First,?_InIt?_Last,
????????????????????_OutIt?_Dest,?const?_Ty?&_Val,?_Range_checked_iterator_tag)
{
????//?copy?omitting?each?matching?_Val
????_DEBUG_RANGE(_First,?_Last);
????_DEBUG_POINTER(_Dest);
????for?(;?_First?!=?_Last;?++_First)
????????if?(!(*_First?==?_Val))
????????????*_Dest++?=?*_First;
????return?(_Dest);
}


template?<?class?_InIt,
?????????class?_OutIt,
?????????class?_Ty?>?inline
_OutIt?unchecked_remove_copy(_InIt?_First,?_InIt?_Last,
?????????????????????????????_OutIt?_Dest,?const?_Ty?&_Val)
{
????//?copy?omitting?each?matching?_Val
????return?_STD?_Remove_copy(_CHECKED_BASE(_First),?_CHECKED_BASE(_Last),?_Dest,?_Val,
?????????????????????????????_STD?_Range_checked_iterator_tag());
}


//?TEMPLATE?FUNCTION?remove
template?<?class?_FwdIt,
?????????class?_Ty?>?inline
_FwdIt?remove(_FwdIt?_First,?_FwdIt?_Last,?const?_Ty?&_Val)
{
????//?remove?each?matching?_Val
????_First?=?find(_First,?_Last,?_Val);
????if?(_First?==?_Last)
????????return?(_First);????//?empty?sequence,?all?done
????else
????{
????????//?nonempty?sequence,?worth?doing
????????_FwdIt?_First1?=?_First;
????????return?(_STDEXT?unchecked_remove_copy(++_First1,?_Last,?_First,?_Val));
????}
}

如下圖所示:


假設現在想要remove 的元素是3,則傳入到?_Remove_copy 函數的3個參數如上圖第一行所示,Val 即3。


接著遍歷First ~ Last 區間的元素,將非移除元素拷貝到前面,覆蓋前面的元素,最后的指向如圖,函數返回的是Dest 位置,如下代


碼所示:


for?(;?_First?!=?_Last;?++_First)


?if?(!(*_First?==?_Val))


????????????*_Dest++?=?*_First;


由上圖可看出移除性算法并沒有改變元素的個數,如果要真正刪除,可以將remove 的返回值傳入erase 進行刪除,如:


v.erase(remove(v.begin(), v.end(), 3), v.end()); 即會將后面兩個元素4 和 5 刪除掉。


在這里順便提一下,erase 會使當前迭代器失效,但可以返回下一個迭代器,故如果需要在遍歷中刪除,下面的做法才是正確的:


C++ Code?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
#include?<iostream>
#include?<vector>

using?namespace?std;

int?main(void)
{
????int?a[]?=?{3,?1,?2,?3,?4};
????vector<int>?v(a,?a?+?5);

????//for?(vector<int>::iterator?it=v.begin();?it!=v.end();?++it)
????//{
????//??if?(*it?==?3)
????//??????v.erase(it);??????????ERROR!
????//??else
????//??????cout<<*it<<'?';
????//}

????for?(vector<int>::iterator?it?=?v.begin();?it?!=?v.end();)
????{
????????if?(*it?==?3)
????????????it?=?v.erase(it);
????????else
????????{
????????????cout?<<?*it?<<?'?';
????????????++it;
????????}
????}

????cout?<<?endl;
????return?0;
}

示例代碼1:

C++ Code?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
#include?<iostream>
#include?<vector>
#include?<list>
#include?<algorithm>
using?namespace?std;

void?print_element(int?n)
{
????cout?<<?n?<<?'?';
}


int?main(void)
{
????int?a[]?=?{?1,?3,?2,?3,?4,?5?};
????vector<int>?v(a,?a?+?6);

????for_each(v.begin(),?v.end(),?print_element);
????cout?<<?endl;

????/*remove(v.begin(),?v.end(),?3);
????for_each(v.begin(),?v.end(),?print_element);
????cout<<endl;*/


????v.erase(remove(v.begin(),?v.end(),?3),?v.end());
????for_each(v.begin(),?v.end(),?print_element);
????cout?<<?endl;

????return?0;
}

二、變序性算法(?rotate)

C++ Code?
1
2
3
4
5
6
7
template<class?_FwdIt>?inline
void?rotate(_FwdIt?_First,?_FwdIt?_Mid,?_FwdIt?_Last)
{
????//?rotate?[_First,?_Last)
????if?(_First?!=?_Mid?&&?_Mid?!=?_Last)
????????_Rotate(_CHECKED_BASE(_First),?_CHECKED_BASE(_Mid),?_CHECKED_BASE(_Last),?_Iter_cat(_First));
}

rotate 調用了_Rotate,實際上_Rotate 繼續調用了某個函數,內部實現代碼比較長,而且不容易看懂,這邊可以看一下簡易的等價


版本實現,來自這里,如下:

C++ Code?
1
2
3
4
5
6
7
8
9
10
11
12
template?<class?ForwardIterator>
void?rotate?(ForwardIterator?first,?ForwardIterator?middle,
?????????????ForwardIterator?last)
{
????ForwardIterator?next?=?middle;
????while?(first?!=?next)
????{
????????swap?(*first++,?*next++);
????????if?(next?==?last)?next?=?middle;
????????else?if?(first?==?middle)?middle?=?next;
????}
}

假設一個容器有 1 2 3 4 5 6 六個元素,現在想把 1 2 放到后面去,可以這樣寫?rotate(v.begin(), v.begin()+2, v.end()); ?如下圖所示:


即將first 與 next 對應的元素互換且不斷向前推進,直到first == next 為止。


三、排序算法 (sort)

C++ Code?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
template<class?_RanIt>?inline
void?sort(_RanIt?_First,?_RanIt?_Last)
{
????//?order?[_First,?_Last),?using?operator<
????_DEBUG_RANGE(_First,?_Last);
????std::_Sort(_CHECKED_BASE(_First),?_CHECKED_BASE(_Last),?_Last?-?_First);
}

template?<?class?_RanIt,
?????????class?_Pr?>?inline
void?sort(_RanIt?_First,?_RanIt?_Last,?_Pr?_Pred)
{
????//?order?[_First,?_Last),?using?_Pred
????_DEBUG_RANGE(_First,?_Last);
????_DEBUG_POINTER(_Pred);
????std::_Sort(_CHECKED_BASE(_First),?_CHECKED_BASE(_Last),?_Last?-?_First,?_Pred);
}

sort 重載了兩個版本,第一個版本只有2個參數,默認按從小到大排序(using?operator<);第二個版本有三個參數,即可以自定義比較邏輯


(_Pred)。它們都調用了標準庫的std::_Sort, 跟蹤進去發現比較復雜,在_Sort 內會根據一些條件選擇不同的排序方式,如標準庫的堆排序,合并


序,插入排序等。站在使用的角度看,沒必要去深究,但如果是想學習相關的排序,那是很好的資源。


示例代碼2:

C++ Code?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
#include?<iostream>
#include?<vector>
#include?<list>
#include?<algorithm>
using?namespace?std;

void?print_element(int?n)
{
????cout?<<?n?<<?'?';
}

bool?my_greater(int?a,?int?b)
{
????return?a?>?b;
}

int?main(void)
{
????int?a[]?=?{?1,?2,?3,?4,?5,?6?};
????vector<int>?v(a,?a?+?6);

????for_each(v.begin(),?v.end(),?print_element);
????cout?<<?endl;

????rotate(v.begin(),?v.begin()?+?2,?v.end());
????for_each(v.begin(),?v.end(),?print_element);
????cout?<<?endl;

????sort(v.begin(),?v.end());
????for_each(v.begin(),?v.end(),?print_element);
????cout?<<?endl;

????sort(v.begin(),?v.end(),?my_greater);
????for_each(v.begin(),?v.end(),?print_element);
????cout?<<?endl;

????return?0;
}

此外,sort 有個坑,如果你自己傳遞比較邏輯,需要注意,如下:



四、已序區間算法 (lower_bound 、upper_bound)


使用這些算法的前提是區間已經是有序的。

C++ Code?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
//?TEMPLATE?FUNCTION?lower_bound
template?<?class?_FwdIt,
?????????class?_Ty,
?????????class?_Diff?>?inline
_FwdIt?_Lower_bound(_FwdIt?_First,?_FwdIt?_Last,?const?_Ty?&_Val,?_Diff?*)
{
????//?find?first?element?not?before?_Val,?using?operator<
????_DEBUG_ORDER_SINGLE(_First,?_Last,?true);
????_Diff?_Count?=?0;
????_Distance(_First,?_Last,?_Count);

????for?(;?0?<?_Count;?)
????{
????????//?divide?and?conquer,?find?half?that?contains?answer
????????_Diff?_Count2?=?_Count?/?2;
????????_FwdIt?_Mid?=?_First;
????????std::advance(_Mid,?_Count2);
????????_DEBUG_ORDER_SINGLE(_Mid,?_Last,?false);

????????if?(_DEBUG_LT(*_Mid,?_Val))
????????????_First?=?++_Mid,?_Count?-=?_Count2?+?1;
????????else
????????????_Count?=?_Count2;
????}
????return?(_First);
}

template?<?class?_FwdIt,
?????????class?_Ty?>?inline
_FwdIt?lower_bound(_FwdIt?_First,?_FwdIt?_Last,?const?_Ty?&_Val)
{
????//?find?first?element?not?before?_Val,?using?operator<
????_ASSIGN_FROM_BASE(_First,
??????????????????????_Lower_bound(_CHECKED_BASE(_First),?_CHECKED_BASE(_Last),?_Val,?_Dist_type(_First)));
????return?_First;
}

lower_bound() 返回第一個“大于等于給定值" 的元素位置,其實還重載了另一個low_bound 版本,如下:


C++ Code?
1
2
3
4
5
6
7
//?TEMPLATE?FUNCTION?lower_bound?WITH?PRED
template?<?class?_FwdIt,
?????????class?_Ty,
?????????class?_Diff,
?????????class?_Pr?>?inline
_FwdIt?_Lower_bound(_FwdIt?_First,?_FwdIt?_Last,
????????????????????const?_Ty?&_Val,?_Pr?_Pred,?_Diff?*)

也就是可以自定義比較邏輯,需要注意的是如果使用這個版本,那么區間應該本來就是按comp 方法排序的,如下面這句話:


The elements are compared using?operator<?for the first version, and?comp?for the second. The elements in the range shall already

?be?sorted?according to this same criterion (operator<?or?comp), or at least?partitioned?with respect to?val.


由于是已序區間,所以函數內用的是二分查找,而兩個版本主要的代碼不同在于:


_DEBUG_LT(*_Mid,?_Val)


_DEBUG_LT_PRED(_Pred, *_Mid, _Val)


upper_bound 與 lower_bound 類似,不過返回的是第一個”大于給定值“ 的元素位置。


示例代碼3:

C++ Code?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
#include?<iostream>
#include?<vector>
#include?<list>
#include?<algorithm>
using?namespace?std;

void?print_element(int?n)
{
????cout?<<?n?<<?'?';
}


int?main(void)
{
????int?a[]?=?{?1,?10,?10,?14,?15,?16?};
????vector<int>?v(a,?a?+?6);

????for_each(v.begin(),?v.end(),?print_element);
????cout?<<?endl;

????vector<int>::iterator?it;
????it?=?lower_bound(v.begin(),?v.end(),?10);
????if?(it?!=?v.end())
????{
????????cout?<<?it?-?v.begin()?<<?endl;
????}

????it?=?upper_bound(v.begin(),?v.end(),?10);
????if?(it?!=?v.end())
????{
????????cout?<<?it?-?v.begin()?<<?endl;
????}

????return?0;
}


五、數值算法(accumulate)


C++ Code?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
//?TEMPLATE?FUNCTION?accumulate
template?<?class?_InIt,
?????????class?_Ty?>?inline
_Ty?_Accumulate(_InIt?_First,?_InIt?_Last,?_Ty?_Val)
{
????//?return?sum?of?_Val?and?all?in?[_First,?_Last)
????_DEBUG_RANGE(_First,?_Last);
????for?(;?_First?!=?_Last;?++_First)
????????_Val?=?_Val?+?*_First;
????return?(_Val);
}

template?<?class?_InIt,
?????????class?_Ty?>?inline
_Ty?accumulate(_InIt?_First,?_InIt?_Last,?_Ty?_Val)
{
????//?return?sum?of?_Val?and?all?in?[_First,?_Last)
????return?_Accumulate(_CHECKED_BASE(_First),?_CHECKED_BASE(_Last),?_Val);
}

//?TEMPLATE?FUNCTION?accumulate?WITH?BINOP
template?<?class?_InIt,
?????????class?_Ty,
?????????class?_Fn2?>?inline
_Ty?_Accumulate(_InIt?_First,?_InIt?_Last,?_Ty?_Val,?_Fn2?_Func)
{
????//?return?sum?of?_Val?and?all?in?[_First,?_Last),?using?_Func
????_DEBUG_RANGE(_First,?_Last);
????_DEBUG_POINTER(_Func);
????for?(;?_First?!=?_Last;?++_First)
????????_Val?=?_Func(_Val,?*_First);
????return?(_Val);
}

template?<?class?_InIt,
?????????class?_Ty,
?????????class?_Fn2?>?inline
_Ty?accumulate(_InIt?_First,?_InIt?_Last,?_Ty?_Val,?_Fn2?_Func)
{
????//?return?sum?of?_Val?and?all?in?[_First,?_Last),?using?_Func
????return?_Accumulate(_CHECKED_BASE(_First),?_CHECKED_BASE(_Last),?_Val,?_Func);
}


accumulate 重載了兩個版本,第一個版本實現的是累加,第二個版本帶_Func 參數,可以自定義計算,比如累乘等。代碼都比較好理解,就不贅述


了。看下面的示例代碼4:

C++ Code?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
#include?<iostream>
#include?<vector>
#include?<list>
#include?<algorithm>
#include?<numeric>
using?namespace?std;

void?print_element(int?n)
{
????cout?<<?n?<<?'?';
}

int?mult(int?a,?int?b)
{
????return?a?*?b;
}

int?main(void)
{
????int?a[]?=?{?1,?2,?3,?4,?5?};
????vector<int>?v(a,?a?+?5);

????for_each(v.begin(),?v.end(),?print_element);
????cout?<<?endl;

????//?累加
????cout?<<?accumulate(v.begin(),?v.end(),?0)?<<?endl;

????//?累乘
????cout?<<?accumulate(v.begin(),?v.end(),?1,?mult)?<<?endl;

????return?0;
}

參考:

C++ primer 第四版
Effective C++ 3rd
C++編程規范


總結

以上是生活随笔為你收集整理的从零开始学C++之STL(七):剩下5种算法代码分析与使用示例(remove 、rotate 、sort、lower_bound、accumulate)的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。