map 4个月前

编程语言
351
map

一、set

1.set简介和基本用法

set底层的实现就是红黑树

相较于算法中的 find O(N) set用AVL树实现的find可以达到 O(logN) 用红黑树实现的find可以达到O(2logN)

将数据放入set中后会自动去重排序

2.multiset

相较于set少了去重的部分,可以让数据重复

find,erase等成员删除的都是中序遍历中第一个成员

二、map

1.pair(键值对)

template<class T1, class T2>
struct pair
{
    typedef T1 first_type;
    typedef T2 second_type;

    T1 first;
    T2 second;

    pair()
        :first(T1()) //传入类型默认值构造
        ,second(T2())
    {}

    pair(const T1& a,const T2& b)
        :first(a)
        ,second(b)
    {}
};

2.插入

map<int, int> m;
    m.insert(pair<int, int>(1, 1)); //相当于传入pair临时构造的匿名对象
                                    //pair构造函数,构造一个匿名对象
    m.insert(make_pair(2, 2));      //函数 模板 构造一个pair对象
                                    //实际上更推荐用make_pair,不用声明模板参数,自动推断

map的插入返回值为

pair<iterator, bool> Insert(const T& data)
//当插入的数在map中没有时,则插入成功,返回插入val的迭代器(引用),和true
//当插入的数在map中已经有了,则插入失败,返回已经和val相同值的迭代器(引用),和false

作为其operator[]的底层

3.operator[]

map用来计数

map<string, int> countmap;
    string strs[] = { "iphone","iphone","huawei","honor","huawei","summim" };
    for (auto& e : strs)
    {
        map<string, int>::iterator ret = countmap.find(e);
        if (ret != countmap.end())
            //(*ret).second++;
            ret->second++;
        else
            countmap.insert(make_pair(e, 1));
    }

    for (auto& e : countmap)
    {
        cout << e.first << ":" << e.second << endl;
    }

也可以用operator[]更加便捷

map<string, int> countmap;
    string strs[] = { "iphone","iphone","huawei","honor","huawei","summim" };
    for (auto& e : strs)
    {
        //如果不在map中,则operator[]会插入pair<str,0> (0 == int() 即默认类型值)  返回映射对象(次数)的引用并且++
        //如果在map中    ,则operator[]返回key对应的映射对象(次数)的应用,对其++
        countmap[e]++;
    }

operator的底层可以看作为

mapped_type& operator[](const key_type& k)
        {
            return (*((this->insert (make_pair(k, mapped_type()) )).first)).second;
            //this->insert (make_pair(k, mapped_type()) 返回值为 pair<map<string,int>::iterator,bool>
            //.first                                    取 map<string,int>::iterator
            //*                                            取 pair<key_type,mapped_type>
            //.second                                    取 mapped_type 并返回其引用
            //返回引用的作用是,方便对其进行以后的操作
        }

所以operator有三种用途 1.插入 2.查找k对应的映射对象 3.修改k对应的映射对象的值

map<string, int> countmap;
    countmap["vivo"];     //插入
    countmap["vivo"] = 1; //修改
    cout << countmap["vivo"] << endl; //查找
    countmap["oppo"] = 2; //插入+修改

    map<string, string> dict;
    dict.insert(make_pair("string", "字符串"));
    dict["string"] = "字字符串";
    dict["sort"] = "排序";

4.multimap

multimap也是去掉了查重的功能,但没有 operator[] 当有多个相同的键值时,不知道返回哪一个对应的val

三、模拟实现set,map


底层都是由红黑树实现的,为了方便了解逻辑,删除了红黑树部分接口

#pragma once
#include<iostream>
using namespace std;

template <class T, class Ref, class Ptr>
struct __BRTreeIterator
{
    typedef BRTreeNode <T> Node;
    Node* _node;
    typedef __BRTreeIterator<T, Ref, Ptr> Self;
    typedef __BRTreeIterator<T, T&, T*> iterator;
    
    __BRTreeIterator(Node* node)
        :_node(node)
    {}

    //普通迭代器时,是拷贝构造
    //const迭代器,指出迭代器构造const迭代器
    __BRTreeIterator(const iterator& s)
        :_node(s._node)
    {}
    
    Ref operator*()
    {
        return _node->_data;
    }

    Ptr operator->()
    {
        return &_node->_data;
    }

    Self operator++()
    {
        if (_node->_right)
        {
            Node* min = _node->_right;
            while (min->_left)
            {
                min = min->_left;
            }
            _node = min;
        }
        else
        {
            Node* cur = _node;
            Node* parent = cur->_parent;
            while (parent && cur == parent->_right)
            {
                cur = parent;
                parent = parent->_parent;
            }
            _node = parent;
        }
        return *this;
    }

    Self operator--()
    {
        if (_node->_left)
        {
            Node* max = _node->_left;
            while (max->_right)
            {
                max = max->_right;
            }
            _node = max;
        }
        else
        {
            Node* cur = _node;
            Node* parent = cur->_parent;
            while (parent && cur == parent->_left)
            {
                cur = parent;
                parent = parent->_parent;
            }
            _node = parent;
        }
        return *this;
    }

    bool operator!=(const Self& s) const
    {
        return _node != s._node;
    }

    bool operator==(const Self& s) const
    {
        return _node == s._node;
    }
};


template<class K, class T, class KeyOfT>
class BRTree
{
public:
    typedef BRTreeNode<T> Node;
    typedef __BRTreeIterator<T, T&, T*> iterator;
    typedef __BRTreeIterator<T, const T&, const T*> const_iterator;

    iterator begin()
    {
        Node* left = _root;
        while (left && left->_left)
        {
            left = left->_left;
        }
        return iterator(left);
    }

    iterator end()
    {
        return iterator(nullptr);
    }

    const_iterator begin() const
    {
        Node* left = _root;
        while (left && left->_left)
        {
            left = left->_left;
        }
        return const_iterator(left);
    }

    const_iterator end() const
    {
        return const_iterator(nullptr);
    }

    pair<iterator, bool> Insert(const T& data)
    {
        if (_root == nullptr)
        {
            _root = new Node(data);
            _root->_col = Black;
            return make_pair(iterator(_root), true);
        }
        KeyOfT kot;
        //父子节点确定插入的位置
        Node* parent = nullptr;
        Node* cur = _root;
        while (cur)
        {
            if (kot(cur->_data) > kot(data))
            {
                parent = cur;
                cur = cur->_left;
            }
            else if (kot(cur->_data) < kot(data))
            {
                parent = cur;
                cur = cur->_right;
            }
            else
                return make_pair(iterator(cur), false);
        }

        //走到这cur就是要插入的位置
        //cur要连接parent,parent也要连接cur---判断靠kv的大小
        cur = new Node(data);
        Node* newnode = cur;
        if (kot(parent->_data) > kot(cur->_data))
        {
            parent->_left = cur;
            cur->_parent = parent;
        }
        else
        {
            parent->_right = cur;
            cur->_parent = parent;
        }

        while (parent && parent->_col == Red)
        {
            Node* grandparent = parent->_parent;
            //parent分在grandparent左右
            if (grandparent->_left == parent)
            {
                //关键是看uncle节点不存在/红色/黑色的情况
                Node* uncle = grandparent->_right;
                if (uncle && uncle->_col == Red)
                {
                    grandparent->_col = Red;
                    parent->_col = uncle->_col = Black;
                    .....
                    
        return make_pair(iterator(newnode), true);
    }

private:
    Node* _root = nullptr;
};

1.set

#include "RBTree.hpp"

namespace 9TSe
{
    template<class K>
    class Set
    {
    public:
        struct SetKeyOfT
        {
            const K& operator()(const K& k)
            {
                return k;
            }
        };
        typedef typename BRTree<K, K, SetKeyOfT>::const_iterator iterator;
        typedef typename BRTree<K, K, SetKeyOfT>::const_iterator const_iterator;

        pair<iterator, bool> Insert(const K& k)
        {
            return _t.Insert(k);
        }

        iterator begin()
        {
            return _t.begin();
        }

        iterator end()
        {
            return _t.end();
        }

        const_iterator begin() const
        {
            return _t.begin();
        }

        const_iterator end() const
        {
            return _t.end();
        }

    private:
        BRTree<K, K, SetKeyOfT> _t;
    };

set内数据本身是不能修改的 否则会破坏树的结构 所以迭代器都是由红黑树的const_iterator构成的

2.map

#include "RBTree.hpp"

namespace 9TSe
{
    template<class K, class V>
    class Map
    {
    public:
        struct MapKeyOfT
        {
            const K& operator()(const pair<K, V>& kv)
            {
                return kv.first;
            }
        };

        V& operator[](const K& k)
        {
            pair<iterator, bool> ret = Insert(make_pair(k, V()));
            return ret.first->second;
        }

        typedef typename BRTree<K, pair<const K, V>, MapKeyOfT>::iterator iterator;
        typedef typename BRTree<K, pair<const K, V>, MapKeyOfT>::const_iterator const_iterator;

        pair<iterator, bool> Insert(const pair<K, V>& kv)
        {
            return _t.Insert(kv);
        }

        const_iterator begin() const
        {
            return _t.begin();
        }

        const_iterator end() const
        {
            return _t.end();
        }

        iterator begin()
        {
            return _t.begin();
        }

        iterator end()
        {
            return _t.end();
        }

    private:
        BRTree<K, pair<const K, V>, MapKeyOfT> _t;
    };
image
EchoEcho官方
无论前方如何,请不要后悔与我相遇。
1377
发布数
439
关注者
2222943
累计阅读

热门教程文档

Spring Cloud
8小节
Next
43小节
MySQL
34小节
PHP
52小节
CSS
33小节