您好,登錄后才能下訂單哦!
這篇文章將為大家詳細講解有關C++中算法與泛型算法的示例分析,小編覺得挺實用的,因此分享給大家做個參考,希望大家閱讀完這篇文章后可以有所收獲。
本文包括的算法有:
只讀算法:find()、count()、accumulate()、equal()
寫算法:fill()、fill_n()、back_inserter()、copy()、copy_backward()、replace()、replace_copy()、next_permutation()、prev_permutation()
重排元素算法:sort()、stable_sort()、unique()
一、算法簡介
大多數算法在頭文件algorithm中。標準庫還在頭文件numeric中定義了一組數值泛型算法
算法是如何工作的:
迭代器令算法不依賴于容器類型:算法不依賴于容器所保存的元素類型。只要有一個迭代器可以來訪問元素,就可以進行運算
但算法依賴于元素類型的操作:雖然迭代器令算法不依賴于容器類型,但大多數算法都是用了一個(多個)元素類型上的操作。例如find用元素類型的==運算符完成每個元素與給定值的比較。其他算法可能要求元素類型支持“<”運算符。不過,我們將看到,大多數算法提供了一種方法,允許我們使用自定義的操作來替代默認的運算符
二、泛型算法
標準庫提供了超過100個算法,這些算法都對一個范圍內的元素來進行操作
算法基本上分為3類:是否讀取元素、改變元素、重排元素順序
三、只讀算法
只可以操作容器元素,不可以改變容器內的值
因為是只讀,所以建議使用只讀迭代器(cbegin()、cend())
find()
功能:遍歷一個范圍中是否包含某元素
參數:前2個參數是一個迭代器范圍或者指針范圍。第3個參數是要查找的元素
返回值:成功返回要查找的元素所在的迭代器。失敗返回參數2
//判斷value在vec中是否存在,因為find如果失敗返回的是參數2.所以可以用來判斷是否查找成功 vector<int> vec{ 1,2,3}; int value = 2; auto result=find(vec.cbegin(),vec.cend(), value); cout << "The value " << value << (result == vec.cend() ? "is not present" : "is present") << endl;
vector<string> vec{ "A","B","C" }; auto result=find(vec.cbegin(),vec.cend(), "B"); cout << "The B "<< (result == vec.cend() ? "is not present" : "is present") << endl;
對數組的操作:可以用內置函數begin()、end()作為數組的迭代器,也可以用指針作為迭代器
int arr[] = { 1,2,3,4,5 }; int val = 4; int* result = find(begin(arr), end(arr), val); if (result != end(arr)) { cout << "find succcess,value is:"<< *result<< endl; }
int arr[] = { 1,2,3,4,5 }; int value = 3; auto result = find(arr + 1, arr + 3, value); cout << "The value "<<value<<((result == arr + 3) ?" is not present":"is present")<< endl;
count()
功能:返回元素在指定迭代器范圍內出現的次數
返回值:成功返回出現的次數,沒有返回0
list<int> li{ 1,2,3,66,66,66,100 }; cout <<"The 66 count is:" <<count(li.cbegin(),li.cend(),66)<< endl;
accumulate()
頭文件:numeric
功能:將指定范圍內的元素進行和運算,參數3為和運算的初始值
返回值:返回和運算的結果
注意:此函數操作的元素必須能夠與+運算符進行操作
//計算li元素的和,和的初始值為0 list<int> li{ 1,2,3 }; cout <<"The sum is:" <<accumulate(li.cbegin(),li.cend(),0)<< endl; //6
使用string時,必須顯示地調用,不能夠直接使用字符串,因為這樣會被accumulate函數認為是一個const char*對象而出錯
//正確 ist<string> li{"A","B","C"}; cout <<accumulate(li.cbegin(),li.cend(),string("String:"))<< endl; //String:ABC
//錯誤 list<string> li{"A","B","C"}; cout <<accumulate(li.cbegin(),li.cend(),"String:")<< endl;
//正確 list<string> li{"A","B","C"}; string s = "String:"; cout <<accumulate(li.cbegin(),li.cend(), s)<< endl;
附加:如果想要進行別的運行,例如乘、除等,可以使用參數4.例如下面是對一個數組內的元素進行乘操作(備注:初始化不要填0,否則結果就為0)
int *p = new int[4] {1, 2, 3, 4}; cout << accumulate(p, p + 4, 1,multiplies<int>()) << endl; //24
equal()
功能:用來比較兩個指定范圍內的元素是否都是相同的值(常來比較兩個元素是否相同)
參數:參數1和參數2指定一個容器的范圍。參數3指定另一個容器的開始范圍
比較規則:將參數1和2指定的范圍內的所有元素,查看這些元素是否與參數3所指定的另一個容器的開始處是否都存在(不一定要個數都相同,只要容器1的元素在容器2中都要一一對應)
返回值:都相同返回1。不相同返回0
因為equal調用迭代器完成操作,所以equal可以用來比較兩個不同類型的容器。例如vector<string>和list<const char*>可以進行比較
vector<int> vec1{ 1,2}; vector<int> vec2{ 1,2,3}; vector<int> vec3{ 1,2,3,4}; vector<int> vec4{ 1,2,3,4 }; cout << equal(vec1.cbegin(),vec1.cend(), vec4.cbegin())<< endl; //1 cout << equal(vec2.cbegin(), vec2.cend(), vec4.cbegin()) << endl; //1 cout << equal(vec3.cbegin(), vec3.cend(), vec4.cbegin()) << endl; //1
vector<int> vec1{ 2,3}; vector<int> vec2{ 1,2,3,4 }; cout << equal(vec1.cbegin(),vec1.cend(), vec2.cbegin())<< endl; //0
vector<string> vec1{ "A","B"}; vector<string> vec2{ "B" }; vector<const char*> vec3{ "A","B","C" }; cout << equal(vec1.cbegin(), vec1.cend(), vec3.cbegin()) << endl; //1 cout << equal(vec2.cbegin(), vec2.cend(), vec3.cbegin())<< endl; //0
四、寫算法
可以讀寫容器內的元素,但不可以改變容器的大小。因此操作時要注意容器的大小(例如不能對空容器操作)
因為會改變值,所以不能使用只讀迭代器(cbegin()、cend())
fill()
用來改變指定位置處的元素
參數:參數1、2指定容器的范圍,參數3位要設置的值
vector<int> vec{ 1,2,3,4,5 }; fill(vec.begin(), vec.end(), 0);//將vec全部置為0 for (auto v = vec.cbegin(); v != vec.cend(); v++) cout << *v << endl;
vector<int> vec{ 1,2,3,4,5,6 }; fill(vec.begin(), vec.begin()+vec.size()/2, 66); //將vec的前半部分元素變為66 for (auto v = vec.cbegin(); v != vec.cend(); v++) cout << *v << endl;
fill_n()
用來將指定數量的元素變為某個值
參數:參數1為迭代器起始位置。參數2為要改變的元素個數。參數3為要設定的值
注意:要注意參數2的設定,不能超出容器的大小,也不能對空容器操作
vector<int> vec{ 1,2,3,4,5,6 }; fill_n(vec.begin(), 3, 66); //將vec的前3個元素變為66 for (auto v = vec.cbegin(); v != vec.cend(); v++) cout << *v << endl; fill_n(vec.begin(), vec.size(), 66); //將vec全部變為66 for (auto v = vec.cbegin(); v != vec.cend(); v++) cout << *v << endl;
//下面代碼不會出錯,但是也不會有效果,因為vec是空向量 vector<int> vec; fill_n(vec.begin(), vec.size(), 66); for (auto v = vec.cbegin(); v != vec.cend(); v++) //不打印任何信息 cout << *v << endl;
back_inserter()
又名插入迭代器
參數:為一個容器的引用
返回值:返回與該容器綁定的插入迭代器
功能:常用來返回一個容器的迭代器,然后對此迭代器進行操作
當我們通過返回的插入迭代器賦值時,會自動調用push_back將一個具有給定值的元素添加到容器中
頭文件iterator
vector<int> vec; //空容器 auto it = back_inserter(vec); //返回vec的第一個迭代器 *it = 42; //此時vec有了一個元素,值為42
現在我們可以使用fill_n來給一個空容器賦值:在每次迭代中,back_inserter返回迭代器,因此每次賦值都會在vec上調用push_back,因此fill_n就能夠操作了。下面是在vec的末尾添加10個新的元素
vector<int> vec; fill_n(back_inserter(vec), 10, 0);//通過back_inserter創建一個插入迭代器,然后可以向vec添加元素了 for (auto v = vec.cbegin(); v != vec.cend(); v++) //打印10個0 cout << *v << endl;
copy()
將參數1、2指定范圍的元素拷貝給參數3指定的容器
參數:參數1、2為一個容器的范圍。參數3要接受拷貝的容器起始位置
注意:參數3要有足夠的空間保存拷貝的數據
返回值:返回拷貝目的位置的迭代器值
int arr1[] = { 1,2,3 }; int arr2[sizeof(arr1)/sizeof(*arr1)]; auto ret = copy(begin(arr1), end(arr1), arr2); //將數組1拷貝給數組2。ret為arr2數組最后元素的下一個位置 for (auto i = 0; i < sizeof(arr2) / sizeof(*arr2); i++) { cout << arr2[i]<< endl; }
copy_backward
該函數與copy的不同之處在于:
copy是從第一個元素開始拷貝,而copy_backward是從最后一個元素開始拷貝
copy的第3個參數是接受拷貝的容器起始位置,而copy_backward是目的序列的結束迭代器
會復制前兩個迭代器參數指定的序列。第三個參數是目的序列的結束迭代器
replace()
將指定范圍內指定的元素替換為另一個值
參數:1、2指定替換的范圍。3:目標值,4:替換后的值
vector<int> vec{ 1,0,0,0,5 }; replace(vec.begin(), vec.end(), 0,66); //將vec中為0的全部替換為66 for (auto v = vec.cbegin(); v != vec.cend(); v++) { cout << *v << endl; }
replace_copy()
此函數會保留原容器不變,然后將替換后的結果保存在另一個容器中
參數:參數12位要替換的范圍。參數3位另一個容器的起始位置。參數4目標值。參數5替換后的值
vector<int> vec{ 1,0,0,0,5 }; vector<int> vec2; replace_copy(vec.begin(), vec.end(),back_inserter(vec2), 0,66); //vec的元素保持不變,vec2為替換后的值 for (auto v = vec2.cbegin(); v != vec2.cend(); v++) { cout << *v << endl; }
next_permutation()
功能:對一個迭代區間的數值進行全排列
返回值:會根據前面next_permutation函數的調用,當操作的區間不存在下一個排列時,函數返回false;否則如果可以繼續進行全排列,那么就返回true
//函數原型 #include <algorithm> bool next_permutation(iterator start,iterator end)
演示案例:下面的程序每調用一次next_permutation就會對我們制定的迭代區間進行一次排列,直到得出全部排列之后,返回false
int *p = new int[3] {1, 2, 3}; do { for (int i = 0; i < 3; ++i){ cout << p[i]; } cout << endl; } while (next_permutation(p, p + 3));
prev_permutation()
與next_permutation的功能顯示,區別就是prev_permutation是求當前排列的前一個排列,而next_permutation是求當前排列的下一個排列
五、重排元素算法
sort()、unqie()、stable_sort()
因為會改變值,所以不能使用只讀迭代器(cbegin()、cend())
sort()
將容器內的元素按照運算符“<”的規則排序,從小到大
參數:一個容器的迭代器范圍
vector<int> vec{ 1,4,2,8,4,1 }; sort(vec.begin(), vec.end()); //將vec的值從小到大排序 for (auto v = vec.cbegin(); v != vec.cend(); v++) { cout << *v << endl; }
unique()
相鄰之間如果有重復相同的元素,則刪除重復的元素只保留一個
參數:一個容器的迭代器范圍
返回值:返回刪除重復元素之后的最后一個元素的后一個位置
注意(重點):雖然刪除了元素,但是容器的大小依然沒有變,迭代器也沒有變。所有變為迭代器時一定要注意
vector<int> vec{ 1,1,2,3,4,4,4,5,1 }; auto end_unique=unique(vec.begin(), vec.end()); //for循環時使用unique的返回值,如果使用vec.cend(),那么會打印后面沒有元素位置的亂值 for (auto v = vec.cbegin(); v != end_unique; v++) { cout << *v << endl; }
stable_sort()
也是排序
如果非字符串,就先按照數值的個數排序,個數相同時再按照大小排序
如果是字符串:按照長度排序,長度相同的按照字典排序
vector<int> vec{ 1,10,2,100,4,1 }; stable_sort(vec.begin(), vec.end()); //1,1,2,4,10,100 for (auto v = vec.cbegin(); v != vec.cend(); v++) { cout << *v << endl; }
六、向算法傳遞函數和lambda表達式
注意事項:
向算法傳遞函數或者lambda表達式時要注意。該算法支持調用一元謂詞(參數)還是多元謂詞(參數)
例如:find_if的第3個參數傳遞的函數/lambda只接受一個參數,如果是兩個參數的函數或lambda,那么就不能調用(后面會介紹bind函數解決這個問題)
sort()
bool isMin(const int &s1, const int & s2) { return s1 < s2; } bool isMax(const int &s1, const int & s2) { return s1 > s2; } vector<int> vec{1,2,3,4,5}; sort(vec.begin(), vec.end(), isMin); //從小到大排序 sort(vec.begin(), vec.end(), isMax); //從大到小排序 //使用lambda表達式 sort(vec.begin(), vec.end(), [](const int &a, const int &b) {return a < b; });//從小到大排序 sort(vec.begin(), vec.end(), [](const int &a, const int &b) {return a > b; });//從大到小排序
stable_sort()
//按照長度排序,長度相同的按照字典排序 bool isShorter(const string &s1, const string & s2) { return s1.size() < s2.size(); } vector<string> vec{"fox","jumps","over","quick","res","slow","the","turtle"}; stable_sort(vec.begin(), vec.end(), isShorter); for (auto v = vec.cbegin(); v != vec.cend(); v++) { cout << *v << endl; }
find_if()
用來在指定范圍內查找比指定值大/下的元素
如果是大于(那么就是最大的那個)。如果是小于(那么就是比他小一個的那個)
參數3:為一個函數指針或者lambda表達式
返回值:存在就返回這個值,不存在返回尾迭代器
vector<int> vec{ 1,2,3,4,5 }; int sz = 4; //在vec中尋找比sz大的數 auto wc=find_if(vec.begin(), vec.end(), [sz](const int &a) {return a > sz; }); //查找比sz大的 auto wc2=find_if(vec.begin(), vec.end(), [sz](const int &a) {return a < sz; }); //查找比sz小的 cout << *wc << endl; //5 cout << *wc2 << endl; //3
for_each()
用來遍歷一個集合
參數:參數12是一個容器的迭代器范圍。參數3lambda表達式
vector<int> vec{ 1,2,3,4,5 }; for_each(vec.begin(), vec.end(), [](const int&s) {cout << s << " "; }); cout << endl;
vector<string> vec{ "ABC","AB","A","sd" }; for_each(vec.begin(), vec.end(), [](const string&s) {cout << s << " "; }); cout << endl;
transform()
參數:參數12為輸入序列。參數3為目的位置
該算法對輸入序列中每個元素調用課調用對象,并將結果寫到目的位置
下面使用transform算法和一個lambda表達式來將vector中的每個負數替換為絕對值。因為參數3位vec.begin(),所以就是將vec的全部元素取絕對值然后再寫入vec的開頭
vector<int> vec{ -1,-2,-3,4 }; //將vec的數全部取絕對值 transform(vec.begin(), vec.end(), vec.begin(), [](int i) {return i < 0 ? -i : i; }); for (auto v = vec.begin() ; v != vec.end(); ++v) cout <<*v << endl;
關于“C++中算法與泛型算法的示例分析”這篇文章就分享到這里了,希望以上內容可以對大家有一定的幫助,使各位可以學到更多知識,如果覺得文章不錯,請把它分享出去讓更多的人看到。
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。