本章重点介绍,各种容器的定义和使用方法。
容器是,用来存储和组织其他对象的对象。容器适配器,严格地说并不是容器,
而是,使用容器的对象,是在容器的基础上发展起来的。
作为容器的成员,必须满足的三个条件:
1 元素必须是可复制的。所有容器均会产生1份元素副本,不会发生alias现象;
所有容器操作为传回的均是其元素的副本。这导致复制构造函数的执行非常频繁。
2 元素必须是可指派(assign)的。
3 元素必须是可释放的(经过析构函数释放内存)。使用者从容器中将元素删除时,容器必须释放其元素
所占的内存。按这种需求,析构函数不能设置为private类型。
作为容器的成员函数(操作),其中3个最重要的能力:
1 容器均能提供value,而非refrence(引用)
2 所有的元素自动形成顺序。
3 函数使用者必须确保传递的参数符合要求。
容器的种类和数据类型
STL容器通常分为3类:
1 序列式容器(sequence 容器):vector动态数组 deque双向队列,list双向串行
2 关联性容器:set,multiset,map,multimap,hash(哈希)table
3 容器配接器:stack,queue,priority_queue
STL容器的数据结构,3种:
1 string类
2 bitset
3 valarray
序列式容器概述:
vector类模板
template <class T,class Allocator=allocator<T>> class vector;
vector 就像一个动态数组,是典型的“将元素置于动态数组中加以管理”的抽象概念。
vector高级编程
1 vector相关的元素访问方法
vector<typename T>c;
c.at(index);
c(index);
c.front();
c.back();
2 迭代器相关函数
begin(),end(),
rbegin(),rend() 逆向迭代
3 元素查找和搜索
find(),find_if()两个算法均可以使用迭代器、,两个迭代器参数决定了搜索和查找的范围
函数返回值均为迭代器类型。
find()函数的原型:
template<class InputIterator,class T>
inline InputIterator find(InputIterator first,InputIterator last,const T& value)
template<class InputIterator,class T,class Predicate>
inline InputIterator find_if(InputIterator first,InputIterator last,Predicate prediccate)
4 vector型容器中的字符串处理
使用vector管理字符串,可以处理字符串中的每个字符,并且vector可以自动管理内存。
5 元素排序
sort()
插入元素
push_back() insert()
删除元素
pop_back() //删除最后一个元素
erase() //删除由迭代器指定的元素,可以删除区间范围的元素
clear() //实现删除向量vector的所有元素
remove() //
对象交换
swap()
template<class T,class A>
void swap(const vector<T,A>&v1,const vector<T,A>&v2);
vector<bool>类(*****************************)
针对元素类别为bool的vector设计了特殊版本,目的是获取优化的vector。
list类模板
list由双向链表实现,list优势在于,在任何位置执行插入和删除动作都非常迅速
template<class T,class Allocator=allocator<T>> class list;
1 list不支持随机存取
2 在list的任何位置执行元素的插入和移除都非常快,可以迅速实现。
3 list不支持随机存取,不提供下标操作符和at()函数
4 list没有提供容量,空间重新分配等操作函数,每个元素都有自己的内存
5 list提供特殊成员函数,专门用于移动元素,和同名算法相比,速度更快
list 的定义和容量
头文件中,4种构造函数
explicit list(const _A& _A1 = _A()):allocator(_A1),_Head(_Buynode()),_Size(0){}
explicit list(size_type _N,const _Ty& _V=_Ty(),const _A& _A1 = _A()):allocator(_A1),_Head(_Buynode()),_Size(0)
{
insert(begin(),_N,_V);
}
list(const _Myt& _X):allocator(_X.alloctor),Head(_Buynode()),_Size(0)
{
insert(begin(),_X.begin(),_X,end());
}
list(const _Ty* _F,const _Ty* _L,const _A& _A1 = A()):allocator(_A1),_Head(_Buynode()),_Size(0)
{
insert(begin(),_F,_L);
}
list(A) listname;
list(A) listname(size);
list(A) listname(size,value);
list(A) listname(elselist);
list(A) listname(first,last);
list<int> mylist;
list提供两个成员函数,push_front(),push_back()
list型容器,具有一些特殊函数
merge()
void merge(list& x);
void merge(list& x,greater<T> pr);
remove()
void remove(const Type& _Val);
remove_if()
template <class Pred> void remove_if(Pred pr);
typedef binder2nd<not_equal_to<_Ty>> Pred;
sort()
void sort()
void sort(greater<T> pr)
splice()
//merge()函数并不是非常灵活,有一定局限性
void splice(iterator it,list& x);
void splice(iterator it,list& x,iterator first);
void splice(iterator it,list& x,iterator first,iterator last);
unique()
void unique();
template <class BinaryPredicate>
void unique(BinaryPredicate _Pred);
reverse()
void reverse();
deque(双端队列)类模板
double-ended queue
容器deque是典型的双端队列,完成了标准C++数据结构中队列的所有功能。
depue和vector相比,具有诸多优点之处
(1)deque可以在两端迅速插入和删除元素,而vector只提供了成员函数push_back和pop_back()
(2) 存取元素时,容器deque会稍慢一些
(3) deque的迭代器指针是之智能指针
(4) 在内存区块受限制的系统中,deque型容器可以包含更多元素,因为deque型容器使用多块内存;
(5) deque不支持对容器和内存重新分配时机的控制
(6) deque的内存区块不使用时,会被释放
(7) 在序列中间插入和删除元素时,deque的速度很慢,需要移动相关的所有元素;
(8) 容器deque的迭代器属于随机存取迭代器
<deque> 4种构造函数
explicit deque(const A& a1 = A());
explicit deque(size_type n,const T& v = T(),const A& a1 = A());
deque(const deque& x);
deque(const_iterator first,const_iterator last,const A& a1 = A());
deque<typename T>name;
deque<typename T>name(size);
deque<typename T>name(size,value);
deque<typename T>name(elsedeque); //用复制构造函数
deque<typename T>name(elsedeque.first(),elsedeque.end());
//使用迭代器创建deque容器对象
deque容器基础成员函数
赋值
push_front() //用于在容器的头部插入新元素
push_back() //用于在容器的尾部插入新元素
pop_front() //用于获取容器的头元素
pop_back() //用于获取容器的尾元素
deque容器还提供运算符[]
const_reference operator[](size_type pos) const;
reference operator[](size_type pos);
迭代器相关函数
(1) begin rbegin end rend; //返回值为迭代器,或者逆迭代器
(2) back front //返回值为引用
(3) bool empty() const
(4) const_reference at(size_type pos) const;
refrence at(size_type pos);
(5) assign()
void assign(const_iterator first,const_iterator last);
void assign(size_type n,const T& x = T());
deque的高级编程
元素交换
template <class T,class Allocator>
void swap(deque<T,Allocator>& x,deque<T,Allocator>&y);
插入和删除
iterator insert(iterator it,const T& x = T());
void insert(iterator it,size_type n,const T& x);
void insert(iterator it,const_iterator first,const_iterator last);
erase()
clear() == erase(begin,end)
查找
find()
相关联容器概述
相关联容器包括:set,multiset,map,multimap,其中set可以视为一种特殊的map
其元素的值即为键值。
相关联容器其实是,相关联数组概念的推广
相关联容器根据特定的排序准则,自动为其元素排序。相关联容器中的元素都已经是排序,是已经排序的。
所有关联式容器都有一个可供选择的template参数,指明排序原则。
排序准则以函数形式呈现,用于比较元素或元素键。模板情况下以“operator<”进行比较
程序员可以提供自己定义的比较函数
通常,关联式容器由二叉树实作出来。
关联容器优点:提供对元素的快速访问,却不能实现任意位置的操作。
set/multiset类模板
集合set定义
template<class Key,class Traits = less<key>,class Allocator = allocator<Key>> class set
Key是存储在集合元素中的数据类型,Traits是实现集合内部排序的仿函数,默认less<Key>
Allocator代表集合的内存配置器,负责内存的分配和销毁
set的构造函数
排序准则
STL先建立一个抽象概念阶层体系,形成一个软件组件分类学,最后再以实际工具(template)将各个概念实现。
理论架构《Generic Programming and the STL》《泛型程序设计与STL》
std::set<int,std::greater<int>> s1;
set<int> s2(less<int>());
#include<iostream>
#include<set>
using namespace std;
void OutPut(set<int> &s)
{
set<int>::iterator it;
for(it=s.begin();it!=s.end();it++)
cout<<" "<<*it<<", ";
cout<<endl;
}
void OutPutM(multiset<int>& s)
{
multiset<int>::iterator it;
for(it=s.begin();it!=s.end();it++)
cout<<" "<<*it<<", ";
cout<<endl;
}
int main()
{
set<int> s1;
s1.insert(10);s1.insert(15);s1.insert(25);s1.insert(20);s1.insert(30);
OutPut(s1);
// set<int> s2(less<int>());
// s2.insert(10);s2.insert(15);s2.insert(25);s2.insert(20);s2.insert(30);
// OutPut(s2);
set<int>::allocator_type s1_Alloc;
s1_Alloc=s1.get_allocator();
set<int>s3(less<int>(),s1_Alloc);
s3.insert(1);s3.insert(5);s3.insert(2);s3.insert(2);
OutPut(s3);
set<int>s4(s1);
OutPut(s4);
multiset<int> sml;
sml.insert(10);sml.insert(15);sml.insert(25);sml.insert(20);sml.insert(30);sml.insert(20);
OutPutM(sml);
return 0;
}
输出:
10, 15, 20, 25, 30,
1, 2, 5,
10, 15, 20, 25, 30,
10, 15, 20, 20, 25, 30,
set(multiset)
提供了查找函数find(),还提供了
low_bound(),
upper_bound(),
equal_range()
Visual C++6.0中提供另外两个函数
key_comp() 用于键值比较
value_comp() 用于实值比较
key_compare key_comp() const;
// key_compare决定了集合中元素的排列顺序
value_compare value_comp() const;
关联式容器-----map/multimap类模板
map类型通常理解为关联数组(associative array)。只是multimap允许重复元素,而map不允许。
容器类型map和multimap示意图
在STL中,两种类型的模板如下:
template<class Key,class T,class Compare=less<Key>,class Allocator=allocator<pair<const Key,T >>>class map;
template<class Key,class T,class Compare=less<Key>,class Allocator=allocator<pair<const Key,T>>> class multimap;
//数据对(pair)
map和multimap成员函数
bool empty() const;
begin() end() rbegin() rend()
map和multimap的高级编程
insert()
erase()
clear()
void swap(map& str);
size_type count(const Key& key) const;
iterator find(const Key& key);
const_iterator find(const Key& key)const;
元素大小比较
(1)键值比较
key_compare key_comp() const;
(2)实值比较
value_compare value_comp() const;
(3)获取内存分配器
Allocator get_allocator() const;
特殊容器用法
位段类模板
堆栈类模板
队列类模板
优先队列模板
bitset类模板
创造一个内含位或布尔值且大小固定的数组(array)。
bitset(); //位段的构造函数
bitset(unsigned long val); //位段的构造函数
explicit bitset(const string& str,size_t pos=0,size_t n=-1);
//位段的构造函数
bitset的成员函数
size()
count()
any()
none()
test(size_t idx)
set()
set(size_t idx,in value)
reset()
reset(size_t idx)
flip() //反转所有位的值
flip(size_t idx) //反转“idx”位置上的位
to_ulong()
==
!=
^=
|=
&=
<<=
>>=
[size_t idx]
=
~
~()
<<()
>>()
&()
|()
^()
to_string()
stack类模板
namespace std{
template<class T, class Container=deque<T>>
class stack;
}
std::stack<int,std::vector<int>> sv;
队列queue类模板
namespace std{
template<class T, class Container=deque<T>>
class queue;
}
std::queue<std::string> buffer;
std::queue<std::string,std::list<std::string>>buffer;
Priority Queues类模板
#include<queue>
namespace std{
template<class T,class Container=vector<T>,class Compare=less<typename Container::value_type>>
class priority_queue;
}
std::priority_queue<float> buffer;
在容器priority_queue中需要使用STL中的堆(heap)算法
类模板的核心成员函数
#include<iostream>
#include<queue>
#include<vector>
#include<list>
#include<queue>
using namespace std;
void print(double& Ele)
{
cout<<Ele<<", ";
}
template<class T>
void Out(priority_queue<T,deque<T>,less<T>>& p)
{
while(!p.empty())
{
cout<<p.top()<<", ";
p.pop(); //弹出队列
}
}
template<class T>
void OutG(priority_queue<T,deque<T>, greater<T>>& pg)
{
while(!pg.empty())
{
cout<<pg.top()<<", ";
pg.pop();
}
cout<<endl;
}
int main()
{
priority_queue<double,deque<double>,less<double>>p1,p2;
p1.push(11.5);
p1.push(22.5);
p1.push(32.5);
p1.push(21.1);
p1.push(15.6);
p1.push(8.9);
p1.push(55.0);
p2 = p1;
Out(p1);
p1 = p2;
priority_queue<double,deque<double>,greater<double>> p3;
while(p2.size())
{
p3.push(p2.top());
p2.pop();
}
OutG(p3);
return 0;
}
输出:
55, 32.5, 22.5, 21.1, 15.6, 11.5, 8.9,
8.9, 11.5, 15.6, 21.1, 22.5, 32.5, 55,
如何实现优先队列priority_queue,其相对队列queue的不同之处在于:优先队列实现内部自动排序,
可根据实际情况自定义排序准则,也可以自己编写函数,或仿函数用于内部优先级的确定。