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
Thinking in C++第二卷笔记之STL容器部分(二)
http://blog.163.com/zhoumhan_0351/blog/static/399542272010457193722/
priority_queue优先队列容器
http://blog.163.com/zhoumhan_0351/blog/static/3995422720103510163429
1、优先队列
可以说堆就是一个优先队列,priority_queue只是对它的一个封装。
2、vector<bool>和bitset
来操作硬件。bitset模板为了操作二进制位设计,不是一个正常的STL容器,没有迭代器,拥有一个面向二进制位层次的操作接口。而vector<bool>是vector的一个特化,有普通vector的所有操作。
bitset接受一个无符号整形模型参数。bitset<10>,bitset<20>是两种不同的类型,不能相比较,赋值等操作。each bitset is implemented by logically packing bits
in an array of integral types (typically unsigned longs, which contain at least 32 bits).
In addition, the only conversion from a bitset to a numerical value is to an unsigned
long (via the function to_ulong( )).
Although there are no other numerical conversions from bitset besides
to_ulong( ), there is a stream inserterthat produces a string containing ones and
zeros, and this can be as long as the actual bitset.
You’ll notice that bitset only has three nonmember operators: and (&), or (|),
and exclusive-or (^). Each of these creates a new bitset as its return value. All the
member operators opt for the more efficient &=, |=, and so on, where a temporary is
not created. However, these forms change the bitset’s value。所以我们通常要写成BS(a)的形式,如cout << (BS(a) <<= SZ/2)。
The vector<bool> container is a specialization of the vector template. A normal
bool variable requires at least one byte, but since a bool only has two states, the
ideal implementation of vector<bool> is such that each bool value only requires one
bit. Since typical library implementations pack the bits into integral arrays, the iterator
must be specially defined and cannot be a pointer to bool.The bit-manipulation
functions for vector<bool> are much more limited than those of bitset. The only
member function that was added to those already in vector is flip( ), to invert all the
bits. There is no set( ) or reset( ) as in bitset. When you use operator[], you get back
an object of type vector<bool>::reference, which also has a flip( ) to invert that
individual bit.
#include <bitset>
#include <iostream>
#include <iterator>
#include <sstream>
#include <vector>
using namespace std;
int main() {
vector<bool> vb(10, true);
vector<bool>::iterator it;
for(it = vb.begin(); it != vb.end(); it++)
cout << *it;
cout << endl;
vb.push_back(false);
ostream_iterator<bool> out(cout, "");
copy(vb.begin(), vb.end(), out);
cout << endl;
vb.flip(); // Flip all bits
copy(vb.begin(), vb.end(), out);
ostringstream os;
copy(vb.begin(),vb.end(),ostream_iterator<bool>(os, ""));
bitset<10> bs(os.str());
cout << "Bitset:"<< endl << bs << endl;
}
// Let c be an STL container other than vector<bool>:
常规容器都有的操作,如下:
T& r = c.front();
T* p = &*c.begin();
但是由于二进制位是不可寻址的,所以上面的两个函数不可能用于处理持有二进制位的容器。Both vector<bool> and bitset use a proxy class (the nested
reference class to read and set bits as necessary.
3、对于一个map,在数组范围以外的位置进行索引意味着创建新条目。
pair由值封装它的对象,这意味着对象装入pair之内,拷贝构造是必须的。对于每个pair中的对象包括至少一个拷贝函数调用和一个析构函数调用。使用迭代器不会产生额外的对象的析构和构造操作。
如下是一个单词计数器
// Count occurrences of words using a map.
#include <iostream>
#include <fstream>
#include <map>
#include <string>
using namespace std;
int main() {
typedef map<string, int> WordMap;
typedef WordMap::iterator WMIter;
//const char* fname = "C:\\bsmain_runtime.txt";
ifstream in("C:\\bsmain_runtime.log");
if(NULL==in) {
cout<<"Failed";
return 1;
}
WordMap wordmap;
string word;
while(in >> word)
wordmap[word]++;
for(WMIter w = wordmap.begin(); w != wordmap.end(); w++)
cout << w->first << ": " << w->second << endl;
} ///:~
下面是另外一个有趣的例子:
string reply;
cin>>reply;
if(reply.at(0)=='q') return 0;
istringstream r(reply);
int i;
r>>i;
我们用multiset来做上面的那个例子,更优雅的实现。
#include <fstream>
#include <iostream>
#include <iterator>
#include <set>
#include <string>
using namespace std;
int main() {
const char* fname = "C:\\bsmain_runtime.log";
ifstream in(fname);
multiset<string> wordmset;
string word;
while(in >> word)
wordmset.insert(word);
typedef multiset<string>::iterator MSit;
MSit it = wordmset.begin();
while(it != wordmset.end()) {
pair<MSit, MSit> p = wordmset.equal_range(*it);
int count = distance(p.first, p.second);//对该范围内的元素进行计数
cout << *it << ": " << count << endl;
it = p.second; // Move to the next word
}
} ///:~
template<class Init, class Dist>
ptrdiff_t distance(InIt first, InIt last);
The template function sets a count n to zero. It then effectively advances
first and increments n until first == last. If InIt is a random-access iterator
type, the function evaluates the expression n += last - first. Otherwise, it
performs each iterator increment by evaluating ++first.
multiset要求所有重复的元素必须相互比邻的存放。一个set实现可能使用散列函数进行排列元素。
在编译器实例化时,所需要的ostream_iterator特化根据参数关联查找(ADL)规则,只查找std。
在删除一个指针后将其值置为零,对一个零指针调用删除操作delete是一个安全的操作。
4、对STL的扩充
利用散列算法实现的set和map比树型数据结构有更高的效率。在SGI中有提供,如hash_multiset,hash_map,hash_multimap,slist,和rope(它是一个string的变种,对非常大型的字符串,字符串的快速连接和取子串等操作进行了优化)