STL提供了一组模板,主要包括:
- 容器
- 迭代器
- 函数对象
- 算法
STL容器用于存储相同类型的数据,算法是完成特定任务的方法,迭代器是用来遍历容器的对象,函数对象可以是类对象或函数指针,STL为各种容器的构造和执行各种操作提供了机制。STL和面向对象思想不相关,是一种泛型编程思想。
1.STL容器
STL容器提供了下面几种数据结构,可以方便的调用它们处理数据。
- string
- vector
- map
- list
- set
vector
vector即矢量,存储了支持随机访问的数据,可以通过重载的下标运算符[]直接读取第8个元素,不必从头遍历前7个元素。
实例1:vector的输入输出及随机访问
#include <iostream>
#include <vector>
using namespace std;
const int NUM = 5;
int main()
{
vector<int> ratings(NUM);
int i;
for(i=0; i<NUM; i++)
cin>>ratings[i];
for(i=0; i<NUM; i++)
cout<<ratings[i]<<"
";
cout<<"4th: "<<ratings[3]<<endl;
return 0;
}
对vector的主要操作包括:
size():获取容器内元素总数
swap():交换两个容器的内容
begin():返回容器的首个元素的迭代器
end():返回指向容器末尾元素下一位置的迭代器
push_back():将元素添加到容器的尾部
erase():删除区间内元素,STL的区间表示都包括前不包括后,即后一个迭代器本身不被处理
实例2:vector添加及删除元素
vector<double> test;
double temp;
while(cin >> temp && temp >=0)
{
test.push_back(temp);
}
test.erase(test.begin(), test.begin() + 10); //如果容器的元素总数不足10个,则会发生地址错误
cout<<"you entered "<<test.size()<<" elements.
";//这时的元素总数在上一步被减去了10个
insert():第一形参表示插入的位置,后两个迭代器表示待处理的元素区间
此外,对于数组通常需要的操作:搜索、排序、随机排序,vector的处理方式是不提供类方法,而是提供非成员函数,这样可尽量减小类的体积,省去大量重复的工作。
实例3:定义并使用非成员函数(包括重载运算符)
#include <iostream>
#include <string>
#include <vector>
#include <algorithm>
using namespace std;
struct Review {
string title;
int rating;
};
bool operator<(const Review &r1, const Review &r2);
bool worseThan(const Review &r1, const Review &r2);
bool FillReview(Review &rr);
void ShowReview(const Review &rr);
int main()
{
vector<Review> books;
Review temp;
while(FillReview(temp))
books.push_back(temp);
if(books.size() > 0)
{
cout<<"size: "<<books.size()<<" ratings:
rating book
";
for_each(books.begin(), books.end(), ShowReview);
sort(books.begin(), books.end());
cout<<"sort by title:
rating book
";
for_each(books.begin(), books.end(), ShowReview);
sort(books.begin(), books.end(), worseThan);
cout<<"sort by rating:
rating book
";
for_each(books.begin(), books.end(), ShowReview);
random_shuffle(books.begin(), books.end());
cout<<"sort shuffle:
rating book
";
for_each(books.begin(), books.end(), ShowReview);
random_shuffle(books.begin(), books.end());
cout<<"sort shuffle2:
rating book
";
for_each(books.begin(), books.end(), ShowReview);
}
else
cout<<"No enteris. ";
cout<<"Bye.
";
return 0;
}
bool operator<(const Review &r1, const Review &r2)
{
if(r1.title < r2.title)
return true;
else if(r1.title == r2.title && r1.rating < r2.rating)
return true;
else
return false;
}
bool worseThan(const Review &r1, const Review &r2)
{
if(r1.rating < r2.rating)
return true;
else
return false;
}
bool FillReview(Review &rr)
{
cout<<"enter book title: ";
getline(cin, rr.title);
if(rr.title == "q")
return false;
cout<<"enter book rating: ";
cin>>rr.rating;
if(!cin)
return false;
while(cin.get() != '
')
continue;
return true;
}
void ShowReview(const Review &rr)
{
cout<<rr.rating<<" "<<rr.title<<endl;
}
list
关联容器
关联容器是对容器的改进,将值与键相关联并使用键查找值,提供了快速查找元素机制。对于容器X,X::value_type用于获取容器值的数据类型,X::key_type用于获取键的数据类型,关联容器通常是通过树实现的。
#include <iostream>
#include <string>
#include <set>
#include <algorithm>
#include <iterator>
int main()
{
using namespace std;
const int N = 6;
string s1[N] = {"atest","aetst","aestt","aetts","atset","atets"};
string s2[N] = {"bingy","bany","bfood","belegant","bdeliver","bfor"};
set<string> A(s1, s1+N);
set<string> B(s2, s2+N);
ostream_iterator<string, char> out(cout, " ");
cout<<"Set A";
copy(A.begin(), A.end(), out);
cout<<endl;
cout<<"Set B";
copy(B.begin(), B.end(), out);
cout<<endl;
cout<<"Union of A and B:
";
set_union(A.begin(), A.end(), B.begin(), B.end(), out);
cout<<endl;
cout<<"Intersection of A and B:
";
set_intersection(A.begin(), A.end(), B.begin(), B.end(), out);
cout<<endl;
cout<<"Difference of A and B:
";
set_difference(A.begin(), A.end(), B.begin(), B.end(), out);
cout<<endl;
set<string> C;
cout<<"Set C:
";
set_union(A.begin(), A.end(), B.begin(), B.end(), insert_iterator<set<string> > (C, C.begin()));
copy(C.begin(), C.end(), out);
cout<<endl;
string s3("grungy");
C.insert(s3);
cout<<"Set C after insertion:
";
copy(C.begin(), C.end(), out);
cout<<endl;
copy(C.lower_bound("ghost"),C.upper_bound("spook"), out);
cout<<endl;
return 0;
}
2.泛型编程和迭代器
面向对象思想关注数据,而泛型编程思想关注算法,两者的唯一共同点是致力于实现数据抽象和代码重用,根本上差别非常大。泛型编程的核心思想是代码独立于数据类型,模板使泛型函数或类得以实现,STL则带来了通用算法。同时,模板使得算法独立于数据类型,迭代器使得算法独立于容器类型,所以两者是STL的核心。
//array
double *find(double *a, int n, double &val)
{
for(int i=0; i<n; ++i)
{
if(val == ar[i])
{
return &ar[i]; //
}
}
return 0; //C++11: return nullptr;
}
//linklist
Node *find(Node *head, const double &val)
{
Node *ret=head;
while(ret!=0)
{
if(ret->data == data)
return ret;
ret=ret->next;
}
return 0;
}
//STL iterator for array
typedef double* iterator;
iterator find_it(iterator it, int n, const double &val)
{
int i=0;
while(i<n)
{
if(*it == val)
return it;
i++;
it++;
}
return 0;
}
//STL iterator for array II
typedef double* iterator;
iterator find_it(iterator begin, iterator end, const double &val)
{
iterator it=begin;
while(it!=end)
{
if(*it == val)
return it;
it++;
}
return end;
}
//STL iterator for LinkList
struct Node {
double data;
Node *next;
};
class iterator {
private:
Node *node_;
public:
iterator() : node_(0) {}
iterator(Node *node) : node_(node) {}
double operator*() { return node_->data; }
iterator &operator++()
{
node_ = node_->next;
return *this;
}
iterator operator++(int)
{
iterator tmp = *this;
node_ = node_->next;
return tmp;
}
};
iterator find_it(iterator begin, const double &val)
{
iterator it=begin;
while(it!=0)
{
if(*it == val)
return it;
it++;
}
return 0;
}