本章都是些STL算法的使用,意思明確,代碼簡介,所以直接寫代碼,實踐一下各種算法。
算法永遠不會改變底層容器大小,智可能改變容器中保存的元素,也可能移動元素,但不會直接添加或刪除元素;
除了insert iterator,重載了賦值運算符。但算法自身永遠不會做這樣的操作;
//find count
vector<int> v1{1, 2, 3, 4, 3, 3};
auto iter = find(v1.begin(), v1.end(), 6);
if (iter != v1.end()) {
cout << *iter << endl;
} else {
cout << "not found" << endl;
}
auto iter = count(v.begin(), v.end(), 3);
cout << iter << endl;
只讀算法:只會讀取其輸入范圍中的元素,不會改變元素
對於只讀算法,最好調用cbegin()和cend();但如果需要用算法返回的迭代器來改變元素,就需要用begin()和end()
vector<int> v{1, 2, 3, 4, 3, 3};
vector<int> v1{1, 2, 3, 4, 3, 3};
vector<int> v2{1, 2, 3, 4, 5, 6};
vector<string> vsa{"tx", "bd", "al", "ms", "ne"};
vector<string> vsb{"tx", "xm", "bd"};
//accumulate
//算法的第三個數據類型決定了調用那個加法運算符以及返回類型
//序列中的元素必須與第三個參數匹配,或者能轉換為第三個類型的參數
{
int sum = accumulate(v.begin(), v.end(), 0);
//錯誤:const char*沒有+運算符
// string ssum = accumulate(vs.begin(), vs.end(), "");
string ssum;
ssum = accumulate(vsa.cbegin(), vsa.cend(), ssum);
cout << ssum << endl;
}
//equal
//1 equal利用迭代器完成操作,因此,可以利用不同類型的容器中的元素,只要保證能用==來比較兩個元素類型即可
//2 基於一個重要的假設:第二個序列至少與第一個序列一樣長;因此,如果想判斷兩個序列完全相等,必須先判斷size
//3 對於只接受單一迭代器表示第二個序列的算法,都假定第二個序列至少與第一個序列一樣長
{
vector<string> vs1{"tx", "xm", "bd"};
vector<const char*> vs2{"tx", "xm", "bd", "al"};
cout << equal(vs1.cbegin(), vs1.cend(), vs2.cbegin()) << endl;
if (vs1.size() == vs2.size() &&
equal(vs1.cbegin(), vs1.cend(), vs2.cbegin())) {
cout << "equal range";
} else {
cout << "non equal";
}
}
小問題:如果兩個vector中保存的都是const char* 不是string, equal會發生什么?
解答:string類重載了==,可比較兩個字符串長度是否向指向其中元素對應位是否相等。
而const char* 本質上是指針類型,用==比較指針對象,僅僅是比較的是地址是否相等,而不是比較其中的字符是否相同;因此,失去了使用equal的邏輯意義。
一些算法會將新值賦予序列中的元素。當使用這些算法時,確保原序列大小至少不小於要求算法寫入的元素數目;
不論如何,算法本身不會執行容器操作,算法自身不可能改變容器大小。(除了inserter)
用到的自定義函數:
template <typename T>
inline void InsertElement(T& v, int first, int last) {
for (int i = first; i <= last; ++i) {
v.insert(v.end(), i);
}
}
template <typename T>
inline void PrintElement(const T& v, const string& s = "") {
if ("" != s) {
cout << s << ": ";
}
for (const auto & elem : v) {
cout << elem << " ";
}
cout << endl;
}
具體算法使用如下:
//fill 將給定序列賦予給定的值
{
vector<int> v1;
InsertElement(v1, 1, 8);
PrintElement(v1);
fill(v1.begin(), v1.end(), 99);
PrintElement(v1);
}
//fill_n 將給定值賦給迭代器指向的元素開始的指定個元素
//該算法假定寫入n個元素是安全的;
{
vector<int> v;
InsertElement(v, 1, 8);
fill_n(v.begin(), v.size(), 1);
PrintElement(v);
//初學容易犯的錯誤是:在空容器上調用fill_n
vector<int> v2;
// fill_n(v2.begin(), 10, 0); //災難
//合法。因為back_inserter會調用容器的push_back,即此時不再是賦值,而是插入
fill_n(back_inserter(v2), 10, 12);
PrintElement(v2);
}
//copy
{
//copy:傳遞給copy的目的序列至少要包含與輸入序列一樣多的元素
vector<int> v(10, 0);
list<int> l(10, 2);
PrintElement(l);
copy(v.begin(), v.end(), l.begin());
PrintElement(l);
list<int> ll;
copy(v.begin(), v.end(), back_inserter(ll));
PrintElement(v, "copy back_inserter");
}
//replace
//replace_copy
{
//replace(v.begin(), v.end(), a, b); 將輸入序列中a替換為b
vector<int> src{3, 3, 1, 1, 1, 1, 1, 4};
PrintElement(src);
//replace
replace(src.begin(), src.end(), 3, 9);
PrintElement(src); //直接修改源序列
//replace_copy
vector<int> dest2(src.size());
replace_copy(src.begin(), src.end(), dest2.begin(), 1, 3);
PrintElement(dest2);
//replace_copy back_inserter
vector<int> dest;
replace_copy(src.begin(), src.end(), back_inserter(dest), 1, 0);
PrintElement(src); //不直接修改源序列修改
PrintElement(dest); //把修改后的序列插入到dest中
}
//reverse
//reverse_copy
{
vector<int> v;
InsertElement(v, 1, 9);
PrintElement(v, "before reverse");
reverse(v.begin(), v.end());
PrintElement(v, "afer reverse");
vector<int> vi;
reverse_copy(v.begin(), v.end(), back_inserter(vi));
PrintElement(v, "reverse source");
PrintElement(vi, "reverse_copy");
}
//unique
//unique將相鄰的重復項“消除”, 返回一個指向不重復值范圍的末尾迭代器;
//“消除”指的是用覆蓋相鄰的重復元素
{
vector<string> vs{"the", "quick", "red", "fox", "jumps", "over", "the","slow", "red", "turtle"};
PrintElement(vs, "before sort");
sort(vs.begin(), vs.end());
PrintElement(vs, "after sort");
auto end_unique = unique(vs.begin(), vs.end()); //此時並沒有消除重復的元素
vs.erase(end_unique, vs.end());
PrintElement(vs, "after unique");
}
向算法傳遞函數:
sort函數默認使用元素類型的<運算符排序,但有時還希望按照長度排序;長度相同時按再按照字典序排序,為了能按照長度排序,將使用sort的第二個版本。
此版本是重載過的,接受第三個參數,此參數是一個謂詞(predicate):一個可調用表達式,返回結果是一個可以用作條件的值
ex1:按字典序重排word,消除重復元素;按長度重排,長度相同維持字典序
//自定義操作
bool isShorter(const string& s1, const string& s2) {
return s1.size() < s2.size();
}
vector<string> vs{"the", "quick", "red", "fox", "jumps", "over", "the","slow", "red", "turtle"};
sort(words.begin(), words.end());
auto end_unique = unique(words.begin(), words.end());
words.erase(end_unique, words.end());
stable_sort(vs.begin(), vs.end(), isShorter); //向算法傳遞函數參數
ex2:打印出長度大於等於5的元素
//自定義操作
bool longer_than_5(const string& s) {
return s.size() >= 5;
}
auto end_partition = partition(vss.begin(), vss.end(), longer_than_5);
for (auto iter = vss.begin(); iter != end_partition; ++iter) {
cout << *iter << " ";
}
在上個例子中,如果要求算法分割的長度大於等於n,此時,自定義函數無能為力,因為算法只接受一個函數參數。而長度n應該是程序中的變量,要想讓算法能夠使用該變量,需要使用lambda表達式。
詳情見下篇文檔簡述泛型算法之 二lambda表達式
本站转载的文章为个人学习借鉴使用,本站对版权不负任何法律责任。如果侵犯了您的隐私权益,请联系我们删除。