STL 容器的一些方法和demo整理

1.vector

 0.vector 底部实现为数组,支持快速的在底部添加数据 ,但是它的修改是n级别的

1 基本操作

(1)头文件#include<vector>.

(2)创建vector对象,vector<int> vec;

(3)尾部插入数字:vec.push_back(a);

(4)使用下标访问元素,cout<<vec[0]<<endl;记住下标是从0开始的。

(5)使用迭代器访问元素.

vector<int>::iterator it;
for(it=vec.begin();it!=vec.end();it++)
    cout<<*it<<endl;

(6)插入元素:    vec.insert(vec.begin()+i,a);在第i+1个元素前面插入a;

(7)删除元素:    vec.erase(vec.begin()+2);删除第3个元素

vec.erase(vec.begin()+i,vec.end()+j);删除区间[i,j-1];区间从0开始

(8)向量大小:vec.size();

(9)清空:vec.clear();



2,删除指定元素时的代码:

#include<iostream>
#include<string>
#include<vector>
using namespace std;

int out(vector<int> &iVec)
{
    for(int i=0;i<iVec.size();i++)
        cout<<iVec[i]<<ends;
    cout<<endl;
    return 0;
}

int main()
{
    vector<int> iVec;
    vector<int>::iterator it;
    int i;
    for( i=0;i<10;i++)
        iVec.push_back(i);

    cout<<"The Num(old):";out(iVec);
    for(it=iVec.begin();it!=iVec.end();)
    {
        if(*it % 3 ==0)
            it=iVec.erase(it);    //删除元素,返回值指向已删除元素的下一个位置    
        else
            ++it;    //指向下一个位置
    }
    cout<<"The Num(new):";out(iVec);
    return 0;
}





2.list

0.Lists将元素按顺序储存在链表中. 与 向量(vectors)相比, 它允许快速的插入和删除,但是随机访问却比较慢.



1.基本操作


assign() 给list赋值 
back() 返回最后一个元素 
begin() 返回指向第一个元素的迭代器 
clear() 删除所有元素 
empty() 如果list是空的则返回true 
end() 返回末尾的迭代器 
erase() 删除一个元素 
front() 返回第一个元素 
get_allocator() 返回list的配置器 
insert() 插入一个元素到list中 
max_size() 返回list能容纳的最大元素数量 
merge() 合并两个list 
pop_back() 删除最后一个元素 
pop_front() 删除第一个元素 
push_back() 在list的末尾添加一个元素 
push_front() 在list的头部添加一个元素 
rbegin() 返回指向第一个元素的逆向迭代器 
remove() 从list删除元素 
remove_if() 按指定条件删除元素 
rend() 指向list末尾的逆向迭代器 
resize() 改变list的大小 
reverse() 把list的元素倒转 
size() 返回list中的元素个数 
sort() 给list排序 
splice() 合并两个list 
swap() 交换两个list 
unique() 删除list中重复的元素


2.DEMO

    #include <iostream>   
    #include <list>   
    #include <numeric>   
    #include <algorithm>   
    using namespace std;   
      
    //创建一个list容器的实例LISTINT   
    typedef list<int> LISTINT;   
    //创建一个list容器的实例LISTCHAR   
    typedef list<int> LISTCHAR;   
      
    void main()   
    {   
        //用list容器处理整型数据    
        //用LISTINT创建一个名为listOne的list对象   
        LISTINT listOne;   
        //声明i为迭代器   
        LISTINT::iterator i;   
          
        //从前面向listOne容器中添加数据   
        listOne.push_front (2);   
        listOne.push_front (1);   
          
        //从后面向listOne容器中添加数据   
        listOne.push_back (3);   
        listOne.push_back (4);   
          
        //从前向后显示listOne中的数据   
        cout<<"listOne.begin()--- listOne.end():"<<endl;   
        for (i = listOne.begin(); i != listOne.end(); ++i)   
            cout << *i << " ";   
        cout << endl;   
          
        //从后向后显示listOne中的数据   
        LISTINT::reverse_iterator ir;   
        cout<<"listOne.rbegin()---listOne.rend():"<<endl;   
        for (ir =listOne.rbegin(); ir!=listOne.rend();ir++) {   
            cout << *ir << " ";   
        }   
        cout << endl;   
          
        //使用STL的accumulate(累加)算法   
        int result = accumulate(listOne.begin(), listOne.end(),0);   
        cout<<"Sum="<<result<<endl;   
        cout<<"------------------"<<endl;   
          
        //--------------------------   
        //用list容器处理字符型数据   
        //--------------------------   
          
        //用LISTCHAR创建一个名为listOne的list对象   
        LISTCHAR listTwo;   
        //声明i为迭代器   
        LISTCHAR::iterator j;   
          
        //从前面向listTwo容器中添加数据   
        listTwo.push_front ('A');   
        listTwo.push_front ('B');   
          
        //从后面向listTwo容器中添加数据   
        listTwo.push_back ('x');   
        listTwo.push_back ('y');   
          
        //从前向后显示listTwo中的数据   
        cout<<"listTwo.begin()---listTwo.end():"<<endl;   
        for (j = listTwo.begin(); j != listTwo.end(); ++j)   
            cout << char(*j) << " ";   
        cout << endl;   
          
        //使用STL的max_element算法求listTwo中的最大元素并显示   
        j=max_element(listTwo.begin(),listTwo.end());   
        cout << "The maximum element in listTwo is: "<<char(*j)<<endl;   
    }   

    #include <iostream>   
    #include <list>   
      
    using namespace std;   
    typedef list<int> INTLIST;   
      
    //从前向后显示list队列的全部元素   
    void put_list(INTLIST list, char *name)   
    {   
        INTLIST::iterator plist;   
          
        cout << "The contents of " << name << " : ";   
        for(plist = list.begin(); plist != list.end(); plist++)   
            cout << *plist << " ";   
        cout<<endl;   
    }   
      
    //测试list容器的功能   
    void main(void)   
    {   
        //list1对象初始为空   
        INTLIST list1;   
        //list2对象最初有10个值为6的元素   
        INTLIST list2(10,6);   
        //list3对象最初有3个值为6的元素   
        INTLIST list3(list2.begin(),--list2.end());   
          
        //声明一个名为i的双向迭代器   
        INTLIST::iterator i;   
          
        //从前向后显示各list对象的元素   
        put_list(list1,"list1");   
        put_list(list2,"list2");   
        put_list(list3,"list3");   
          
        //从list1序列后面添加两个元素   
        list1.push_back(2);   
        list1.push_back(4);   
        cout<<"list1.push_back(2) and list1.push_back(4):"<<endl;   
        put_list(list1,"list1");   
          
        //从list1序列前面添加两个元素   
        list1.push_front(5);   
        list1.push_front(7);   
        cout<<"list1.push_front(5) and list1.push_front(7):"<<endl;   
        put_list(list1,"list1");   
          
        //在list1序列中间插入数据   
        list1.insert(++list1.begin(),3,9);   
        cout<<"list1.insert(list1.begin()+1,3,9):"<<endl;   
        put_list(list1,"list1");   
          
        //测试引用类函数   
        cout<<"list1.front()="<<list1.front()<<endl;   
        cout<<"list1.back()="<<list1.back()<<endl;   
          
        //从list1序列的前后各移去一个元素   
        list1.pop_front();   
        list1.pop_back();   
        cout<<"list1.pop_front() and list1.pop_back():"<<endl;   
        put_list(list1,"list1");   
          
        //清除list1中的第2个元素   
        list1.erase(++list1.begin());   
        cout<<"list1.erase(++list1.begin()):"<<endl;   
        put_list(list1,"list1");   
          
        //对list2赋值并显示   
        list2.assign(8,1);   
        cout<<"list2.assign(8,1):"<<endl;   
        put_list(list2,"list2");   
          
        //显示序列的状态信息   
        cout<<"list1.max_size(): "<<list1.max_size()<<endl;   
        cout<<"list1.size(): "<<list1.size()<<endl;   
        cout<<"list1.empty(): "<<list1.empty()<<endl;   
          
        //list序列容器的运算   
        put_list(list1,"list1");   
        put_list(list3,"list3");   
        cout<<"list1>list3: "<<(list1>list3)<<endl;   
        cout<<"list1<list3: "<<(list1<list3)<<endl;   
          
        //对list1容器排序   
        list1.sort();   
        put_list(list1,"list1");   
          
        //结合处理   
        list1.splice(++list1.begin(), list3);   
        put_list(list1,"list1");   
        put_list(list3,"list3");   
    }   


3.priority queue


0.

优先队列:顾名思义,首先它是一个队列,但是它强调了“优先”二字,所以,已经不能算是一般意义上的队列了,它的“优先”意指取队首元素时,有一定的选择性,即根据元素的属性选择某一项值最优的出队~
百度百科上这样描述的:
  优先级队列 是不同于先进先出队列的另一种队列。每次从队列中取出的是具有最高优先权的元素
  优先队列的类定义  
  优先队列是0个或多个元素的集合,每个元素都有一个优先权或值,对优先队列执行的操作有1) 查找;2) 插入一个新元素;3) 删除.在最小优先队列(min priorityq u e u e)中,查找操作用来搜索优先权最小的元素,删除操作用来删除该元素;对于最大优先队列(max priority queue),查找操作用来搜索优先权最大的元素,删除操作用来删除该元素.优先权队列中的元素可以有相同的优先权,查找与删除操作可根据任意优先权进行. 
优先队列,其构造及具体实现我们可以先不用深究,我们现在只需要了解其特性,及在做题中的用法,相信,看过之后你会收获不少。
使用优先队列,首先要包函STL头文件"queue",

如果我们要把元素从小到大输出怎么办呢?
这时我们可以传入一个比较函数,使用functional.h函数对象作为比较函数。
 
 
priority_queue < int , vector < int > , greater < int >   > qi2;

1.基本操作

#include<stdio.h>  
#include<functional>  
#include<queue>  
#include<vector>  
using namespace std;  
//定义结构,使用运算符重载,自定义优先级1  
struct cmp1{  
    bool operator ()(int &a,int &b){  
        return a>b;//最小值优先  
    }  
};  
struct cmp2{  
    bool operator ()(int &a,int &b){  
        return a<b;//最大值优先  
    }  
};  
//定义结构,使用运算符重载,自定义优先级2  
struct number1{  
    int x;  
    bool operator < (const number1 &a) const {  
        return x>a.x;//最小值优先  
    }  
};  
struct number2{  
    int x;  
    bool operator < (const number2 &a) const {  
        return x<a.x;//最大值优先  
    }  
};  
int a[]={14,10,56,7,83,22,36,91,3,47,72,0};  
number1 num1[]={14,10,56,7,83,22,36,91,3,47,72,0};  
number2 num2[]={14,10,56,7,83,22,36,91,3,47,72,0};  
  
int main()  
{   priority_queue<int>que;//采用默认优先级构造队列  
  
    priority_queue<int,vector<int>,cmp1>que1;//最小值优先  
    priority_queue<int,vector<int>,cmp2>que2;//最大值优先  
  
    priority_queue<int,vector<int>,greater<int> >que3;//注意“>>”会被认为错误,  
                                                      //这是右移运算符,所以这里用空格号隔开  
    priority_queue<int,vector<int>,less<int> >que4;最大值优先  
  
    priority_queue<number1>que5;  
    priority_queue<number2>que6;  
  
    int i;  
    for(i=0;a[i];i++){  
        que.push(a[i]);  
        que1.push(a[i]);  
        que2.push(a[i]);  
        que3.push(a[i]);  
        que4.push(a[i]);  
    }  
    for(i=0;num1[i].x;i++)  
        que5.push(num1[i]);  
    for(i=0;num2[i].x;i++)  
        que6.push(num2[i]);  
  
  
    printf("采用默认优先关系:\n(priority_queue<int>que;)\n");  
    printf("Queue 0:\n");  
    while(!que.empty()){  
        printf("%3d",que.top());  
        que.pop();  
    }  
    puts("");  
    puts("");  
  
    printf("采用结构体自定义优先级方式一:\n(priority_queue<int,vector<int>,cmp>que;)\n");  
    printf("Queue 1:\n");  
    while(!que1.empty()){  
        printf("%3d",que1.top());  
        que1.pop();  
    }  
    puts("");  
    printf("Queue 2:\n");  
    while(!que2.empty()){  
        printf("%3d",que2.top());  
        que2.pop();  
    }  
    puts("");  
    puts("");  
    printf("采用头文件\"functional\"内定义优先级:\n(priority_queue<int,vector<int>,greater<int>/less<int> >que;)\n");  
    printf("Queue 3:\n");  
    while(!que3.empty()){  
        printf("%3d",que3.top());  
        que3.pop();  
    }  
    puts("");  
    printf("Queue 4:\n");  
    while(!que4.empty()){  
        printf("%3d",que4.top());  
        que4.pop();  
    }  
    puts("");  
    puts("");  
    printf("采用结构体自定义优先级方式二:\n(priority_queue<number>que)\n");  
    printf("Queue 5:\n");  
    while(!que5.empty()){  
        printf("%3d",que5.top());  
        que5.pop();  
    }  
    puts("");  
    printf("Queue 6:\n");  
    while(!que6.empty()){  
        printf("%3d",que6.top());  
        que6.pop();  
    }  
    puts("");  
    return 0;  
}  
/* 


4.set

0.set集合容器:实现了红黑树的平衡二叉检索树的数据结构,插入元素时,它会自动调整二叉树的排列,把元素放到适当的位置,以保证每个子树根节点键值大于左子树所有节点的键值,小于右子树所有节点的键值;另外,还得保证根节点左子树的高度与右子树高度相等。
平衡二叉检索树使用中序遍历算法,检索效率高于vector、deque和list等容器,另外使用中序遍历可将键值按照从小到大遍历出来。
构造set集合主要目的是为了快速检索,不可直接去修改键值。


1.基本操作

1.元素插入:insert()
2.中序遍历:类似vector遍历(用迭代器)
3.反向遍历:利用反向迭代器reverse_iterator。
    例:
    set<int> s;
    ......
    set<int>::reverse_iterator rit;
    for(rit=s.rbegin();rit!=s.rend();rit++)
4.元素删除:与插入一样,可以高效的删除,并自动调整使红黑树平衡。
            set<int> s;
            s.erase(2);        //删除键值为2的元素
            s.clear();
5.元素检索:find(),若找到,返回该键值迭代器的位置,否则,返回最后一个元素后面一个位置。
            set<int> s;
            set<int>::iterator it;
            it=s.find(5);    //查找键值为5的元素
            if(it!=s.end())    //找到
                cout<<*it<<endl;
            else            //未找到
                cout<<"未找到";
6.自定义比较函数
    (1)元素不是结构体:
        例:
        //自定义比较函数myComp,重载“()”操作符
        struct myComp
        {
            bool operator()(const your_type &a,const your_type &b)
            [
                return a.data-b.data>0;
            }
        }
        set<int,myComp>s;
        ......
        set<int,myComp>::iterator it;
    (2)如果元素是结构体,可以直接将比较函数写在结构体内。
        例:
        struct Info
        {
            string name;
            float score;
            //重载“<”操作符,自定义排序规则
            bool operator < (const Info &a) const
            {
                //按score从大到小排列
                return a.score<score;
            }
        }
        set<Info> s;
        ......
        set<Info>::iterator it;



5.map

0.map是一类关联式容器,它是模板类。关联的本质在于元素的值与某个特定的键相关联,而并非通过元素在数组中的位置类获取。它的特点是增加和删除节点对迭代器的影响很小,除了操作节点,对其他的节点都没有什么影响。对于迭代器来说,不可以修改键值,只能修改其对应的实值。


1.基本操作

map的基本操作函数:
      C++ Maps是一种关联式容器,包含“关键字/值”对
      begin()          返回指向map头部的迭代器
      clear()         删除所有元素
      count()          返回指定元素出现的次数
      empty()          如果map为空则返回true
      end()            返回指向map末尾的迭代器
      equal_range()    返回特殊条目的迭代器对
      erase()          删除一个元素
      find()           查找一个元素
      get_allocator()  返回map的配置器
      insert()         插入元素
      key_comp()       返回比较元素key的函数
      lower_bound()    返回键值>=给定元素的第一个位置
      max_size()       返回可以容纳的最大元素个数
      rbegin()         返回一个指向map尾部的逆向迭代器
      rend()           返回一个指向map头部的逆向迭代器
      size()           返回map中元素的个数
      swap()            交换两个map
      upper_bound()     返回键值>给定元素的第一个位置
      value_comp()      返回比较元素value的函数



  1   头文件 
  #include   <map> 
  
  2   定义 
  map<string,   int>   my_Map; 
  或者是typedef     map<string,   int>   MY_MAP; 
  MY_MAP   my_Map; 
  
  3   插入数据 
  (1)   my_Map["a"]   =   1; 
  (2)   my_Map.insert(map<string,   int>::value_type("b",2)); 
  (3)   my_Map.insert(pair<string,int>("c",3)); 
  (4)   my_Map.insert(make_pair<string,int>("d",4)); 
  
  4   查找数据和修改数据 
  (1)   int   i   =   my_Map["a"]; 
            my_Map["a"]   =   i; 
  (2)   MY_MAP::iterator   my_Itr; 
            my_Itr.find("b"); 
            int   j   =   my_Itr->second; 
            my_Itr->second   =   j; 
  不过注意,键本身是不能被修改的,除非删除。 
  
  5   删除数据 
  (1)   my_Map.erase(my_Itr); 
  (2)   my_Map.erase("c"); 
  还是注意,第一种情况在迭代期间是不能被删除的,道理和foreach时不能删除元素一样。 
  
  6   迭代数据 
  for   (my_Itr=my_Map.begin();   my_Itr!=my_Map.end();   ++my_Itr)   {} 
  
  7   其它方法 
  my_Map.size()               返回元素数目 
  my_Map.empty()       判断是否为空 
  my_Map.clear()           清空所有元素 
  可以直接进行赋值和比较:=,   >,   >=,   <,   <=,   !=   等等


自定义比较规则

我们可以自定义一个按照key中的string长度排序,程序如下:

#include<iostream>
#include<string>
#include<algorithm>
#include<map>
using namespace std; 

struct cmp  //自定义比较规则
{
  bool operator() (const string& str1, const string& str2)
  {
    return str1.length() < str2.length(); 
  }
};

int main()
{
  map<string, int, cmp > scoreMap;  //这边调用cmp  
  map<string, int, cmp >::iterator iter; 

  scoreMap["LiMin"] = 90; 
  scoreMap["ZZihsf"] = 95; 
  scoreMap["Kim"] = 100;
  scoreMap.insert(map<string, int>::value_type("Jack", 88)); 

  for(iter=scoreMap.begin(); iter!=scoreMap.end(); iter++)
    cout<<iter->first<<' '<<iter->second<<endl; 

  return 0; 
}

\

按照这个示例,我们还可以设计其他的比较规则,把比较规则写在cmp结构中,然后在定义map的时候调用即可~

 根据value排序

其实更多的时候,我们需要对value进行排序,比如对学生成绩这个map进行排序的时候,我们不大可能需要名字排序,却很有可能需要按照分数进 行排序。那么问题来了,我们是否可以按照上面那样子,简单的指明一个参数,或者自定义一个比较规则cmp即可呢?答案是失望的,map模板里面没有这个性 能。。。

究其原因,map是个关联容器,不是序列容器。像是一些序列容器list, vector都是可以排序的~咦,我们可不可以把map中的<key, value>对放在一个vector中呢?那样是否就可以直接用vetor的sort函数呢?这个想法不错~

下面我们来详细说一下这个想法:

首先,map中的<key, value>是pair形式的,那么我们就可以把一个pair作为vector中的元素;

然后,调用vetor容器中的sort函数,sort函数也是可以用户指定比较类型的。

template <class RandomAccessIterator>  
  void sort ( RandomAccessIterator first, RandomAccessIterator last );  
  
template <class RandomAccessIterator, class Compare>  
  void sort ( RandomAccessIterator first, RandomAccessIterator last, Compare comp );

程序如下:

#include<iostream>
#include<string>
#include<algorithm>
#include<map>
#include<vector>
using namespace std; 

typedef pair<string, int> PAIR; 

struct cmp  //自定义比较规则
{
  bool operator() (const PAIR& P1, const PAIR& P2)  //注意是PAIR类型,需要.firt和.second。这个和map类似
  {
    return P1.second < P2.second; 
  }
};


int main()
{
  map<string, int> scoreMap;  //这边调用cmp  
  map<string, int>::iterator iter; 

  scoreMap["LiMin"] = 90; 
  scoreMap["ZZihsf"] = 95; 
  scoreMap["Kim"] = 100;
  scoreMap.insert(map<string, int>::value_type("Jack", 88)); 

  vector<PAIR>scoreVector; 
  for(iter=scoreMap.begin(); iter!=scoreMap.end();iter++)  //这边本来是使用vector直接初始化的,当时由于vc 6.0 编译器问题,只能这样写,而且还有非法内存。。
    scoreVector.push_back(*iter); 
  //转化为PAIR的vector
  sort(scoreVector.begin(), scoreVector.end(), cmp());  //需要指定cmp

  for(int i=0; i<=scoreVector.size(); i++)  //也要按照vector的形式输出
    cout<< scoreVector[i].first<<' '<<scoreVector[i].second <<endl; 

  /*
  for(iter=scoreMap.begin(); iter!=scoreMap.end(); iter++)
    cout<<iter->first<<' '<<iter->second<<endl; 
  */

  return 0; 
}

\

这样我们就把map的排序:按照key排序;按照value排序都说好了~


但是 map归根到底是一个关联容器,如果遇到 需要 操作的还是使用vector 比较合适.

6.总结

C++ STL 的实现:

1.vector  底层数据结构为数组 ,支持快速随机访问

2.list    底层数据结构为双向链表,支持快速增删

3.deque   底层数据结构为一个中央控制器和多个缓冲区,详细见STL源码剖析P146,支持首尾(中间不能)快速增删,也支持随机访问

4.stack   底层一般用23实现,封闭头部即可,不用vector的原因应该是容量大小有限制,扩容耗时

5.queue   底层一般用23实现,封闭头部即可,不用vector的原因应该是容量大小有限制,扩容耗时

6.45是适配器,不叫容器因为容器封装

7.priority_queue 的底层数据结构一般为vector为底层容器,堆heap为处理规则来管理底层容器实现

8.set       底层数据结构为红黑树,有序,不重复

9.multiset  底层数据结构为红黑树,有序,可重复 

10.map      底层数据结构为红黑树,有序,不重复

11.multimap 底层数据结构为红黑树,有序,可重复

12.hash_set 底层数据结构为hash表,无序,不重复

13.hash_multiset 底层数据结构为hash表,无序,可重复 

14.hash_map      底层数据结构为hash表,无序,不重复

15.hash_multimap 底层数据结构为hash表,无序,可重复


  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值