5.2 STL初步

这是微软帮助文档中对集合(set)的解释: “描述了一个控制变长元素序列的对象的模板类,每一个元素包含了一个排序键(sort key)和一个值(value)。对这个序列可以进行查找、插入、删除序列中的任意一个元素,而完成这些操作的时间同这个序列中元素个数的对数成比例关 系,并且当游标指向一个已删除的元素时,删除操作无效。”

STL的大三主体:算法、容器、迭代器。C++ STL 之所以得到广泛的赞誉,也被很多人使用,不只是提供了像vector, string, list等方便的容器,更重要的是STL封装了许多复杂的数据结构算法和大量常用数据结构操作。vector封装数组,list封装了链表,map和set封装了二叉树等,在封装这些数据结构的时候,STL按照程序员的使用习惯,以成员函数方式提供的常用操作,如:插入、排序、删除、查找等。让用户在STL使用过程中,并不会感到陌生。

容器(Container)的概念的出现早于模板(template),它原本是一个计算机科学领域中的一个重要概念,但在这里,它的概念和STL混合在一起了。下面是在STL中出现的7种容器:

vector(向量)——STL中标准而安全的数组。只能在vector 的“前面”增加数据。

deque(双端队列double-ended queue)——在功能上和vector相似,但是可以在前后两端向其中添加数据。 

list(列表)——游标一次只可以移动一步。如果你对链表已经很熟悉,那么STL中的list则是一个双向链表(每个节点有指向前驱和指向后继的两个指针)。

set(集合)——包含了经过排序了的数据,这些数据的值(value)必须是唯一的。

map(映射)——经过排序了的二元组的集合,map中的每个元素都是由两个值组成,其中的key(键值,一个map中的键值必须是唯一的)是在排序 或搜索时使用,它的值可以在容器中重新获取;而另一个值是该元素关联的数值。比如,除了可以ar[43] = "overripe"这样找到一个数据,map还可以通过ar["banana"] = "overripe"这样的方法找到一个数据。如果你想获得其中的元素信息,通过输入元素的全名就可以轻松实现。

multiset(多重集)——和集合(set)相似,然而其中的值不要求必须是唯一的(即可以有重复)。

multimap(多重映射)——和映射(map)相似,然而其中的键值不要求必须是唯一的(即可以有重复)。
注意:如果你阅读微软的帮助文档,你会遇到对每种容器的效率的陈述。比如:log(n*n)的插入时间。除非你要处理大量的数据,否则这些时间的影响是可 以忽略的。如果你发现你的程序有明显的滞后感或者需要处理时间攸关(time critical)的事情,你可以去了解更多有关各种容器运行效率的话题。


1.迭代器:

参考:http://blog.csdn.net/sandy_zc_1/article/details/5352932

Iterator(迭代器)模式又称Cursor(游标)模式,用于提供一种方法顺序访问一个聚合对象中各个元素, 而又不需暴露该对象的内部表示。或者这样说可能更容易理解:Iterator模式是运用于聚合对象的一种模式,通过运用该模式,使得我们可以在不知道对象内部表示的情况下,按照一定顺序(由iterator提供的方法)访问聚合对象中的各个元素。迭代器提供对一个容器中的对象的访问方法,并且定义了容器中对象的范围。迭代器就如同一个指针。事实上,C++的指针也是一种迭代器。但是,迭代器不仅仅是指针,因此你不能认为他们一定具有地址值。例如,一个数组索引,也可以认为是一种迭代器。

迭代器的类型

对于STL数据结构和算法,你可以使用五种迭代器。下面简要说明了这五种类型:

·        Input iterators 提供对数据的只读访问。只能单步向前迭代元素,不允许修改由该类迭代器引用的元素。

·        Output iterators 提供对数据的只写访问。只能单步向前迭代元素,不同的是该类迭代器对元素只有写的权力。

·        Forward iterators 提供读写操作,并单步向前迭代元素。(set/map)

·        Bidirectional iterators提供读写操作,并能向前和向后操作。(list)

·        Random access iterators提供读写操作,并能在数据中随机移动。该类迭代器能完成上面所有迭代器的工作,它自己独有的特性就是可以像指针那样进行算术计算,而不是仅仅只有单步向前或向后迭代。(vector\deque)

reverse iterator:取决于你这个容器本身的迭代器是什么类型。但是至少是bidirectional的(不然我怎么逆向啊?)
  insert iterator
:属于output iterator
  istream iterator
:属于input iterator
  ostream iterator
:属于output iterator

forward iterator没有完全继承output iterator的所有功能,只是继承了大部分功能而已。

尽管各种不同的STL实现细节方面有所不同,还是可以将上面的迭代器想象为一种类继承关系。从这个意义上说,下面的迭代器继承自上面的迭代器。由于这种继承关系,你可以将一个Forward迭代器作为一个output或input迭代器使用。同样,如果一个算法要求是一个bidirectional 迭代器,那么只能使用该种类型和随机访问迭代器。

vector迭代器的自增和解引用运算
  迭代器类型定义了一些操作来获取迭代器所指向的元素,并允许程序员将迭代器从一个元素移动到另一个元素。
  迭代器类型可使用解引用操作符(*操作符)来访问迭代器所指向r 元素:
  *iter = 0;
  解引用操作符返回迭代器当前所指向的元素。假设iter指向vector对象ivec的第一个元素,那么*iter和ivec[0]就是指向同一个元素。上面这个语句的效果就是把这个元素的值赋为0。
  迭代器使用自增操作符(1.4.1节)向前移动迭代器指向容器中下一个元素。从逻辑上说,迭代器的自增操作和int型对象的自增操作类似。对 int对象来说,操作结果就是把int型值“加1”,而对迭代器对象则是把容器中的迭代器“向前移动一个位置”。因此,如果iter指向第一个元素, 则++iter指向第二个元素。
  如果迭代器到达了容器中的最后一个元素的后面,则迭代器变成past-the-end值。使用一个past-the-end值得指针来访问对象是非法的,就好像使用NULL或为初始化的指针一样。
***每个容器必须带有一些东西,以配合迭代器这个概念来使用
iterator                                                    正向迭代器
const_iterator                                              正向只读迭代器(只能用于读取容器内的元素,不能改变其值
reverse_iterator                                            逆向迭代器(这种特殊的迭代器提供一种逆向的访问——它是倒着走的。它的++操作符是往前回退,而--操							    作符是往后移动,与正常的迭代器刚好相反)
const_reverse_iterator                                      逆向只读迭代器只能用于读取容器内的元素,不能改变其值
difference_type                                             同一容器上两个迭代器相减结果类型
pointer                                                     容器中元素类型的指针
reference                                                   容器中元素类型的引用
const_reference                                             容器中元素类型的常量引用
size_type                                                   容器中用来统计元素个数的类型 
value_type                                                  容器中保存元素的类型,如vector<int>::value_type 等价于int

声明:set<string>::iterator it = dict.begin();

迭代器失效的情况:

任何容器的erase操作

erase的位置的迭代器失效;

vectorpush_back操作

可能没事,但是一旦引发内存重分配,所有迭代器都会失效;

vectorinsert操作

插入点之后的所有迭代器失效;但一旦引发内存重分配,所有迭代器都会失效;

vectorerase操作

插入点之后的所有迭代器失效;

vectorreserve操作

所有迭代器失效(因为它导致内存重分配);

dequeinsert操作

所有迭代器失效;

dequeerase操作

所有迭代器失效;


2.优先队列:

①定义:是不同于先进先出队列的另一种队列。每次从队列中取出的是具有最高优先权的元素

②使用方法:

priority_queue<int> q;  大的数优先级高

priority_queue<int, vector<int>, cmp> q2;  自定义优先级,以下是重载函数

struct cmp
{
    bool operator()(int &x,int &y)
        {
            return x > y;
        }
};

③操作命令:

empty():如果队列为空返回真
pop():删除对顶元素
push():加入一个元素
size():返回优先队列中拥有的元素个数
top():返回优先队列对顶元素(无front函数)

注意:越小的整数优先级越大:priority_queue<int,vector<int>,great<int> > pq (最后两个<不能连在一起,否则会被编译器认为是cin)

④例题(UVA-10954 优先队列+贪心)

#include <iostream>
#include <cstdio>
#include<queue>
using namespace std;
struct cmp
{
    bool operator()(int &x,int &y)
        {
            return x > y;
        }
};
int num[5005];
int main()
{
    int n;
    while(cin>>n && n)
    {
        for(int i = 0;i < n;i++)
            cin>>num[i];
        int sum = 0;
        priority_queue<int,vector<int>,cmp> shu;
        for(int i = 0;i < n;i++)
            shu.push(num[i]);
        while(1)
        {
            int temp = shu.top();
            shu.pop();
            int tsum = temp + shu.top();
            shu.pop();
            sum += tsum;
            if(shu.empty()) break;
            shu.push(tsum);
        }
        printf("%d\n",sum);
    }
	return 0;
}

3.map容器:

map是STL的一个关联容器,它提供一对一(其中第一个可以称为关键字,每个关键字只能在map中出现一次,第二个可能称为该关键字的值)的数据处理能力,由于这个特性,它完成有可能在我们处理一对一数据的时候,在编程上提供快速通道。map内部自建一颗红黑树(一种非严格意义上的平衡二叉树),这颗树具有对数据自动排序的功能,所以在map内部所有的数据都是有序的。

构造函数:
   map();                         // 默认构造函数
   map(const map& m)    // 拷贝构造函数
   map(iterator begin, iterator end );  //区间构造函数
   map(iterator begin, iterator end, const traits& _compare) //带比较谓词的构造函数
   map(iterator begin, iterator end, const traits& _compare, const allocator& all) //带分配器

插入函数:
enumMap.insert(pair<int, Cstring>(1, “One”));//用insert方法插入pair对象
enumMap.insert(map<int, Cstring>::value_type (1, “One”));//用insert方法插入value_type对象
enumMap[1] = "One";enumMap[2] = "Two";//用数组方式插入值
PS:第三种非常直观,但存在一个性能的问题。插入2时,先在enumMap中查找主键为2的项,没发现,然后将一个新的对象插入enumMap,键是2,值是一个 空字符串,插入完成后,将字符串赋为"Two"; 该方法会将每个值都赋为 缺省值,然后再赋为显示的值,如果元素是类对象,则开销比较大。用前两种方法可以避免开销。用insert函数插入数据,在数据的插入上涉及到集合的唯一性这个概念,即当map中有这个关键字时,insert操作是插入数据不了的,但是用数组方式就不同了,它可以覆盖以前该关键字对应的值。

遍历函数
下标操作符给出了获得一个值的最简单方法:CString tmp = enumMap[2];只有当map中有这个键的实例时才对,否则会自动插入一个实例,值为初始化值。可以使用find()和count()方法来发现一个键是否存在:查找map中是否包含某个关键字条目用find()方法,传入的参数是要查找的key,在这里需要提到的是begin()和end()两个成员,分别代表map对象中第一个条目和最后一个条目,这两个数据的类型是iterator.
通过map对象的方法获取的iterator数据类型是一个std::pair对象,包括两个数据。
iterator->first 关键字(key)
iterator->second 存储的数据(value)
④Map中的元素是自动按key升序排序,所以不能对map用sort函数。
iterator begin() 返回指向map头部的迭代器
iterator end() 返回指向map末尾的迭代器
reverse_iterator  rbegin() 返回一个指向map尾部的逆向迭代器
reverse_iterator  rend() 返回一个指向map头部的逆向迭代器

查找函数:
size_type count(const key_type& k); // 返回指定元素出现的次数,只有0或1
iterator find(const key_type& k) ;//查找一个元素,返回指定元素出现的位置,如果没有返回end()
iterator lower_bound(const key_type& k);// 返回键值>=给定元素的第一个位置,这个函数用来返回要查找关键字的下界(是一个迭代器)
iterator upper_bound(const key_type& k);//返回键值>给定元素的第一个位置,这个函数用来返回要查找关键字的上界(是一个迭代器)

删除函数:
iterator erase(iterator it); //通过一个条目对象删除
iterator erase(iterator first, iterator last); //删除一个范围
size_type erase(const Key& key); //通过关键字删除
void clear() 删除所有元素

基本操作函数:
bool empty() 如果map为空则返回true
pair<iterator, iterator> equal_range(const key_type& k);//返回特殊条目的迭代器对
get_allocator() 返回map的配置器
size_type max_size() 返回可以容纳的最大元素个数
size_type size() 返回map中元素的个数
swap() 交换两个map
value_compare  value_comp() 返回比较元素value的函数
key_compare key_comp() 返回比较元素key的函数


4.set容器:

set中的key和value是Key类型的,而map中的key和value是一个pair结构中的两个分量。set集合容器实现了红黑树(Red-Black Tree)的平衡二叉检索树的的数据结构,在插入元素时,它会自动调整二叉树的排列,把该元素放到适当的位置,以确保每个子树根节点的键值大于左子树所有节点的键值,而小于右子树所有节点的键值;另外,还得确保根节点的左子树的高度与右子数的高度相等,这样,二叉树的高度最小,从而检索速度最快。要注意的是,它不会重复插入相同键值的元素,而采取忽略处理。

 平衡二叉检索树的检索使用中序遍历算法,检索效率高于vector、deque、和list的容器。另外,采用中序遍历算法可将键值由小到大遍历出来,所以,可以理解为平衡二叉检索树在插入元素时,就会自动将元素按键值从小到大的顺序排列。构造set集合的主要目的是为了快速检索。
构造函数:
set(); //构造一个空的set容器。
set(const Compare& comp);//构造一个空的set容器。使用comp作为关键字比较函数。
set(const set<Key, Compare, Alloc> & x);//使用x初始化一个set容器。
template <class InputIterator> set(InputIterator first, InputIterator last);//使用迭代器[first, last)指代的元素构造set容器。
template <class InputIterator> set(InputIterator first, InputIterator last, const Compare & comp);使用迭代器[first, last)指代的元素构造set容器。并使用comp作为关键字比较函数。

运算符:
v1 == v2
v1 != v2
v1 <= v2
v1 >= v2
v1 < v2
v1 > v2 
v[]
两个set被认为是相等的,如果: 它们具有相同的容量,所有相同位置的元素相等.set之间大小的比较是按照词典规则. 

遍历函数:
iterator   begin() //返回第一个元素的迭代器
iterator   end() //返回最后一个元素的下一位置的指针(set为空时,end()=begin())
reverse_iterator rbegin(); //返回一个指向反向set容器的第一个元素的反向双向定位器,指向set的最后一个元素
#include  <set>
#include  <iostream>
#define  len 5
using  namespace  std;
int print(set   <int>  c)
//用于打印一个    set
{
	set <int>::const_iterator    cp;
	for(cp=c.begin ();cp!=c.end ();cp++)
	//让 cp 从 c 的开始到结束打印   cp  对应的值
	cout<<*cp<<"   ";
	return  0;
}
int main()
{
	set <int>  ctr;
	set <int>::iterator    cp;
	set <int>::reverse_iterator     rcp;
	int i;
	for(i=0;i<len;i++ )ctr.insert(i);
	//下面先给  ctr  赋值
	cout<<"ctr  is:";
	print(ctr);
	//调用子程序,把   ctr  打印出来
	cout<<endl;
	cout<<"Its  reverse  is:";
	for(rcp=ctr.rbegin ();rcp!=ctr.rend ();rcp++)
	//打印出反向   set  容器
		cout<<*rcp<<"   ";
	cout<<endl;
	return  0;
}
reverse_iterator  rend()  //反向迭代器,指向set第一个元素前一个位置
const_iterator cbegin();//返回正向只读迭代器,指向set第一个元素
const_iterator cend();//返回正向只读迭代器,指向set最后一个元素后面
const_reverse_iterator crend();//返回反向只读迭代器,指向第一个元素后面
iterator find(const Key& _Key);  //查找元素_Key,并返回该元素的(常量)迭代器;找不到返回.end()
iterator lower_bound(const Key& _Key) const;  //返回第一个大于等于_Key的定位器,或者返回指向set容器的结束的定位器
iterator upper_bound(key_value) const;// 返回最后一个大于等于key_value的定位器
pair <iterator,iterator> equal_range(const key_type & x)  const;//返回容器中关键字等于x(满足==x关系)的元素区间。返回值[pair.first, pair.second]均满足该关系。这个返回值是一个pair类型,如果这一对定位器中哪个返回失败,就会等于end()的值。
#include <set> 
#include <iostream>
using namespace std;  
int print(set <int> c)  //用于打印一个set 
{ 
set <int>::const_iterator cp; 
for(cp=c.begin();cp!=c.end();cp++)    //让cp从c的开始到结束打印cp对应的值            
cout<<*cp<<" ";  return 0;
 }  
int main() 
 { 
set <int> ctr;    
pair <set <int>::const_iterator, set <int>::const_iterator> p;    
int i; 
for(i=0;i<=3;i++)ctr.insert(i);  //给ctr赋值    
cout<<"The ctr is: ";    
print(ctr);     //调用子程序来打印ctr的内容     
cout<<endl; 
p=ctr.equal_range(2);    
if(p.first!=ctr.end())    {     cout<<"The first element which key >= 2 is: ";cout<<*p.first;    //调用子程序来打印一项     cout<<endl;    } 
if(p.second!=ctr.end())    {     cout<<"The first element which key > 2 is: ";     cout<<*p.second;      cout<<endl;    } 
return 0; 
} 
size_type count(const key_type & x) const; // 用来查找set中某个某个键值出现的次数。这个函数在set并不是很实用,因为一个键值在set只可能出现0或1次,这样就变成了判断某一键值是否在set出现过了。

属性函数:
bool   empty() const; //判断是否为空,若为空返回1,否则返回0
size_type size() const;//返回储存数据的个数
size_type max_size() const; //返回set的最大容量,一般值为size_type(-1)
key_compare key_comp() const; //取得一个比较对象的副本来对set容器中的元素进行排序,返回用于关键字比较的仿函数对象。
#include <set> 
#include <iostream> 
using namespace std; 
int main()  
{ 
set <int> ctr; 
set <int,less<int>>::key_compare kc = ctr.key_comp()
    if(kc(1, 2))    
cout<<"kc(1,2) is true"<<endl;        
else     
cout<<"kc(1,2) is false"<<endl;     
return 0; 
}

value_compare value_comp() const;//返回用于值比较的反函数对象。
#include <iostream>
#include <set>
int main ()
{
  std::set<int> myset;
  std::set<int>::value_compare mycomp = myset.value_comp();
  for (int i=0; i<=5; i++) myset.insert(i);
  std::cout << "myset contains:";
  int highest=*myset.rbegin();
  std::set<int>::iterator it=myset.begin();
  do {
    std::cout << ' ' << *it;
  } while ( mycomp(*(++it),highest) );
  std::cout << '\n';
  return 0;
}

删除函数:
iterator clear() //清空该集合
iterator erase(iterator _Where); //输入删除元素的迭代器,返回一个指向第一个没被删除的元素的双向定位器,如果不存在这样的元素,则返回set容器的末尾
iterator erase(iterator _First,iterator _Last); /输入删除元素区间的迭代器,返回一个指向第一个没被删除的元素的双向定位器,如果不存在这样的元素,则返回set容器的末尾
size_type erase(const key_type & _Key); //输入删除元素的关键字,返回被删除的元素的个数
  	set<int> myset;
  	set<int>::iterator it;
  	for (int i=1; i<10; i++) myset.insert(i*10);  // 10 20 30 40 50 60 70 80 90
  	it=myset.begin();
  	it++;                                         
 	 myset.erase (it);     //删除it位置的数据
 	 myset.erase (40);     //删除40这个数据

增加函数:
pair <iterator,bool> insert(const value_type& _Val);找合适的地方插入val,返回一对值,插入成功返回bool=true,插入元素已有时返回bool=false,iterator指向插入的位置或者已存在元素的位置
template<class InputIterator>  void insert(InputIterator _First,InputIterator _Last); 将迭代器first到second之间[first,second)的元素插入到set中,返回值是void。
iterator insert(iterator _Where,const value_type& _Val);_Where是第一个被插入到set的元素的位置,返回值指向插入的位置

其他函数:
swap() //交换两个set的所有元素
 
  int myints[]={12,75,10,32,20,25};
  set<int> c1 (myints,myints+3);     // 10,12,75
  set<int> c2 (myints+3,myints+6);      // 20,25,3
  c1.swap(c2);//交换c1与c2的元素 此时c1包括 20,25,32  c2包括10,12,75
Allocator get_allocator() const;返回一个构造该set容器的allocator的一个副本。
#include <set> 
#include <iostream> 
using namespace std;  
int main()
{ 
set <char> ctr;    
ctr.insert('a'); 
set <char> ctr2(less<char>(),ctr.get_allocato());    
cout<<"ctr2's size is: "<<ctr2.size<<endl;    
return 0; 
}
template <class... Args>  pair<iterator,bool> emplace (Args&&... args);
template <class... Args>  iterator emplace_hint (const_iterator position, Args&&... args);//在一定的位置插入元素,position参数只是用来提高插入的速度,并不一定就是说要在此处插入元素。示例
#include <iostream>
#include <set>
#include <string>
int main ()
{
  std::set<std::string> myset;
  auto it = myset.cbegin();

  myset.emplace_hint (it,"alpha");
  it = myset.emplace_hint (myset.cend(),"omega");
  it = myset.emplace_hint (it,"epsilon");
  it = myset.emplace_hint (it,"beta");

  std::cout << "myset contains:";
  for (const std::string& x: myset)
    std::cout << ' ' << x;
  std::cout << '\n';

  return 0;
}



5.vector容器:

vector是连续内存容器,换句话说,标准要求所有标准库实现的时候,vector中的元素的内存必须是连续的。所以对于插入和删除的时间复杂度是很高的,因为删除或者插入的时候,需要元素的移动,即元素复制拷贝。


构造函数:

vector();//无参数 - 构造一个空的vector
vector( size_type num);//数量(num) - 构造一个初始放入num个值的Vector,size为10
vector( size_type num, const TYPE &val );//数量(num)和值(val) - 构造一个初始放入num个值为val的元素的Vector
vector( const vector &from );//vector(from) - 构造一个与vector from 相同的vector 
vector( input_iterator start, input_iterator end );//迭代器(start)和迭代器(end) - 复制[start,end)区间内另一个数组的元素到vector中,可以是数组的指针

运算符:
v1 == v2
v1 != v2
v1 <= v2
v1 >= v2
v1 < v2
v1 > v2 
v[]
两个vectors被认为是相等的,如果: 它们具有相同的容量,所有相同位置的元素相等.vectors之间大小的比较是按照词典规则. 

增加函数:
void push_back( const TYPE &val );//添加值为val的元素到当前vector末尾
iterator insert( iterator loc, const TYPE &val );//在指定位置loc前插入值为val的元素,返回指向这个元素的迭代器, 
void insert( iterator loc, size_type num, const TYPE &val );//在指定位置loc前插入num个值为val的元素 
void insert( iterator loc, input_iterator start, input_iterator end );//在指定位置loc前插入相同类型变量区间[start, end)的所有元素 . 

删除函数:
void clear();//删除当前vector中的所有元素.
iterator erase( iterator loc );//删指定位置loc的元素。返回值是指向删除的最后一个元素的下一位置的迭代器.
iterator erase( iterator start, iterator end );//删除区间[start, end)的所有元素.返回值是指向删除的最后一个元素的下一位置的迭代器.
void pop_back();//删除当前vector最末的一个元素。

遍历函数:
TYPE at( size_type loc );//返回当前Vector指定位置loc的元素的引用. at() 函数 比 [] 运算符更加安全, 因为它不会让你去访问到Vector内越界的元素. 如果试图访问内存里非法值,at() 函数能够辨别出访问是否越界并在越界的时候抛出一个异常out_of_range.
TYPE back();//返回当前vector最末一个元素的引用
iterator begin();//返回一个指向当前vector起始元素的迭代器.
iterator end();//返回一个指向当前vector末尾元素的下一位置的迭代器.注意,如果你要访问末尾元素,需要先将此迭代器自减1. 
TYPE front();//返回当前vector起始元素的引用 
reverse_iterator rbegin();//返回指向当前vector末尾的逆迭代器.(译注:实际指向末尾的下一位置,而其内容为末尾元素的值,详见逆代器相关内容)
reverse_iterator rend();//回指向当前vector起始位置的逆迭代器. 
for_each( v1.begin(),  v1.end(),  print ); 
使用算法的时候,可以使用函数对象,例如
class OutPut
{
public:
       void operator ()( double  i )


       {
              std::cout <<  i;
}
}
for_each( v1.begin(), v1.end(), OutPut );

判断函数: 

bool empty();//如果当前vector没有容纳任何元素,则empty()函数返回true,否则返回false.

大小函数:
size_type size();//返回当前vector所容纳元素的数目(不是所能容纳元素数目)
size_type capacity();//返回当前vector在重新进行内存分配以前所能容纳的元素数量.
如果你想知道一个vector或string中有多少没有被占用的内存,你必须从capacity()中减去size()。如果size和capacity返回同样的值,容器中就没有剩余空间了,而下一次插入(通过insert或push_back等)会引发上面的重新分配步骤。
size_type max_size();//返回当前vector所能容纳元素数量的最大值(译注:包括可重新分配内存). 

其他函数:
void assign( input_iterator start, input_iterator end );//将迭代器[start, end)的元素赋到当前vector
void assign( size_type num, const TYPE &val );//赋num个值为val的元素到vector中.这个函数将会清除掉为vector赋值以前的内容
allocator_type get_allocator();//返回当前vector的内存分配器.在STL里面一般不会调用new或者alloc来分配内存,而且通过一个allocator对象的相关方法来分配.
void reserve( size_type size );//reserve()函数为当前vector预留至少共容纳size个元素的空间.(译注:实际空间可能大于size)
void resize( size_type size);//改变当前vector的大小为size。如果n小于当前大小,容器尾部的元素会被销毁。
void resize( size_type size, TYPE val );//改变当前vector的大小为size,且对新创建的元素赋值val
resize 与reserve的区别
reserve是容器预留空间,但并不真正创建元素对象,在创建对象之前,不能引用容器内的元素,因此当加入新的元素时,需要用push_back()/insert()函数。
resize是改变容器的大小,并且创建对象,因此当加入新的元素时,用operator[]操作符,或者用迭代器来引用元素对象。
扩大新元素时,如果超过当前的容量,则容量会自动扩充2倍,如果2倍容量仍不足,则继续扩大2倍。包括重新配置、元素移动、释放原始空间的过程。因此对vector容器而言,当增加新的元素时,有可能很快完成(直接存在预留空间中),有可能稍慢(扩容后再放新元素);对修改元素值而言是较快的;对删除元素来说,弱删除尾部元素较快,非尾部元素稍慢,因为牵涉到删除后的元素移动。而进行pop_back操作时,capacity并不会因为vector容器里的元素减少而有所下降,还会维持操作之前的大小。对于vector容器来说,如果有大量的数据需要进行push_back,应当使用reserve()函数提前设定其容量大小,否则会出现许多次容量扩充操作,导致效率低下。
void swap( vector &from );//交换当前vector与vector from的元素
void swap( vector &from1,vector &from2 );//交换vector form1与vector from2的元素 

vector迭代器的几种失效的情况: 
a.当插入(push_back)一个元素后,end操作返回的迭代器肯定失效。 
b.当插入(push_back)一个元素后,capacity返回值与没有插入元素之前相比有改变,则需要重新加载整个容器,此时first和end操作返回的迭代器都会失效。 
c.当进行删除操作(erase,pop_back)后,指向删除点的迭代器全部失效;指向删除点后面的元素的迭代器也将全部失效。 


原则:尽量使用区间成员函数代替它们的单元素参数兄弟成员函数
原则:使得容器中元素的拷贝操作轻量而正确,拷贝是STL中容器的运行的基本方式,将元素加入到容器,必然保持一个拷贝,容器中的元素不再是原来的那个元素,所以如果将指针加入容器,必须在容器离开作用域以前删除指针所指的对象。
原则:必须是已存在的元素才能用下标操作符进行索引。
原则:注意对于 vector,任何插入删除操作都会引起迭代器失效。所以要小心。
原则:不要使用auto_ptr作为模板参数来建立容器,这会产生意想不到的陷阱,因为auto_ptr的拷贝有特殊的语义
原则:避免使用vector<bool>, 因为它不能当作标准容器来用
原则:尽量使用标准容器自带的算法代替公共算法。
原则:尽量使用reserve来减少不必要的内存分配次数。
原则:使用erase-remove惯用法删除元素  v1.erase( remove(v1.begin(), v1.end(), 3.0),  v1.end() );
原则:尽量使用empty而不是size()==0 来判断容器是否为空

使用“交换技巧”来修整vector过剩空间/内存:
      有一种方法来把它从曾经最大的容量减少到它现在需要的容量。这样减少容量的方法常常被称为“收缩到合适(shrink to fit)”。该方法只需一条语句:vector<int>(ivec).swap(ivec);
表达式vector<int>(ivec)建立一个临时vector,它是ivec的一份拷贝:vector的拷贝构造函数做了这个工作。但是,vector的拷贝构造函数只分配拷贝的元素需要的内存,所以这个临时vector没有多余的容量。然后我们让临时vector和ivec交换数据,这时我们完成了,ivec只有临时变量的修整过的容量,而这个临时变量则持有了曾经在ivec中的没用到的过剩容量。在这里(这个语句结尾),临时vector被销毁,因此释放了以前ivec使用的内存,收缩到合适。

用swap方法强行释放STL Vector所占内存:
template < class T> void ClearVector( vector<T>& v )
{
    vector<T>vtTemp;
    vtTemp.swap( v );
}

    vector<int> v ;
    nums.push_back(1);
    nums.push_back(3);
    nums.push_back(2);
    nums.push_back(4);
    vector<int>().swap(v);
/* 或者v.swap(vector<int>()); */

/*或者{ std::vector<int> tmp = v;   v.swap(tmp);   }; //加大括号{ }是让tmp退出{ }时自动析构*/


#include<algorithm>中的泛函算法
搜索算法:find() 、search() 、count() 、find_if() 、search_if() 、count_if()
分类排序:sort() 、merge()
删除算法:unique() 、remove()
生成和变异:generate() 、fill() 、transformation() 、copy()
关系算法:equal() 、min() 、max()

iterator失效主要有两种情况: 
a.iterator变量已经变成了“悬空指针”,对它进行*,++,--都会引起程序内存操作异常; 
b.iterator所指向的变量已经不是你所以为的那个变量了。



6.Stack容器:

堆栈是一种线性表,栈是一种容器适配器,特别为后入先出而设计的一种(LIFO ),那种数据被插入。由于堆栈的底层使用的是其他容器,因此,堆栈可看做是一种适配器,将一种容器转换为另一种容器(堆栈容器)。默认的参数中容器是用deque实现的;被包含的容器要满足提供value_type,size_type,empt,size,push_back,pop_back;可选择的容器有list,deque,vector;要求有最快的平均访问速度,而且大概的容量要求也清楚(比较衡定),那么,使用vector是个不错的选择 要求每次的访问时间平稳,而不在乎平均访问时间时,那么,可以考虑使用list;所以,库默认的deque是个不错的选择,它介于vector和list之间,并且很好的综合了两者的优势。



为了严格遵循堆栈的数据后进先出原则,stack 不提供元素的任何迭代器操作,因此,stack 容器也就不会向外部提供可用的前向或反向迭代器类型。

创建函数:

stack();//      默认构造函数,创建一个空的 stack 对象。

stack(const stack&);//  复制构造函数,用一个 stack 堆栈创建一个新的堆栈。


出入栈函数:

void  push(const value_type& x);//入栈,由于 C++ STL 的堆栈函数是不预设大小的,因此,入栈函数就不考虑堆栈空间是否为满,均将元素压入堆栈,从而函数没有标明入栈成功与否的返回值。
void pop();//    stack容器的元素出栈函数为 pop 函数,由于函数并没有判断堆栈是否为空,才进行元素的弹出,因此,需要自行判断堆栈是否为空,才可执行 pop 函数。

遍历函数:

value_type&  top();//取栈顶元素,原理是先pop后push

属性函数:

size_type size ( ) const;//计算栈对象元素个数

bool  empty();//一般需要调用 empty 函数判断是否非空,才作元素出栈和取栈顶元素的操作。


7.queue容器:

与stack 模板类很相似,queue 模板类也需要两个模板参数,一个是元素类型,一个容器类型,元素类型是必要的,容器类型是可选的,默认为deque 类型。



8.deque容器:

deque的实现比较复杂,内部会维护一个map(注意!不是STL中的map容器)即一小块连续的空间,该空间中每个元素都是指针,指向另一段(较大的)区域,这个区域称为缓冲区,缓冲区用来保存deque中的数据。因此deque在随机访问和遍历数据会比vector慢。具体的deque实现可以参考《STL源码剖析》,当然此书中使用的SGI STL与VS2008所使用的PJ STL的实现方法还是有区别的。下面给出了deque的结构图:







  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值