STL入门引导
涉及到的源码:http://download.csdn.net/detail/nuptboyzhb/4239649
STL主要有以下六个大的部分:
l 迭代器(iterators)
迭代器可以理解为一个模板指针;迭代器技术能够使程序反复的对STL容器的内容进行访问;
l 算法(alogrithms)
STL提供了很多的数据结构算法,这些算法在std命名空间中定义,通过#include<algorithm>来获得使用权。如常用的算法有:for_each()、find()、find_if()、count()、replace()、copy()、sort()、merge等
l 容器(containers)
常见的容器有:向量容器vector、双向链表容器list、双端队列容器deque、集合容器set、多重集合容器multiset、映射容器map、多重映射容器multimap
l 函数对象(function objects)
l 内存分配器(allocators)
l 适配器(adapter)
适配器是一种泛化的模板类型。STL提供的适配器主要分为迭代器适配器、函数对象适配器、容器适配器,分别用来进行迭代器、函数对象和容器的转换。
1. 命名空间
用标准的std命名空间,using namespace std;
2. 一些建议
1.在Debug模式下,忽略如下警告信息:#pragma warning(disable: 4786)
2.当定义如下容器时:
不要写成vector <list<int>> veclis;而要vector <list <int> > veclis;也即是在‘>’与‘>’之间,加一个空格;
3. copy算法的巧用
对于如下程序的输出;
#include <string> #include <set> #include <iostream> using namespace std; #pragma warning(disable: 4786) int main(int argc, char* argv[]) { set <string> strset; set <string>::iterator si; strset.insert("cantaloupes"); strset.insert("apple"); strset.insert("orange"); strset.insert("banana"); strset.insert("grapes"); strset.insert("grapes"); // This one overwrites the previous occurrence for (si=strset.begin(); si!=strset.end(); si++) { cout << *si << " "; } cout << endl; return 0; }
我们可以用如下语句,代替for循环的输出:
copy(strset.begin(), strset.end(), ostream_iterator<string>(cout, " "));
4. 如何对一些类应用Map容器
map是一个通过键(key)来获得值的。当你用你自己定义的类,而不是一些数据类型(如int),你必须保证自定义的类包含如下函数和操作;
1. 默认构造函数(通常是空)
2. 拷贝构造函数
3. 重载运算符’=’
以上三点,是必须的,当然,你也可以添加其他的函数和运算符;
举例:
#include <string> #include <iostream> #include <vector> #include <map> using namespace std; class CStudent { public : int nStudentID; int nAge; public : //定义一个空的构造函数 CStudent() { } // Full constructor CStudent(int nSID, int nA) { nStudentID=nSID; nAge=nA; } // 定义一个拷贝构造函数 CStudent(const CStudent& ob) { nStudentID=ob.nStudentID; nAge=ob.nAge; } // 重载运算符 = void operator = (const CStudent& ob) { nStudentID=ob.nStudentID; nAge=ob.nAge; } }; int main(int argc, char* argv[]) { map <string, CStudent> mapStudent; mapStudent["Joe Lennon"] = CStudent(103547, 22); mapStudent["Phil McCartney"] = CStudent(100723, 22); mapStudent["Raoul Starr"] = CStudent(107350, 24); mapStudent["Gordon Hamilton"] = CStudent(102330, 22); // Access via the name cout << "The Student number for Joe Lennon is " << (mapStudent["Joe Lennon"].nStudentID) << endl; return 0; }
5. typedef的应用
例如:
typedef set <int> SET_INT;
typedef SET_INT::iterator SET_INT_ITER
6. 迭代器的注意事项
iterator - For any container other than the vector, you can only step one at a time in a forward direction through the container. That is you can only use the ++ operator, not the -- or += operator on it. For vector only you can use any of +=, --, -=, ++, and all the comparison operators <, <=, >, >=, ==, !=.对于大多数的容器,只能应用如下操作符:++,<,<=,>,>=,==,!=;而对于vector向量容器,还可以使用+=, --, -=, ++运算符。
reverse_iterator - If you want to step backwards instead of forwards through a non-vector container, replace iterator with reverse_iterator,begin() with rbegin(), and end() withrend(), ++ will then traverse backwards.
const_iterator - a forward iterator that returns aconst value. Use this if you want to make it clear that this points to a read-only value.
const_reverse_iterator - a reverse iterator that returns aconst value.
7. 算法
算法时应用在模板中的函数。你可以很轻松的对模板容器中的元素进行排序、搜索、操作、交换。
容器本身并不传递给算法,而是容器的迭代器传递给算法。因此,算法所限制的数据类型是迭代器的数据类型。
举例:
#include <algorithm> // If you want to use an // algorithm this is the header used. #include <numeric> // (For Accumulate) #include <vector> #include <iostream> using namespace std; int testscore[] = {67, 56, 24, 78, 99, 87, 56}; // predicate that evaluates a passed test限定函数 bool passed_test(int n) { return (n >= 60); } // predicate that evaluates a failed test bool failed_test(int n) { return (n < 60); } int main(int argc, char* argv[]) { int total; // 用数组初始化向量容器 vector <int> vecTestScore(testscore, testscore + sizeof(testscore) / sizeof(int)); //生成迭代器vi vector <int>::iterator vi; // 整理和输出向量容器里的值 sort(vecTestScore.begin(), vecTestScore.end()); cout << "Sorted Test Scores:" << endl; for (vi=vecTestScore.begin(); vi != vecTestScore.end(); vi++) { cout << *vi << ", "; } cout << endl; // min_element 返回一个指向最小值的一个迭代器 vi = min_element(vecTestScore.begin(), vecTestScore.end()); cout << "The lowest score was " << *vi << "." << endl; // Same with max_element vi = max_element(vecTestScore.begin(), vecTestScore.end()); cout << "The highest score was " << *vi << "." << endl; // Use a predicate function to determine the number who passed //用一个限定函数,来限定传入值的类型;这里限制的是分数 cout << count_if(vecTestScore.begin(), vecTestScore.end(), passed_test) << " out of " << vecTestScore.size() << " students passed the test" << endl; // and who failed cout << count_if(vecTestScore.begin(), vecTestScore.end(), failed_test) << " out of " << vecTestScore.size() << " students failed the test" << endl; // Sum the scores total = accumulate(vecTestScore.begin(), vecTestScore.end(), 0); // Then display the Average cout << "Average score was " << (total / (int)(vecTestScore.size())) << endl; return 0; }
8. 模板的派生和嵌入
1. 作为类的成员变量;如:
class CParam { string name; string unit; vector <double> vecData; };
2. 继承模板
class CParam : public vector <double> { string name; string unit; };
9. 模板中的模板
为了创建一个更加复杂的数据结构,你可以在一个模板内创建一个模板。最好先用typedef关键字定义该模板。
举例:
#include <iostream> #include <vector> using namespace std; typedef vector <int> VEC_INT; int inp[2][2] = {{1, 1}, {2, 0}}; // Regular 2x2 array to place into the template int main(int argc, char* argv[]) { int i, j; vector <VEC_INT> vecvec; // if you want to do this in all one step it looks like this // vector <vector <int> > vecvec; // Fill it in with the array VEC_INT v0(inp[0], inp[0]+2); // passing two pointers // for the range of values to be copied to the vector VEC_INT v1(inp[1], inp[1]+2); vecvec.push_back(v0); vecvec.push_back(v1); for (i=0; i<2; i++) { for (j=0; j<2; j++) { cout << vecvec[i][j] << " "; } cout << endl; } return 0; } // Output: // 1 1 // 2 0