Thinking in C++第二卷笔记之STL容器部分(二)
相关日志
STL的总结
http://blog.163.com/zhoumhan_0351/blog/static/3995422720103174417603/
标准模板类(STL)(四),容器的比较、对比和总结
http://blog.163.com/zhoumhan_0351/blog/static/3995422720102267442299/
标准模板类(STL)(五),算法和函数
http://blog.163.com/zhoumhan_0351/blog/static/39954227201022783524890/
1、list
以一个双向链表数据结构来实现。可以在任何地方快速地插入或删除数据,而对于vectoris,deque而言这个操作是很高的代价的。但是如果想查找对象要频繁的遍历序列,最好不要用list。在元素被添加到list后,迭代器不会失效。通用的sort(),reverse()算法仅适用于数据,vector,deque。
If you have large, complex objects, you might want to choose a list first,
especially if construction, destruction, copy-construction, and assignment are
expensive and if you are doing things like sorting the objects or otherwise
reordering them a lot。
2、集合set
仅接受每个元素的一个副本。
int isalpha(int ch)//测试参数是否为大、小写字母
template<class E>
bool isalpha(E c, const locale& loc) const;
int isspace(int ch)//测试参数是否是空格、制表符或换行符
template<class E>
bool isspace(E c, const locale& loc) const;
template<class E, class T, class A>
basic_istream<E, T>& getline(
basic_istream <E, T>& is,
basic_string<E, T, A>& str);
The first template function returns getline(is, str, is.widen('\n')).If the
function extracts no elements, it calls setstate(failbit). In any case, it returns
*this.和流操作运算符operator>>一样。如果没有遇到物理错误,文件结束,或非法字符, ios_base::operator void*( )调用good()来返回结果。
template<class E, class T, class A>
basic_istream<E, T>& getline(
basic_istream <E, T>& is,
basic_string<E, T, A>& str,
E delim);
例1:提取合法单词
//: C07:WordList.cpp
// Display a list of words used in a document.
#include <algorithm>
#include <cctype>
#include <cstring>
#include <fstream>
#include <iostream>
#include <iterator>
#include <set>
#include <sstream>
#include <string>
using namespace std;
char replaceJunk(char c) {
// Only keep alphas, space (as a delimiter), and '
return (isalpha(c) || c == '\'') ? c : ' ';
}
int main() {
char* fname = "C:\\copy.txt";
ifstream in(fname);
set<string> wordlist;
string line;
while(getline(in, line)) {
transform(line.begin(), line.end(), line.begin(),replaceJunk);
istringstream is(line);
string word;
while(is>>word)
{
wordlist.insert(word);//以空格分开,但是要注意,并不是优先以空格为界定符,而是以数据类型
}
}
// Output results:
copy(wordlist.begin(),wordlist.end(),
ostream_iterator<string>(cout, "\n"));
} ///:~
如下程序为使用输入输出流缓冲迭代器实现:
#include <cstring>
#include <fstream>
#include <iostream>
#include <iterator>
#include <set>
#include <string>
using namespace std;
int main() {
char* fname = "copy.txt";
ifstream in(fname);
istreambuf_iterator<char> p(in), end;//默认构造函数创建的对象为指向流结束位置的,也就是超越末尾的迭代器对象。
set<string> wordlist;
while(p != end) {
string word;
insert_iterator<string> ii(word, word.begin());
// Find the first alpha character:
while(p != end && !isalpha(*p))
++p;
// Copy until the first non-alpha character:
while(p != end && isalpha(*p))
*ii++ = *p++;
if(word.size() != 0)
wordlist.insert(word);
}
// Output results:
copy(wordlist.begin(), wordlist.end(),
ostream_iterator<string>(cout, "\n"));
} ///:~
template<class E, class T = char_traits<E> >
class istreambuf_iterator
: public iterator<input_iterator_tag, T, Dist>
istreambuf_iterator(streambuf_type *sb = 0) throw();
istreambuf_iterator(istream_type& is) throw();
The first constructor initializes the input stream-buffer pointer with sb. The
second constructor initializes the input stream-buffer pointer with is.rdbuf().
4、队列
是一个受到限制的deque形式。只可在一端放,另一端删除。我们用一个“银行出纳员”问题来模拟这个容器的应用。
// Using a queue and simulated multithreading
// to model a bank teller system.
#include <cstdlib>
#include <ctime>
#include <iostream>
#include <iterator>
#include <list>
#include <queue>
using namespace std;
class Customer {
int serviceTime;
public:
Customer() : serviceTime(0) {}
Customer(int tm) : serviceTime(tm) {}
int getTime() { return serviceTime; }
void setTime(int newtime) { serviceTime = newtime; }
friend ostream&
operator<<(ostream& os, const Customer& c) {
return os << '[' << c.serviceTime << ']';
}
};
class Teller {
queue<Customer>& customers;
Customer current;
enum { SLICE = 5 };
int ttime; // Time left in slice
bool busy; // Is teller serving a customer?
public:
Teller(queue<Customer>& cq)
: customers(cq), ttime(0), busy(false) {}
Teller& operator=(const Teller& rv) {
customers = rv.customers;
current = rv.current;
ttime = rv.ttime;
busy = rv.busy;
return *this;
}
bool isBusy() { return busy; }
void run(bool recursion = false) {
if(!recursion)
ttime = SLICE;
int servtime = current.getTime();
if(servtime > ttime) {
servtime -= ttime;
current.setTime(servtime);
busy = true; // Still working on current
return;
}
if(servtime < ttime) {
ttime -= servtime;
if(!customers.empty()) {
current = customers.front();
customers.pop(); // Remove it
busy = true;
run(true); // Recurse
}
return;
}
if(servtime == ttime) {
// Done with current, set to empty:
current = Customer(0);
busy = false;
return; // No more time in this slice
}
}
};
// Inherit to access protected implementation:
class CustomerQ : public queue<Customer> {
public:
friend ostream&
operator<<(ostream& os, const CustomerQ& cd) {
copy(cd.c.begin(), cd.c.end(),
ostream_iterator<Customer>(os, " "));
return os;
}
};
int main() {
CustomerQ customers;
list<Teller> tellers;
typedef list<Teller>::iterator TellIt;
tellers.push_back(Teller(customers));
srand(time(0)); // Seed the random number generator
clock_t ticks = clock();
// Run simulation for at least 5 seconds:
while(clock() < ticks + 5 * CLOCKS_PER_SEC) {
// Add a random number of customers to the
// queue, with random service times:
for(int i = 0; i < rand() % 5; i++)
customers.push(Customer(rand() % 15 + 1));
cout << '{' << tellers.size() << '}'
<< customers << endl;
// Have the tellers service the queue:
for(TellIt i = tellers.begin();i != tellers.end(); i++)
(*i).run();
cout << '{' << tellers.size() << '}'
<< customers << endl;
// If line is too long, add another teller:
if(customers.size() / tellers.size() > 2)
tellers.push_back(Teller(customers));
// If line is short enough, remove a teller:
if(tellers.size() > 1 && customers.size() / tellers.size() < 2)
for(TellIt i = tellers.begin();i != tellers.end(); i++)
if(!(*i).isBusy()) {
tellers.erase(i);
break; // Out of for loop
}//if
}//while
} ///:~