STL学习笔记--非变易算法
非变易算法
C++ STL 的非变易算法(Non-mutating algorithm)是一组不破坏操作数据的模板函数,用来对序列数据进行逐个处理、元素查找、子序列搜索、统计和匹配。作为算法函数参数的迭代器,一般为 Input Iterator 输入迭代器,具有 "++" 迭代和 "*" 访问操作。通过迭代器的元素遍历,可对迭代器区间所界定的元素进行操作。因此,非变易算法具有极为广泛的适用性,基本上可应用于各种容器。
目录:
逐个容器元素 for_each
1 /* 下面的示例程序将 list 链表容器的元素,调用 for_each 算法函数,通过 print 函数对象,将各个链表的元素乘以3后打印,并输出元素个数 2 */ 3 -------------------------------------------------------- 应用 for_each 算法遍历 list 容器 4 #include <algorithm> // 这个头文件很重要的哦 5 #include <list> 6 #include <iostream> 7 using namespace std; 8 9 struct print 10 { 11 int count; // 打印的元素计数 12 print(){count=0;} 13 void operator() (int x) 14 { 15 cout << 3*x << endl; 16 count++; 17 } 18 }; 19 20 int main() 21 { 22 // 双向链表初始化 23 list<int> lInt; 24 lInt.push_back(29); 25 lInt.push_back(32); 26 lInt.push_back(16); 27 lInt.push_back(22); 28 lInt.push_back(28); 29 lInt.push_back(27); 30 31 // 打印链表的元素 32 print p = for_each(lInt.begin(), lInt.end(), print()); 33 // 打印的元素个数 34 cout <<"元素个数为:"<<p.count << endl; 35 36 return 0; 37 }
查找容器元素 find
1 /* 下面示例程序利用 find 算法函数查找 list 链表中第一个值为 14 的元素 2 */ 3 -------------------------------------------------------- 应用 find 算法查找 list 容器的元素 4 #include <algorithm> 5 #include <list> 6 #include <iostream> 7 using namespace std; 8 int main() 9 { 10 // 双向链表初始化 11 list<int> lInt; 12 lInt.push_back(100); 13 lInt.push_back(10); 14 lInt.push_back(14); 15 lInt.push_back(13); 16 lInt.push_back(14); 17 lInt.push_back(40); 18 19 // 查找元素 14 20 list<int>::iterator iLocation = find(lInt.begin(), lInt.end(), 14); 21 if (iLocation != lInt.end()) 22 cout << "找到元素14 " << endl; 23 24 // 打印第一个14元素前面的那个元素。即打印元素 10 25 cout << "前一个元素为:" << *(--iLocation) << endl; 26 27 return 0; 28 }
条件查找容器元素 find_if
1 /* 下面示例程序使用 find_if 算法在 vector 向量容器上查找首个可被5整除的元素,程序输出为“找到第一个能被5整除的元素15,元素的索引位置为2” 2 */ 3 -------------------------------------------------------- 应用 find_if 算法条件查找 vector 容器的元素 4 #include <algorithm> 5 #include <vector> 6 #include <iostream> 7 using namespace std; 8 9 // 谓词判断函数 divby5 10 bool divby5(int x) 11 { 12 return x%5 ? 0 : 1; 13 } 14 15 int main() 16 { 17 vector<int> vInt(20); // 可以参考之前对 vector 的介绍 18 for (unsigned int i=0; i<vInt.size(); i++) 19 vInt[i] = (i+1)*(i+3); 20 21 vector<int>::iterator iLocation; 22 iLocation = find_if(vInt.begin(), vInt.end(), divby5); 23 24 if (iLocation != vInt.end()) 25 cout << "找到第一个能被5整除的元素:" 26 << *iLocation << endl // 打印15 27 << "元素的索引位置为:" 28 << iLocation-vInt.begin() << endl; // 打印2 29 30 return 0; 31 }
邻近查找容器元素 adjacent_find
1 /* 调用 adjacent_find 算法函数找出邻近相等的元素11(链表中,有2个11是临近的),再利用是否为奇偶相同,做谓词判断,找出首先同为奇数的 9和11. 2 */ 3 -------------------------------------------------------- 应用 adjacent_find 算法临近查找容器的元素 4 #include <algorithm> 5 #include <list> 6 #include <iostream> 7 using namespace std; 8 9 bool parity_equal (int x, int y) 10 { 11 return (x-y)%2 == 0 ? 1 :0; 12 } 13 14 int main() 15 { 16 // 初始化链表 17 list<int> lInt; 18 lInt.push_back(3); 19 lInt.push_back(6); 20 lInt.push_back(9); 21 lInt.push_back(11); 22 lInt.push_back(11); 23 lInt.push_back(18); 24 lInt.push_back(20); 25 lInt.push_back(20); 26 // 查找邻接相等的元素 27 list<int>::iterator iResult = adjacent_find(lInt.begin(), lInt.end()); 28 if (iResult != lInt.end()) 29 { 30 cout << "发现链表有两个邻接的元素相等" << endl; 31 cout << *iResult << endl; // 打印第1 个11 32 ++iResult; 33 cout << *iResult << endl; // 打印第2 个11 34 } 35 36 // 查找奇偶性相同的邻接元素 37 iResult = adjacent_find(lInt.begin(), lInt.end(), parity_equal); 38 if (iResult != lInt.end()) 39 { 40 cout << "发现有两个邻接元素的奇偶性相同" << endl; 41 cout << *iResult << endl; // 打印 9 42 ++iResult; 43 cout << *iResult << endl; // 打印 11 44 } 45 46 return 0; 47 }
范围查找容器元素 find_first_of
1 /* 下面示例程序在字符串 "abcdef7ghijklmn" 中查找首个出现在字符串 "zyx3pr7ys" 的字符,结果当然是字符 7 2 */ 3 -------------------------------------------------------- 应用 find_first_of 算法范围查找容器元素 4 #include <algorithm> 5 #include <iostream> 6 using namespace std; 7 int main() 8 { 9 // 定义2个字符串 10 char* str1 = "abcdef7ghijklmn"; 11 char* str2 = "zyx3pr7ys"; 12 // 范围查找 str1 于 str2 中 13 char* result = find_first_of(str1, str1 + strlen(str1), 14 str2, str2 + strlen(str2)); 15 cout << "字符串 str1 的第一个出现在 str2 的字符为:" 16 << *result << endl; // 打印 7 17 18 return 0; 19 }
统计等于某值的容器元素个数 count
1 /* 下面的示例程序链入100个20的余数到双向链表 list 中,然后统计其中等于 9 的元素个数。 2 */ 3 4 -------------------------------------------------------- 应用 count 算法统计等于某值的容器元素个数 5 #include <algorithm> 6 #include <list> 7 #include <iostream> 8 using namespace std; 9 int main() 10 { 11 // 链表初始化 12 list<int> lInt; 13 for (int i=0; i<100; i++) 14 lInt.push_back(i%20); 15 // 统计链表中等于 value 值的元素个数 16 int num = 0; 17 int value = 9; 18 num = count(lInt.begin(), lInt.end(), value); 19 cout << "链表中元素等于 value 的元素个数为:" 20 << num << endl; // 打印5 21 22 return 0; 23 }
条件统计容器元素个数 count_if
1 /* 下面示例程序,将学生记录放入使用红黑树的 map 容器,然后利用一元谓词判断 setRange20_30 ,统计年龄在20至30岁之间的学生人数 2 */ 3 4 -------------------------------------------------------- 应用 count_if 算法统计满足条件的记录数 5 #pragma warning(disable:4786) 6 #include <algorithm> 7 #include <map> 8 #include <iostream> 9 using namespace std; 10 11 // 学生记录结构体 12 struct StudentRecord 13 { 14 struct StudentInfo 15 { 16 char* name; 17 int year; 18 char* addr; 19 }; 20 int id; // 学号 21 StudentInfo sf; // 学生信息 22 StudentRecord(int id_, char* name_, int year_, char* addr_) 23 { 24 id = id_; 25 sf.name = name_; 26 sf.year = year_; 27 sf.addr = addr_; 28 } 29 }; 30 31 bool setRange20_30(pair<int, StudentRecord::StudentInfo> s) 32 { 33 // 20 < x < 30 34 if (s.second.year > 20 && s.second.year < 30) 35 return 1; 36 37 return 0; 38 } 39 40 int main() 41 { 42 // 学生数据 43 StudentRecord st1 = StudentRecord(1, "李强", 21, "北京"); 44 StudentRecord st2 = StudentRecord(2, "李文", 29, "山东"); 45 StudentRecord st3 = StudentRecord(3, "张三", 12, "江苏"); 46 StudentRecord st4 = StudentRecord(4, "李四", 23, "武汉"); 47 StudentRecord st5 = StudentRecord(5, "王五", 32, "上海"); 48 49 // 映照容器 50 map<int, StudentRecord::StudentInfo> m; 51 // 插入 5条学生记录 52 pair<int, StudentRecord::StudentInfo> pairSt1(st1.id, st1.sf); 53 m.insert(pairSt1); 54 pair<int, StudentRecord::StudentInfo> pairSt2(st2.id, st2.sf); 55 m.insert(pairSt2); 56 pair<int, StudentRecord::StudentInfo> pairSt3(st3.id, st3.sf); 57 m.insert(pairSt3); 58 pair<int, StudentRecord::StudentInfo> pairSt4(st4.id, st4.sf); 59 m.insert(pairSt4); 60 pair<int, StudentRecord::StudentInfo> pairSt5(st5.id, st5.sf); 61 m.insert(pairSt5); 62 63 // 条件统计 64 int num = 0; 65 num = count_if(m.begin(), m.end(), setRange20_30); 66 cout << "年龄介于20至30之间的学生人数为:" 67 << num << endl; // 打印 3 68 69 return 0; 70 }
元素不匹配查找 mismatch
1 /* 下面示例程序,分别使用了 mismatch 算法函数的两种形式。 2 */ 3 4 -------------------------------------------------------- 应用 msimatch 算法比较两个序列的元素 5 #include <algorithm> 6 #include <vector> 7 #include <iostream> 8 using namespace std; 9 10 bool strEqual(const char* s1, const char* s2) 11 { 12 return strcmp(s1, s2) == 0 ? 1: 0; 13 } 14 15 int main() 16 { 17 vector<int> v1, v2; 18 v1.push_back(2); 19 v1.push_back(0); 20 v1.push_back(0); 21 v1.push_back(6); 22 23 v2.push_back(2); 24 v2.push_back(0); 25 v2.push_back(0); 26 v2.push_back(7); 27 28 // v1 和 v2 不匹配检查 29 pair<vector<int>::iterator, vector<int>::iterator> result = mismatch(v1.begin(), v1.end(), v2.begin()); 30 31 if (result.first == v1.end() && result.second == v1.end()) 32 cout << "v1 和 v2 完全相同" << endl; 33 else 34 cout << "v1 和 v2 不相同,不匹配的数是:\n" 35 << *result.first << endl 36 << *result.second << endl << endl; 37 38 39 // 初始化字符串 s1、s2 40 char* s1[]={"apple", "pear", "watermelon", "banana", "grape"}; 41 char* s2[]={"apple", "pears", "watermelons", "banana", "grape"}; 42 // s1 和 s2 不匹配检查 43 pair<char**, char**> result2 = mismatch(s1, s1+5, s2, strEqual); 44 if (result2.first == s1+5 && result2.second == s2+5) 45 cout << "s1和s2完全相同" << endl; 46 else 47 cout << "s1 与 s2不相同,不匹配的字符串为:\n" 48 << s1[result2.first - s1] << endl 49 << s2[result2.second - s2] << endl << endl; 50 51 return 0; 52 }
元素相等判断 equal
1 /* 下面示例程序,利用二元谓词判断 absEqual ,判断出两个 vector 向量容器的元素均绝对值相等。 2 */ 3 4 -------------------------------------------------------- 应用 equal 算法判断容器元素是否绝对值相等 5 #include <algorithm> 6 #include <vector> 7 #include <iostream> 8 using namespace std; 9 10 bool absEqual(int a, int b) 11 { 12 return (a==abs(b) || abs(a)==b) ? 1 : 0; 13 } 14 15 int main() 16 { 17 vector<int> v1(5); 18 vector<int> v2(5); 19 for (unsigned int i=0; i<v1.size(); i++) 20 { 21 v1[i] = i; 22 v2[i] = -1 * i; 23 } 24 25 // v1、v2 相等检查 26 if (equal(v1.begin(), v1.end(), v2.begin(), absEqual)) 27 cout << "v1 和 v2 元素的绝对值完全相等" << endl; 28 else 29 cout << "v1 和 v2 元素的绝对值不完全相等" << endl; 30 31 return 0; 32 }
子序列搜索 search
1 /* 下面示例程序,搜索 vector 向量 V1={5, 6, 7, 8, 9}是否包含子序列向量容器 v2={7, 8}. 2 */ 3 4 -------------------------------------------------------- 应用 search 方法搜索子序列 5 #include <algorithm> 6 #include <vector> 7 #include <iostream> 8 using namespace std; 9 int main() 10 { 11 // 初始化向量 v1 12 vector<int> v1; 13 v1.push_back(5); 14 v1.push_back(6); 15 v1.push_back(7); 16 v1.push_back(8); 17 v1.push_back(9); 18 // 初始化向量 v2 19 vector<int> v2; 20 v2.push_back(7); 21 v2.push_back(8); 22 // 检查 v2 是否构成 v1 的子序列 23 vector<int>::iterator iterLocation; 24 iterLocation = search(v1.begin(), v1.end(), v2.begin(), v2.end()); 25 // 打印从 v1[2]开始匹配 26 if (iterLocation != v1.end()) 27 cout << "v2 的元素包含在 v1 中,起始元素为:" 28 << "v1[" << iterLocation - v1.begin() << "] \n"; 29 else 30 cout << "v2的元素不包含在v1中." << endl; 31 32 return 0; 33 }
重复元素子序列搜索 search_n
1 /* 下面示例程序,搜索出向量 v={1, 8, 8, 8, 6, 6, 8}中有3个连续元素8、没有4个连续的元素8,以及有2个连续元素6 2 */ 3 4 -------------------------------------------------------- 应用 search_n 算法搜索重复元素值 5 #include <algorithm> 6 #include <vector> 7 #include <iostream> 8 using namespace std; 9 int main() 10 { 11 // 初始化向量 v 12 vector<int> v; 13 v.push_back(1); 14 v.push_back(8); 15 v.push_back(8); 16 v.push_back(8); 17 v.push_back(6); 18 v.push_back(6); 19 v.push_back(8); 20 21 // 查找子序列 {8, 8, 8} 22 vector<int>::iterator iLocation; 23 iLocation = search_n(v.begin(), v.end(), 3, 8); 24 if (iLocation != v.end()) 25 cout << "在v中找到3个连续的元素8" << endl; 26 else 27 cout << "v中没有3个连续的元素8" << endl; 28 29 // 查找子序列 {8, 8, 8, 8} 30 iLocation = search_n(v.begin(), v.end(), 4, 8); 31 if (iLocation != v.end()) 32 cout << "在v中找到4个连续的元素8" << endl; 33 else 34 cout << "v中没有4个连续的元素8" << endl; 35 36 // 查找子序列{6, 6} 37 iLocation = search_n(v.begin(), v.end(), 2, 6); 38 if (iLocation != v.end()) 39 cout << "在v中找到2个连续的元素6" << endl; 40 else 41 cout << "v中没有2个连续的元素6" << endl; 42 43 return 0; 44 }
最后一个子序列搜索 find_end
1 /* 下面示例程序,搜索向量 v1={-5, 1, 2, -6, -8, 1, 2, -11}中最后一个与V2={1, 2}匹配的子序列,打印输出为 "v1中找到最后一个匹配v2的子序列,位置在 v1[5]" 2 */ 3 -------------------------------------------------------- 应用 find_end 算法搜索最后一个匹配子序列 4 #include <algorithm> 5 #include <vector> 6 #include <iostream> 7 using namespace std; 8 int main() 9 { 10 // 初始化向量 v1 11 vector<int> v1; 12 v1.push_back(-5); 13 v1.push_back(1); 14 v1.push_back(2); 15 v1.push_back(-6); 16 v1.push_back(-8); 17 v1.push_back(1); 18 v1.push_back(2); 19 v1.push_back(-11); 20 21 // 初始化向量 v2 22 vector<int> v2; 23 v2.push_back(1); 24 v2.push_back(2); 25 26 // v1中查找最后一个子序列 v2 27 vector<int>::iterator iLocation; 28 iLocation = find_end(v1.begin(), v1.end(), v2.begin(), v2.end()); 29 30 // 打印子序列在 v1 的起始位置 v[5] 31 if (iLocation != v1.end()) 32 cout << "v1中找到最后一个匹配 v2 的子序列,位置在" 33 << "v1[" << iLocation - v1.begin() << "] \n"; 34 35 36 return 0; 37 }
------------ 非变易算法小结
C++ STL 算法库中的非变易算法,是一些原则上不会变更操作数据的算法,包括可逐元素循环提交处理的 for_each 算法、用于元素查找的 find/find_if/adjacent_find/find_first_of 算法、用于统计元素个数的 count/count_if 算法、两序列匹配比较 mismatch/equal 算法和子序列搜索 search/search_n/find_end 算法。