STL编程
参考资料
=======================================================
- 30分钟掌握STL:http://net.pku.edu.cn/~yhf/UsingSTL.htm
- 双向链表list的使用:http://www.cnblogs.com/fangyukuan/archive/2010/09/21/1832364.html (STL中最好的的入手点就是list,方便的实现内存优化)
STL简介
=======================================================
STL = Standard Template Library,标准模板库,惠普实验室开发的一系列软件的统称。它是由Alexander Stepanov、Meng Lee和David R Musser在惠普实验室工作时所开发出来的。这可能是一个历史上最令人兴奋的工具的最无聊的术语。从根本上说,STL是一些“容器”的集合,这些“容器”有list,vector,set,map等,STL也是算法和其他一些组件的集合。这里的“容器”和算法的集合指的是世界上很多聪明人很多年的杰作。STL的目的是标准化组件,这样就不用重新开发,可以使用现成的组件。STL现在是C++的一部分,因此不用额外安装什么。
STL被内建在你的编译系统之内。STL的版本很多,常见的有HP STL、PJ STL、 SGI STL等。
在C++标准中,STL被组织为下面的13个头文件:
<algorithm>、<deque>、<functional>、<iterator>、<array>、<vector>、<list>、<forward_list>、<map>、<unordered_map>、<memory>、<numeric>、<queue>、<set>、<unordered_set>、<stack>和<utility>。
入门例程
=======================================================
|
#include <iostream>
#include <algorithm>
#include <vector>
using namespace std;
vector<int> intVector(100);
int main()
{
intVector[20] = 50;
vector<int>::iterator intIter =
find(intVector.begin(), intVector.end(), 50);
if (intIter != intVector.end())
{
printf("%d %d\n", intVector.begin(), intVector.end());
printf("Vector contains value %d\n", *intIter);
}
system("pause");
return 0;
}
|
从这里面能看到不少好玩的东西,首先,这个begin(), end()确实不好接受,并不是顺次的,可能内部根本就是链表实现的。一切都以指针扫描为基准,实现不同数据类型的统一操作。
find模板函数的定义:
|
template <class InputIterator, class T>
InputIterator find( InputIterator first, InputIterator last, const T& value)
{
}
|
注意 :在 find() 算法中,注意如果 first 和 last 指向不同的容器,该算法可能陷入死循环。
使用copy进行数组赋值:
|
#include <iostream>
#include <algorithm>
#include <vector>
using namespace std;
double darray[10] = {1.0,1.1,1.2,1.3, 1.4, 1.5, 1.6, 1.7, 1.8, 1.9};
vector<double> vdouble(20);
int main()
{
vector<double>::iterator outputIterator = vdouble.begin();
copy(darray, darray + 10, outputIterator);
replace(vdouble.begin(), vdouble.end(), 1.5 , 3.14159);
while (outputIterator != vdouble.end())
{
cout << *outputIterator << " ";
outputIterator++;
}
cout << endl;
return 0;
}
|
注意:当使用copy()算法的时候,你必须确保目标容器有足够大的控件,或者容器本身是自动扩展的。
前推迭代器能够读写数据值,并能够向前推进到下一个值。但是没法递减。
replace()算法显示了前推迭代器的使用方法:
|
template <class ForwardIterator, class T>
void replace (ForwardIterator first, ForwardIterator last, const T& old_value, const T& new_value);
|
使用replace()将[first, last]范围内的所有值为old_value的对象替换为new_value。:
数组排序和输出流迭代器
========================================================
|
#include <iostream>
#include <stdlib.h> // Need random(), srandom()
#include <time.h> // Need time()
#include <algorithm>// Need sort(), copy()
#include <vector> // Need vector
using namespace std;
void Display(vector<int>& v, const char* s);
int main()
{
// Seed the random number generator
srand(time(NULL));
// Construct vector and fill with random integer values
vector<int> collection(10);
for (int i = 0; i < 10; i++)
collection[i] = rand() % 10000;
// Display, sort, and redisplay
Display(collection, "Before sorting");
sort(collection.begin(), collection.end());
Display(collection, "After sorting");
return 0;
}
// Display label s and contents of integer vector v
void Display(vector<int>& v, const char* s)
{
cout << endl << s << endl;
copy(v.begin(), v.end(), ostream_iterator<int>(cout, "\t"));
cout << endl;
}
|
插入迭代器
=====================================================
|
#include <iostream>
#include <stdlib.h> // Need random(), srandom()
#include <time.h> // Need time()
#include <algorithm>// Need sort(), copy()
#include <vector> // Need vector
#include <list>
using namespace std;
int iArray[5] = { 1, 2, 3, 4, 5 };
void Display(list<int>& v, const char* s);
int main()
{
list<int> iList;
// Copy iArray backwards into iList
copy(iArray, iArray + 5, back_inserter(iList)); //front_inserter
Display(iList, "Before find and copy");
// Locate value 3 in iList
list<int>::iterator p = find(iList.begin(), iList.end(), 3);
// Copy first two iArray values to iList ahead of p
copy(iArray, iArray + 2, inserter(iList, p));
Display(iList, "After find and copy");
return 0;
}
// Display label s and contents of integer vector v
void Display(list<int>& v, const char* s)
{
cout << endl << s << endl;
copy(v.begin(), v.end(), ostream_iterator<int>(cout, "\t"));
cout << endl;
}
|
混合迭代器函数
============================================================
在涉及到容器和算法的操作中,还有两个迭代器函数非常有用: · advance() 按指定的数目增减迭代器。
· distance() 返回到达一个迭代器所需(递增)操作的数目。 例如: list<int> iList; list<int>::iterator p =
find(iList.begin(), iList.end(), 2); cout << "before: p == " << *p << endl; advance(p, 2); // same as p = p + 2; cout << "after : p == " << *p << endl; int k = 0;
distance(p, iList.end(), k); cout << "k == " << k << endl;
advance()函数接受两个参数。第二个参数是向前推进的数目。对于前推迭代器,该值必须为正,而对于双向迭代器和随机访问迭代器,该值可以为负。 使用 distance()函数来返回到达另一个迭代器所需要的步骤。
注意 distance()函数是迭代的,也就是说,它递增第三个参数。因此,你必须初始化该参数。未初始化该参数几乎注定要失败。
使用for_each调用回调函数
===============================================================
|
#include <iostream>
#include <stdlib.h>
#include <time.h>
#include <vector>
#include <list>
#include <algorithm>
using namespace std;
vector<long> v(24); // Vector object
// Function prototypes
void initialize(long &ri);
void show(const long &ri);
bool isMinus(const long &ri);
int main()
{
srand(time(NULL)); // Seed random generator
for_each(v.begin(), v.end(), initialize); //调用普通函数
cout << "Vector of signed long integers" << endl;
for_each(v.begin(), v.end(), show);
cout << endl;
int count = 0;
vector<long>::iterator p;
p = find_if(v.begin(), v.end(), isMinus);//调用断言函数
while (p != v.end())
{
count++;
p = find_if(p + 1, v.end(), isMinus);
}
cout << "Number of values: " << 24 << endl;
cout << "Negative values : " << count << endl;
return 0;
}
// Set ri to a signed integer value
void initialize(long &ri)
{
ri = ( rand() - (RAND_MAX / 2) );
}
// Display value of ri
void show(const long &ri)
{
cout << ri << " ";
}
// Returns true if ri is less than 0
bool isMinus(const long &ri)
{
return (ri < 0);
}
|
使用accumulate实现累加与乘累加
============================================================
|
#include <iostream>
#include <stdlib.h>
#include <time.h>
#include <vector>
#include <list>
#include <algorithm>
#include <numeric>
#include <functional>
using namespace std;
vector<long> v(10); // Vector object
int main()
{
for (int i = 0; i < 10; i++)
v[i] = i + 1; //像普通数组一样操作容器
// Accumulate the sum of contained values
long sum = accumulate(v.begin(), v.end(), 0);
cout << "Sum of values == " << sum << endl;
long product = accumulate(v.begin(), v.end(), 1, multiplies<long>());//注意这行
cout << "Product of values == " << product << endl;
return 0;
}
|
一些模板类的实现,可以稍微看一点STL的源码,感觉下模板编程
|
// TEMPLATE FUNCTION accumulate
template<class _II, class _Ty> inline
_Ty accumulate(_II _F, _II _L, _Ty _V)
{
for (; _F != _L; ++_F)
_V = _V + *_F;
return (_V);
}
// TEMPLATE FUNCTION accumulate WITH BINOP
template<class _II, class _Ty, class _Bop> inline
_Ty accumulate(_II _F, _II _L, _Ty _V, _Bop _B)
{
for (; _F != _L; ++_F)
_V = _B(_V, *_F);
return (_V);
}
// TEMPLATE STRUCT binary_function
template<class _A1, class _A2, class _R>
struct binary_function
{
typedef _A1 first_argument_type;
typedef _A2 second_argument_type;
typedef _R result_type;
};
// TEMPLATE STRUCT multiplies
template<class _Ty>
struct multiplies : binary_function<_Ty, _Ty, _Ty>
{
_Ty operator()(const _Ty& _X, const _Ty& _Y) const
{
return (_X * _Y);
}
};
|
list使用自定义的类
===========================================================
如果不关心排序之类的功能基本这就没问题了。如果要支持排序,重载下各种运算符即可。从简单的功能开始使用。list的功能强大而健全,要好好利用STL的强大功能。
|
#include <iostream>
#include <stdlib.h>
#include <time.h>
#include <string.h>
#include <vector>
#include <list>
#include <algorithm>
using namespace std;
class STUDENT
{
public:
STUDENT(){}
~STUDENT(){}
STUDENT(char* name, int age)
{
strcpy(m_name, name);
m_age = age;
}
public:
char m_name[128];
int m_age;
};
void show(const STUDENT& stu)
{
printf("name = %10s\tage = %d\n", stu.m_name, stu.m_age);
}
list<STUDENT> students; //空学生链表
int main()
{
students.insert(students.begin(), STUDENT("John", 19));
students.insert(students.begin(), STUDENT("Hanna", 21));
students.insert(students.begin(), STUDENT("Jack", 18));
for_each(students.begin(), students.end(), show);
cout << "There are student: " << students.size() << endl;
return 0;
}
|
总结
===========================================================
尽管很多程序员仍然在使用标准C函数,但是这就好像骑着毛驴寻找Mercedes一样。你当然最终也会到达目标,但是你浪费了很多时间。
尽管有时候使用标准C函数确实方便(如使用sprintf()进行格式化输出)。但是C函数不使用异常机制来报告错误,也不适合处理新的数据类型。而且标准C函数经常使用内存分配技术,没有经验的程序员很容易写出bug来。.
C++标准库则提供了更为安全,更为灵活的数据集处理方式。STL最初由HP实验室的Alexander Stepanov和Meng Lee开发。最近,C++标准委员会采纳了STL,尽管在不同的实现之间仍有细节差别。
STL的最主要的两个特点:数据结构和算法的分离,非面向对象本质。访问对象是通过象指针一样的迭代器实现的;容器是象链表,矢量之类的数据结构,并按模板方式提供;算法是函数模板,用于操作容器中的数据。由于STL以模板为基础,所以能用于任何数据类型和结构。
浙公网安备 33010602011771号