STL编程

参考资料
=======================================================
  1. 30分钟掌握STL:http://net.pku.edu.cn/~yhf/UsingSTL.htm
  2. 双向链表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)
{
while (first != last && *first != value) ++first;
return first;
 
 
注意 :在 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以模板为基础,所以能用于任何数据类型和结构。
posted on 2014-10-07 09:57  calay  阅读(296)  评论(0)    收藏  举报