美文网首页
三、常用容器(Stack、Queue、List、Set)

三、常用容器(Stack、Queue、List、Set)

作者: 木鱼_cc | 来源:发表于2018-06-16 18:02 被阅读0次

    1.Stack 栈容器

    栈同数据结构的定义和特性一样,自己去查,这里介绍栈的API

    特别说明:stack没有遍历行为!!

    构造函数

    stack<T> stkT;//stack采用模板类实现,stack对象的默认构造函数
    stack(const stack &stk);//拷贝构造函数
    

    stack赋值操作

    stack & operator=(const stack &stk);//重载等号操作符
    

    数据存取操作

    void push(const TYPE & elem);//向栈顶添加一个元素
    void pop();//从栈顶移除一个元素
    TYPE & top();//返回栈顶元素
    

    大小操作

    bool empty();//判断堆栈是否为空
    int size();//返回堆栈的大小
    

    2.Queue 队列

    2.1queue概念

    queue是一种先进先出(first in first out,FIFO)的数据类型,它有两个口,数据元素只能从一个口进,从另一个口出。队列只允许从队尾加入元素,队头删除元素,必须符合先进先出原则,queue和stack一样不具有遍历行为!

    1.png

    特点

    • 必须从一个口数据元素入队,另一个口数据元素出队
    • 不能随机存取,不支持遍历
    2.2queue常用API

    构造函数

    queue<T> queT;//queue采用模板类实现,queue对象的默认构造形式
    queue(const queue &que);//拷贝构造函数
    

    queue存取、插入和删除操作

    void push(const TYPE &elem);//往队尾添加元素
    void pop();//从队头移除第一个元素
    TYPE & back();//返回最后一个元素
    TYPE & front();//返回第一个元素
    

    queue赋值操作

    queue& operator=(const queue &que);
    

    queue大小操作

    bool empty();//判断队列是否为空
    int size();//返回队列大小
    

    3.list容器(双向链表)

    3.1list特性

    链表是一种物理存储单元上非连续、非顺序的存储数据结构,数据元素的逻辑顺序是通过链表中的指针次序实现的。链表由一系列的结点(链表中每一个元素称为结点)组成,结点可以在运行时动态生成。每个结点包括两个部分:一个是存储数据元素的数据域,另一个是存储下一个结点地址的指针域

    2.png

    特性总结

    • 采用动态存储分配,不会造成内存浪费和溢出
    • 链表执行插入和删除操作十分方便,修改指针即可,不需要移动大量元素
    • 链表灵活,但是空间和时间额外消耗较大
    3.2 list常用API

    list初始化

    list<T> list;//默认构造函数
    list(iterator beg,iterator end);//构造函数将[beg,end)区间中的元素拷贝给本身
    list(int n,TYPE & elem);//构造函数将n个elem拷贝给自身
    list(const list &lst);//拷贝构造函数
    

    list数据元素插入和删除操作

    void push_back(const TYPE &elem);//在容器尾部加入一个元素
    void pop_back();//在容器尾部删除一个元素
    push_front(const TYPE &elem);//在容器头部加入一个元素
    pop_front(const TYPE &elem);//在容器开头移除一个元素
    iterator insert(iterator pos,const TYPE & elem);//在pos位置插elem元素的拷贝,返回新数据的位置
    void insert(iterator pos,int n,const TYPE &elem);//在pos位置插入n个elem元素
    void insert(iterator pos,iterator beg,iterator end);//在pos位置插入[beg,end)区间的数据
    void clear();//移除容器的所有数据
    iterator erase(iterator beg,iterator end);//删除[beg,end)区间的数据,返回下一个数据的位置
    iterator erase(iterator pos);//删除pos位置的数据,返回下一个数据的位置
    void remove(const &TYPE elem);//删除容器中所有与elem值匹配的元素
    

    大小操作

    int size();//返回容器中的元素个数
    bool empty();//判断容器是否为空
    void resize(int num);//重新制定容器长度为num,若边长,则以默认值填充新位置
    //若变短,则末尾超出容器长度的元素被删除
    void resize(int num,const TYPE & elem);//重新制定容器长度为num,若边长,则以elem填充新位置
    //若变短,则末尾超出容器长度的元素被删除
    

    list赋值操作

    void assign(iterator beg,iterator end);//将[beg,end)区间中的数据拷贝赋值给本身
    void assign(int num,const TYPE &elem);//将n个elem拷贝给自身
    list & operator=(const list &lst);//重载=号操作符
    void swap(lst);//将lst与本身的元素互换
    
    注意:assign和assign并不是叠加关系,而是重新构造的关系
    
    

    list数据的存取

    TYPE front();//返回第一个元素
    TYPE back();//返回最后一个元素
    

    list反转排列排序

    void reverse();//反转链表  1,3,5 变 5,3,1
    void sort();//List排序,默认从小到大
    

    链表和数组有什么区别

    • 数组必须实现定义固定的长度(元素个数),不能适应数据动态增减的情况。当数据增加时,可能超出原先定义的元素的个数;当数据减少时,造成内存浪费
    • 链表动态地进行存储分配,可以适应数据动态地增减的情况,且可以方便地插入、删除

    4. Set集合

    4.1 set/multiset特性

    set/multiset的特性是所有元素会根据元素的值自动进行排序。set是以RB-tree(红黑树,平衡二叉树的一种)为底层机制,其查找效率非常好。set容器中不允许重复元素,multiset允许重复元素

    1.png

    问:我们可以通过set的迭代器改变元素的值吗?

    答:不行,因为set集合是根据元素值进行排序的,关系到set的排序规则,如果任意改变set的元素值,会严重破会set组织。只能先删掉,再插入,就是二叉排序树的关系嘛!!

    set构造函数

    set<T> st;//默认构造函数
    multiset<T> mst;//multiset默认构造函数
    set(const set &st);//拷贝构造函数
    

    set赋值操作

    set & operator=(const set &st);
    void swap(st);//交换两个集合器
    

    set大小操作

    int size();//返回容器中元素的数目
    bool empty();//判断容器是否为空
    

    set插入和删除操作

    void insert(const TYPE & elem);//在容器中插入元素
    void clear();//清楚所有元素
    iterator erase(iterator pos);//删除pos爹地器所指的元素,返回下一个元素的迭代器
    iterator erase(iterator beg,iterator end);//删除区间[beg,end)的所有元素,返回下一个元素的迭代器
    int erase(const TYPE &elem);//删除容器中值为elem的元素
    
    
    
    void test(){
    
       set<int> myset;//默认从小到大排序
       myset.insert(4);
       myset.insert(2);
       myset.insert(1);
       myset.insert(5);
       myset.insert(2);
    
       printSet(myset);
    
       //删除
       myset.erase(myset.begin());//删除第一个元素
       myset.erase(2);//根据元素值删除
       printSet(myset);
     myset.erase(myset.beigin(),myset.end());//myset.clear();
     
       cout<<"size:"<<myset.size();
    
    }
    
    2.png

    multiset操作同理类似

    #include <set>
    
    int main(int argc, char const *argv[])
    {
        
        multiset<int> muset;
        muset.insert(10);
        muset.insert(20);
        muset.insert(5);
        muset.insert(35);
        muset.insert(5);
    
        for (multiset<int>::iterator it = muset.begin(); it != muset.end();it++)
        {
            cout<<*it<<" "<<endl;
        }
    
        return 0;
    }
    
    3.jpg

    set查找操作

    iterator find(const TYPE &key);//在当前集合中查找等于key值的元素,并返回指向该元素的迭代器;如果没有找到,返回指向集合最后一个元素的迭代器。
    iterator lower_bound(const TYPE &keyElem);//返回第一个>=keyElem元素的迭代器
    iterator upper_bound(const TYPE &keyElem);//返回第一个>keyElem元素的迭代器
    pairii equal_bound(const TYPE &keyElem);//返回容器中key与keyElem相等的上下限的两个迭代器
    
    class Teacher
    {
    public:
        Teacher(int id,int age){
            this->id = id;
            this->age = age;
        }
    private:
        int id;
        int age;
    }
    
    class compare
    {
    public:
         bool operator()(Teacher t1,Teacher t2){
            return t1.id>t2.id;
         }
    }
    
    void test(){
       
        Teacher t1(1,2),t2(3,4),t3(5,6);
        set<Teacher,compare> myset;
    
        myset.insert(t1);
        myset.insert(t2);
        myset.insert(t3);
    
        set<Teacher,compare>::iterator pos = myset.find(Teacher(3,10));
        if (pos == myset.end())//竟然能查找到,因为它是根据id排序的
                               //所以查找也是根据id查找的,id = 3和t2重复!
                               //所以能查到
        {
            cout<<"没有查找到!"<<endl;
        }
        else{
            cout<<"查找到:"<<pos->id<<":"<<pos->age<<endl;
        }
    }
    
    ----------------------------------------------------
    void test2(){
        set<int> myset;
        myset.insert(10);
        myset.insert(5);
        myset.insert(1);
        myset.insert(8);
    
        set<int>::iterator pos = myset.lower_bound(5);//查找第一个>=5的迭代器
        if (pos ==myset.end())
        {
            cout<<"没有找到"<<endl;
        }
        else{
            cout<<"找到:"<<*pos<<endl;
        }
    
    
        pos = myset.upper_bound(5);//返回第一个>keyElem元素的迭代器
        if (pos ==myset.end())
        {
            cout<<"没有找到"<<endl;
        }
        else{
            cout<<"找到:"<<*pos<<endl;
        }
    
        pair<set<int>::iterator,set<int>iterator> pos2 = myset.equal_range(5);
        if (pos2.first == myset.end())
        {
            cout<<"没有找到"<<endl;
        }
        else{
            cout<<"找到:"<<*(pos2.first)<<endl;
        }
    
        if (pos2.second == myset.end())
        {
            cout<<"没有找到"<<endl;
        }
        else{
            cout<<"找到:"<<*(pos2.first)<<endl;
        }
    }
    
    

    问题:我们发现打印出来set集合中的元素都是从小到大的升序排序,那么我们如何制定排序为降序呢?这个问题呢?我们需要了解函数对象的概念。

    #include <functional>//预定义函数对象
    
    set<int,greater<int>> myset;//从大到小
    set<int,less<int>> myset;//从小到大
    
    
    template<class T>
    class compare{
    public:
       bool operator()(T v1,T v2) const{
              return v1>v2;
       }
    };
    
    //函数对象
    compare mycom;
    mycom<int>(1,2);//函数对象 仿函数
    
    set<int,compare<int>> myset;
    
    

    相关文章

      网友评论

          本文标题:三、常用容器(Stack、Queue、List、Set)

          本文链接:https://www.haomeiwen.com/subject/tkxmeftx.html