C++学习之第十八天-STL有序关联式容器-set、map

关联式容器—set、multiset、map、multimap知识点总览

1.关联式容器:

            底层实现使用红黑树。初始化、遍历、查找(count,find)、插入(insert)(set与map需要判断插入是不是成功),自定义类型需要去对Compare进行改写(std::less、std::greater、函数对象)。

2.set

1、不能存放关键字key相同的元素,关键字必须唯一 
2、默认以升序进行排列 
3、底层实现是红黑树--不支持进行数据修改,不支持下标访问
4.std::greater<int>,std::less<int>,自定义排序仿函数书写
5.insert成功返回true或者false,ret.second,pair的第二个参数

红黑树的五大特征:  
1、节点不是红色就是黑色 
2、根节点是黑色的 
3、叶子节点也是黑色的
4、如果一个节点是红色的,那么它的左右孩子节点必须是黑色的 
5、从根节点到叶子节点上所有路径要保证黑色节点的个数相同

3.multiset

1、可以存放关键字key相同的元素,关键字不唯一
2、默认以升序进行排列
3、底层实现是红黑树
4.与set的区别,insert进行插入数据肯定是成功的,没有返回值

4.map

1、存放的是键值对,也就是也个pair,即pair<const Key, value>,key值必须唯一,不能重复
2、默认按照关键字key进行升序排列
3、底层实现是红黑树

查找:
auto it = numbers.lower_bound(2);//>=key的第一个位置
auto it2 = numbers.upper_bound(2);//>key的第一个位置

5.mutilmap

1、可以存放关键字key相同的元素,关键字不唯一
2、默认以升序进行排列
3、底层实现是红黑树
4、与map的区别:关键字不唯一,进行插入的时候,肯定是成功的

6.insert参考接口

1.value_type,若是set/multiset代表的是key,
  若是map/multimap代表的是pair<const key, value>std::pair<iterator,bool> 

2.insert( const value_type& value ); //插入左值
std::pair<iterator,bool>
3.insert( value_type&& value );iterator//插入右值 
4.insert( iterator hint, const value_type& value );//获取某个位置的迭代器,往那个位置进行插入
5.iterator insert( const_iterator hint, const value_type& value );
6.iterator insert( const_iterator hint, value_type&& value );
7.template< class InputIt > void insert( InputIt first, InputIt last );
8.void insert( std::initializer_list<value_type> ilist );//插入列表
9.insert_return_type insert(node_type&& nh);
10.iterator insert(const_iterator hint, node_type&& nh);

set案例

1.set查找元素find,如果元素在set中存在,返回该元素的迭代器,否则返回 set.end()

2.set容器插入操作insert

        2.1 insert的返回结果是一对pair,first是当前插入值在set中的位置迭代器,second代表插入是否成功

        2.2 以列表的形式往set中插入数据:两种方式(迭代器范围和大列表方式)返回的都是void

3.set的删除erase: 1.按迭代器位置删除 2.按迭代器范围进行删除(左闭右开

                               3.返回值是被删除的最后一个元素对应的迭代器。

4.set不允许使用下标操作,为了保护红黑树的结构稳定,迭代器内容不允许修改,*it=20-->错误

#include <math.h>
#include <iostream>
#include <set>
#include <utility>
#include <string>
#include <vector>
#include <algorithm>
#include <iterator>

using std::ostream_iterator;
using std::cout;
using std::endl;
using std::set;
using std::pair;
using std::string;
using std::vector;

template <typename Container>
void display(const Container &con)
{
    for(auto &elem : con)
    {
        cout << elem << "  ";
    }
    cout << endl;
}
void test01()
{
    set<int> number = {1,3,5,7,9,11,13,7,8,10,1};
    display(number);//1  3  5  7  8  9  10  11  13

    cout<<"1.set查找元素find:"<<endl;

    auto it = number.find(3);//如果元素在set中存在,返回该元素的迭代器
    if(it == number.end())
    {
        cout<<"该元素不在set中"<<endl;
    }
    else
    {
        cout<<"该元素在set中"<<endl;
    }

    cout<<"2.set容器插入操作insert:"<<endl;
    //insert的返回结果是一对pair,first是当前插入值在set中的位置迭代器,第二个代表插入是否成功
    pair<set<int>::iterator, bool> ret = number.insert(2);
    if(ret.second == true)
    {
        cout<<"插入元素成功"<<*ret.first<<endl;
        cout<<ret.second<<endl;
    }
    else
    {
        cout<<"该元素在set中存在,插入失败"<<endl;
        cout<<*ret.first<<endl;//10
        cout<<ret.second<<endl;//0
        
    }
    //first是2在set中的对应的迭代器
    copy(ret.first,number.end(),ostream_iterator<int>(cout," "));
    //2 3 5 7 8 9 10 11 13
    cout<<endl;

    cout<<"3.以列表的形式往set中插入数据:两种方式返回的都是void"<<endl;
    cout<<"3.1迭代器形式插入:"<<endl;
    vector<int> vec = {10,20,30};
    number.insert(vec.begin(),vec.end());
    display(number);//1  2  3  5  7  8  9  10  11  13  20  30 

    cout<<"3.2大括号形式进行插入"<<endl;
    number.insert(std::initializer_list<int>({-9,100,200,300}));
    //display(number);
    copy(number.begin(),number.end(),ostream_iterator<int>(cout," "));//输出迭代器方式进行输出
    //-9 1 2 3 5 7 8 9 10 11 13 20 30 100 200 300
    cout<<endl;

    cout<<"4.set的删除erase:1.按迭代器位置删除 2.按范围进行删除:"<<endl;
    cout<<"4.1按迭代器位置进行删除"<<endl;
    it = number.begin();//-9
    it++;//1
    it++;//2,set里面的迭代器用的BidirectionalIterator双向迭代器,可进行++,--
    it++;//3
    it--;//2
    number.erase(it);//按迭代器位置删除,删除第二个迭代器,对应的值为2
    display(number);//-9  1  3  5  7  8  9  10  11  13  20  30  100  200  300 
    cout<<"4.2按照迭代器范围进行删除:左闭右开"<<endl;
    it=number.begin();
    for(int idx = 0;idx<5;idx++)
    {
        ++it;
    }
    cout<<*it<<endl;//8
    number.erase(number.begin(),it);//左闭右开
    display(number);//8  9  10  11  13  20  30  100  200  300
}

int main()
{
    test01();
    return 0;
}

/*
1  3  5  7  8  9  10  11  13  
1.set查找元素find:
该元素在set中
2.set容器插入操作insert:
插入元素成功2
1
2 3 5 7 8 9 10 11 13 
3.以列表的形式往set中插入数据:两种方式返回的都是void
3.1迭代器形式插入:
1  2  3  5  7  8  9  10  11  13  20  30  
3.2大括号形式进行插入
-9 1 2 3 5 7 8 9 10 11 13 20 30 100 200 300 
4.set的删除erase:1.按迭代器位置删除 2.按范围进行删除:
4.1按迭代器位置进行删除
-9  1  3  5  7  8  9  10  11  13  20  30  100  200  300  
4.2按照迭代器范围进行删除:
8
8  9  10  11  13  20  30  100  200  300  
*/

set容器实现自定义类型存储---重写Compare函数

自定义类型Point

class Point
{
public:
    Point(int ix=0,int iy=0)
        :_ix(ix),_iy(iy)
    {
    }

    float getDistance()const
    {
        return hypot(_ix,_iy);//两个数平方和再开方,求坐标距O的距离
    }

    ~Point()
    {

    }
    //重载左移运算符,直接实现打印对象
    friend std::ostream &operator<<(std::ostream &os,const Point &rhs);
    friend bool operator<(const Point &lhs,const Point &rhs);
    //friend bool operator>(const Point &lhs,const Point &rhs);
    friend struct CompareSet;//函数对象


private:
    int _ix;
    int _iy;
};

std::ostream& operator<<(std::ostream &os,const Point &rhs)
{
    os << "(" <<  rhs._ix
        << ", " << rhs._iy
        << ")";
    return os;
}
bool operator<(const Point &lhs,const Point &rhs)
{
    if(lhs.getDistance() < rhs.getDistance())
    {
        return true;
    }
    else if(lhs.getDistance() == rhs.getDistance())//相等的情况,需要分类讨论
    {
        if(lhs._ix < rhs._ix)
        {
            return true;
        }
        else if(lhs._ix == rhs._ix)
        {
            if(lhs._iy < rhs._iy)
            {
                return true;
            }
            else
            {
                return false;
            }
        }
        else
        {
            return false;
        }
    }
    else//lhs.getDistance() > rhs.getDistance()
    {
        return false;
    }
}

//函数对象
struct CompareSet
{
    bool operator()(const Point &lhs,const Point &rhs)const
    {

        if(lhs.getDistance() < rhs.getDistance())
        {
            return true;
        }
        else if(lhs.getDistance() == rhs.getDistance())//相等的情况,需要分类讨论
        {
            if(lhs._ix < rhs._ix)
            {
                return true;
            }
            else if(lhs._ix == rhs._ix)
            {
                if(lhs._iy < rhs._iy)
                {
                    return true;
                }
                else
                {
                    return false;
                }
            }
            else
            {
                return false;
            }
        }
        else//lhs.getDistance() > rhs.getDistance()
        {
            return false;
        }
    }
};
//对于自定义类型,set的使用
void test02()
{
    Point p1(3,4);
    cout<<p1.getDistance()<<endl;
    cout<<p1<<endl;
    set<Point,std::less<Point>> point={
        Point(1,2),
        Point(-1,-2),
        Point(3,2),
        Point(2,4),
        Point(3,5)
    } ;
    //   set<Point,CompareSet> point={
    //      Point(1,2),
    //      Point(-1,-2),
    //      Point(3,2),
    //      Point(2,4),
    //      Point(3,5)
    //  } ;

    display(point);
}
/*test02运行结果:
5
(3, 4)
(-1, -2)  (1, 2)  (3, 2)  (2, 4)  (3, 5)
    
*/

set容器存储自定义类型Person

class Person
{
public:
    Person(int num=0, string name="hello world")
        :_num(num),_name(name)
        {
        }
    friend bool operator<(const Person &lhs,const Person &rhs);
    friend std::ostream& operator<<(std::ostream &os,const Person &rhs);
    friend struct MyPersonSet;//函数对象形式
private:
    int _num;
    string _name;
};
bool operator<(const Person &lhs,const Person &rhs)
{
    if(lhs._num != rhs._num)
    {
        return lhs._num < rhs._num;
    }
    else
    {
        return lhs._name!=rhs._name;
    }
}

std::ostream& operator<<(std::ostream &os,const Person &rhs)
{
    os<<rhs._num<<":"<<rhs._name;
    return os;
}
struct MyPersonSet
{
    bool operator()(const Person &lhs, const Person &rhs)
    {

        if(lhs._num != rhs._num)
        {
            return lhs._num < rhs._num;
        }
        else
        {
            return lhs._name!=rhs._name;
        }
    }
};
//set自定义类型
void test03()
{
    set<Person,std::less<Person>> person = {//在自定义类Person里面重载<运算符
        Person(1,"孙悟空"),
        Person(2,"白龙马"),
        Person(3,"沙 僧"),
        Person(3,"唐 僧"),
        Person(6,"猪八戒"),
        Person(9,"白骨精"),
        Person(1,"孙悟空"),
        Person(9,"白骨精")
    };
    display(person);
}
/*
1:孙悟空  2:白龙马  3:唐 僧  3:沙 僧  6:猪八戒  9:白骨精
*/
//函数对象形式
void test04()
{
    set<Person,MyPersonSet> person = {
        Person(1,"孙悟空"),
        Person(2,"白龙马"),
        Person(3,"沙 僧"),
        Person(3,"唐 僧"),
        Person(6,"猪八戒"),
        Person(9,"白骨精"),
        Person(1,"孙悟空"),
        Person(9,"白骨精")
    };
    display(person);
}
/*
1:孙悟空  2:白龙马  3:唐 僧  3:沙 僧  6:猪八戒  9:白骨精
*/

map案例代码

1.map容器的操作和set大多相同

2.map允许用下标进行访问,如果被访问的key值不存在,会自动把key加入容器,有默认值

#include <iostream>
#include <math.h>
#include <iostream>
#include <map>
#include <utility>
#include <string>

using std::cout;
using std::endl;
using std::map;
using std::pair;
using std::string;

template <typename Container>
void display(const Container &con)
{
    for(auto &elem : con)
    {
        cout << elem.first << "  " << elem.second << endl;
    }
}
void test01()
{
    map<string, string> number={
        {"021", "北京"},
        {"027", "武汉"},
        {"0755", "深圳"},
        {"022", "天津"},
        pair<string, string>("0653", "北京"),
        pair<string, string>("021", "南京"),
        std::make_pair("0712", "广州"),
        std::make_pair("022", "广州")
    };
    
    cout<<"1.map的插入操作:"<<endl;
    auto ret = number.insert(pair<string,string>("999", "苏州"));
     if(ret.second)
    {
        cout << "该元素不在map中,插入成功 " 
             << ret.first->first << "  "
             << ret.first->second << endl;
    }
    else
    {
        cout << "该元素存在,map中, 插入失败" << endl;
    }
    
    display(number);
    
    cout<<"2.map的下标访问操作:"<<endl;
    cout << "number[\"1\"] = " << number["022"] << endl;
    cout << "number[\"10\"] = " << number["10"] << endl;
    display(number);

}
int main()
{
    test01();
    return 0;
}

猜你喜欢

转载自blog.csdn.net/weixin_49278191/article/details/121444239
今日推荐