map和set的使用以及模拟实现

本文详细介绍了STL中set和map容器的特性与接口使用方法,并通过代码示例展示了如何进行元素插入、查找和删除等操作。同时,还探讨了set与map底层实现原理,包括红黑树的数据结构。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

1,set
我们先来看看STL中set的接口有哪些
这里写图片描述
这里写图片描述

set的底层使用红黑树来实现,红黑树是一个不暴露给外界的数据结构,map和set都用它来实现,所以map和set是属于关联式容器。

set的特性:
所有的元素都会根据元素的键值自动排序,set的元素不像map那样可以同时拥有实值(value)和键值(key),set元素的键值就是实值,实值就是键值,set不允许两个元素有相同的键值。
我们不可以通过set的迭代器来改变set的元素值,因为其元素值就是键值,关系到set元素的排列规则。因此,在STL中set的迭代器底层是rb_tree的const_iterator.

以下是对set部分接口的使用:

#include<set>
#include<iostream>
using namespace std;

void Test()
{
    set<int> s;
    int a[10] = { 10, 9, 8, 5, 4, 2, 1, 3, 7, 6 };
    for (size_t i = 0; i < 10; i++)
    {
        s.insert(a[i]);
    }
    set<int>::iterator it1 = s.begin();
    while (it1 != s.end())
    {
        cout << *it1 << " ";
        ++it1;
    }
    cout << endl;
    cout << "Size = " << s.size() << endl;
    cout << "3 Count = " << s.count(3) << endl;
    s.insert(5);
    cout << "Size = " << s.size() << endl;
    s.insert(11);
    cout << "Size = " << s.size() << endl;
    set<int>::iterator it2 = s.begin();
    while (it2 != s.end())
    {
        cout << *it2 << " ";
        ++it2;
    }
    cout << endl;
    s.erase(2);
    set<int>::iterator it3 = s.begin();
    while (it3 != s.end())
    {
        cout << *it3<< " ";
        ++it3;
    }
    cout << endl;
}

这里写图片描述
由以上打印结果,我们可以看出,set中的insert使用的是rb_tree的insert_unique(),而不是insert_equal(),因为set不允许相同键值存在,multiset才允许相同键值存在。

2,map
先来看map的接口
这里写图片描述
这里写图片描述
font size=4 color=#8B008B>map的特性:

所有元素都会根据元素的键值自动被排序,map的所有元素都是pair,同时拥有实值(value)和键值(key)。pair的第一个元素被视为键值,第二个元素被视为实值。map不允许两个元素拥有相同的键值。
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)
    {}
};

为什么要有pair呢?
因为map是K,V模型,而一个函数不能有两个返回值,要返回两个值需要返回一个结构体,pair就是这个要返回的结构体。

map的键值(key)不能被修改,但实值(value)可以修改.
我们来简单使用以下map的部分接口:

void Test()
{
    map<string, int> p;
    p[string("liuyulin")] = 1;
    p[string("zhangyuhao")] = 2;
    p[string("cuicui")] = 3;
    p[string("yuxi")] = 4;

    pair<string, int> value(string("daiwei"), 5);
    p.insert(value);

    map<string, int>::iterator it = p.begin();
    while (it != p.end())
    {
        cout << it->first << ":" << it->second << endl;
        ++it;
    }

    int num = p[string("liuyulin")];
    cout << num << endl;

    map<string, int>::iterator it1;
    it1 = p.find(string("zhangyuhao"));
    if (it1 == p.end())
    {
        cout << "zahngyuhao found" << endl;
    }
    it1->second = 6;//可以修改second的值
    int num2 = p["zhangyuhao"];
    cout << num2 << endl;
}

这里写图片描述

map中的make_pair返回一个pair对象。

tempalate<class K,class V>
inline pair<k,v>make_pair(const K& key,const V& value)
{
return pair<k,v>(key,value);//类型推演
}

我们再来介绍map的operator[]:

typedef Key key_value;
typedef pair<const Key,T> value_type;
T& operator[](const key_type& k)
{
return (*((insert(value_type(k,T()))).first)).second;
}

首先,根据类型推演产生一个临时对象value_type(k,T())
再将该元素插入到map中

insert(value_type(k,T())

插入操作返回一个pair,其第一个元素是个迭代器,指向插入妥当的新元素,或指向插入失败点(键值重复)的旧元素。

insert(value_type(k,T()))).first

取迭代器中的第二个元素,是个bool值

(*((insert(value_type(k,T()))).first)).second;

关于map的一道面试题:
统计公司员工最喜欢吃的前K中水果

map<string,int>countMap;
string str[] = {"苹果","香蕉","橘子","苹果""橘子"};
for(size_t i = 0;i<sizeof(str)/sizof(str[0]);++i)
{
   map<string,int>::iterator it = countMap.find(str[i]);
  (1)if(it != countMap.end())//说明已经有这种水果了
  {
     it->second++;
  }
   else
  {
   (2)//countMap.insert(pair<string,int>(str[i],1));
    countMap.insert(make_pair(s[i],1);//make_pair是一个模板函数
  }
   (3)//countMap[str[i]]++;
}

下面我们来简单模拟map和set的部分接口的实现。
由于它们底层都是红黑树,所以我们对之前红黑树的代码做部分调整即可。需要清楚的是:set的value_type是K类型,而map的value_type是pair类型。

rb_tree.h

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

enum Colour
{
    RED,
    BLACK,
};

template<class ValueType>
struct RBTreeNode
{
    ValueType _valueField;

    RBTreeNode<ValueType>* _left;
    RBTreeNode<ValueType>* _right;
    RBTreeNode<ValueType>* _parent;

    Colour _col;

    RBTreeNode(const ValueType& v)
        :_valueField(v)
        , _left(NULL)
        , _right(NULL)
        , _parent(NULL)
        , _col(RED)
    {}
};

//map返回pair
//set返回K
template<class ValueType>
struct __TreeIterator
{
    typedef RBTreeNode<ValueType>Node;
    typedef __TreeIterator<ValueType> Self;
    Node* _node;

    __TreeIterator(Node* node)
        :_node(node)
    {}

    ValueType& operator*()
    {
        return _node->_valueField;
    }

    ValueType* operator->()
    {
        return &(_node->_valueField);
    }

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

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

    Self& operator++()//前置++
    {
        if (_node->_right)
        {
            Node* SubRight = _node->_right;
            while (SubRight->_left)
            {
                //访问右子树的最左节点
                SubRight = SubRight->_left;
            }
            _node = SubRight;
        }
        else
        {
            Node* cur = _node;
            Node* parent = cur->_parent;
            while(parent && cur == parent->_right)
            {
                cur = parent;
                parent = cur->_parent;
            }
            _node = parent;
        }
        return *this;
    }

    Self operator++(int)//后置++
    {
        Self tmp(*this);
        ++tmp;
        return *this;
    }

    Self& operator--()
    {
        if (_node->_left)
        {
            Node* Subleft = _node->_left;
            while (Subleft->_right)
            {
                //左子树的最右节点
                Subleft = Subleft->_right;
            }
            _node = Subleft;
        }
        else
        {
            Node* cur = _node;
            Node* parent = cur->_parent;
            while (parent && cur == parent->_left)
            {
                cur = parent;
                parent = cur->_parent;
            }
            _node = parent;
        }
        return *this;
    }

    Self operator--(int)
    {
        Self tmp(*this);
        --tmp;
        return *this;
    }

};


template<class K,class V,class KeyOfValue>
class RBTree
{
    typedef V ValueType;
    typedef RBTreeNode<ValueType> Node;
public:
    typedef __TreeIterator<ValueType> Iterator;
    RBTree()
        :_root(NULL)
    {}

    RBTree(const RBTree<K, V,KeyOfValue>& tree)
    {
        _Copy(tree._root);
    }


    ~RBTree()
    {
        _Destroy(_root);
    }

    RBTree<K, V,KeyOfValue>& operator = (const RBTree<K, V,KeyOfValue>& tree)
    {
        RBTree<K, V,KeyOfValue> tmp(tree);
        swap(_root, tree._root);
        return *this;
    }

    Iterator Begin()
    {
        Node* cur = _root;
        while (cur && cur->_left)
        {
            cur = cur->_left;
        }
        return cur;//单参数的构造函数允许隐式类型转换
    }

    Iterator End()
    {
        return NULL;
    }

    Iterator ReBegibn()
    {
        Node* cur = _root;
        while (cur->_right)
        {
            cur = cur->_right;
        }
        return cur;
    }

    Iterator ReEnd()
    {
        return NULL;
    }


    pair<Iterator,bool> Insert(const ValueType& v)
    {
        if (_root == NULL)
        {
            _root = new Node(v);
            _root->_col = BLACK;
            return make_pair(Iterator(_root),true);
        }

        KeyOfValue keyOfValue;
        Node* parent = NULL;
        Node* cur = _root;
        while (cur)
        {
            if (keyOfValue(cur->_valueField)  < keyOfValue(v))
            {
                parent = cur;
                cur = cur->_right;
            }
            else if (keyOfValue(cur->_valueField) > keyOfValue(v))
            {
                parent = cur;
                cur = cur->_left;
            }
            else
            {
                return make_pair(Iterator(cur),false);
            }
        }
        Node* newNode = cur;
        cur = new Node(v);
        if (keyOfValue(parent->_valueField) < keyOfValue(v))
        {
            parent->_right = cur;
            cur->_parent = parent;
        }
        else
        {
            parent->_left = cur;
            cur->_parent = parent;
        }

        while (parent && parent->_col == RED)
        {
            Node* grandfather = parent->_parent;
            if (parent == grandfather->_left)
            {
                Node* uncle = grandfather->_right;
                if (uncle && uncle->_col == RED)
                {
                    parent->_col = BLACK;
                    uncle->_col = BLACK;
                    grandfather->_col = RED;

                    cur = grandfather;
                    parent = cur->_parent;
                }
                else // u 不存在 u黑
                {
                    if (cur == parent->_right) // 双旋
                    {
                        RotateL(parent);
                        swap(cur, parent);
                    }

                    RotateR(grandfather);
                    parent->_col = BLACK;
                    grandfather->_col = RED;
                    break;
                }
            }
            //parent = grandfather->right
            else if (parent == grandfather->_right)
            {
                Node* uncle = grandfather->_left;
                if (uncle && uncle->_col == RED)
                {
                    parent->_col = BLACK;
                    uncle->_col = BLACK;
                    grandfather->_col = RED;

                    cur = grandfather;
                    parent = cur->_parent;
                }
                else
                {
                    if (cur == parent->_right)
                    {
                        RotateR(parent);
                        swap(parent, cur);
                    }
                    RotateL(grandfather);
                    parent->_col = BLACK;
                    grandfather->_col = RED;
                    break;
                }
            }
        }
        _root->_col = BLACK;
        return make_pair(Iterator(newNode),true);
    }

    void InOrder()
    {
        _InOrder(_root);
    }

protected:
    void _Copy(Node* root)
    {
        Node* newNode = NULL;
        Node* cur = root;
        while (cur)
        {
            newNode = new Node(cur->_key, cur->_value);
            newNode->_left = _Copy(cur->_left);
            newNode->_right = _Copy(cur->_right);
        }
    }

    void _Destroy(Node* root)
    {
        Node* cur = root;
        if (root == NULL)
            return;
        _Destroy(cur->_left);
        _Destroy(cur->_right);
        delete cur;
        cur = NULL;
    }

    Iterator Find(const K& key)
    {
        KeyOfValue keyOfValue;
        Node* cur = _root;
        while (cur)
        {
            if (keyOfValue(cur->_valueField) > key)
            {
                cur = cur->_left;
            }
            else if (keyOfValue(cur->_valueField) < key)
            {
                cur = cur->_right;
            }
            else
            {
                return cur;
            }
        }
        return Iterator(NULL);
    }

    //右旋
    void RotateR(Node* parent)
    {
        Node* subL = parent->_left;
        Node* subLR = subL->_right;
        parent->_left = subLR;
        if (subLR)
            subLR->_parent = parent;

        subL->_right = parent;
        Node* ppNode = parent->_parent;
        parent->_parent = subL;

        if (ppNode == NULL)
        {
            _root = subL;
            subL->_parent = NULL;
        }
        else
        {
            if (ppNode->_left == parent)
            {
                ppNode->_left = subL;
            }
            else
            {
                ppNode->_right = subL;
            }
            subL->_parent = ppNode;
        }
    }

    //左旋
    void RotateL(Node* parent)
    {
        Node* subR = parent->_right;
        Node* subRL = subR->_left;

        parent->_right = subRL;
        if (subRL)
            subRL->_parent = parent;

        subR->_left = parent;
        Node* ppNode = parent->_parent;
        parent->_parent = subR;

        if (ppNode == NULL)
        {
            _root = subR;
            subR->_parent = NULL;
        }
        else
        {
            if (ppNode->_left == parent)
            {
                ppNode->_left = subR;
            }
            else
            {
                ppNode->_right = subR;
            }
            subR->_parent = ppNode;
        }
    }

    void _InOrder(Node* root)
    {
        Node* cur = root;
        if (cur == NULL)
            return;
        _InOrder(cur->_left);
        cout << cur->_valueField<< " ";
        _InOrder(cur->_right);
    }
private:
    Node* _root;
};

myset.h

#pragma once
#include"rbtree.h"

template<class K>
class Set
{
public:
    struct KeyOfValue
    {
        const K& operator()(const K& k)
        {
            return k;
        }
    };

    //typename是告诉编译器在实例化的时候确定类型,延迟确认
    typedef typename RBTree<K, K,KeyOfValue>::Iterator Iterator;
    pair<Iterator, bool> InSert(const K& key)
    {
        return _tree.Insert(key);
    }

    Iterator Begin()
    {
        return _tree.Begin();
    }

    Iterator End()
    {
        return _tree.End();
    }

    Iterator ReBegin()
    {
        return _tree.ReBegibn();
    }

    Iterator ReEnd()
    {
        return _tree.ReEnd();
    }

    void InOrder()
    {
        _tree.InOrder();
    }
private:
    RBTree<K, K,KeyOfValue> _tree;
};

void TestSet()
{
    Set<int> s;
    s.InSert(10);
    s.InSert(15);
    s.InSert(12);
    s.InSert(11);
    s.InSert(13);
    s.InSert(14);
    s.InSert(16);

    Set<int>::Iterator it = s.Begin();
    while (it != s.End())
    {
        cout << *it << " ";
        ++it;
    }
    cout << endl;
}

这里写图片描述

mymap.h

#pragma once
#include"rbtree.h"
#include<string>

template<class K,class V>
class Map
{
public:
    typedef pair<K, V> ValueType;

    struct KeyOfValue
    {
        const K& operator()(const ValueType& kv)
        {
            return kv.first;
        }
    };

    typedef typename RBTree<K, ValueType, KeyOfValue>::Iterator Iterator;
    pair<Iterator, bool>InSert(const ValueType& v)
    {
        return _tree.Insert(v);
    }

    Iterator Begin()
    {
        return _tree.Begin();
    }

    Iterator End()
    {
        return _tree.End();
    }

    void InOrder()
    {
        _tree.InOrder();
    }
private:
    RBTree<K, ValueType,KeyOfValue>_tree;
};

void TestMap()
{
    Map<string, string> dict;
    dict.InSert(make_pair("sort", "排序"));
    dict.InSert(make_pair("insert", "插入"));
    dict.InSert(make_pair("left", "左边"));
    dict.InSert(make_pair("right", "右边"));
    Map<string, string>::Iterator it = dict.Begin();
    while (it != dict.End())
    {
        cout << it->first << ":" << it->second <<endl;
        ++it;
    }
    cout << endl;
}

这里写图片描述

multiset和multimap
multiset的特性以及用法和set完全相同,唯一的差别在于它允许键值重复,因此它的插入操作采用的底层机制是RB_Tree的insert_equal,而非insert_unique.

void TestSet()
{
    int a[] = { 1, 2, 2, 3, 4, 4 };
    set<int> s;
    for (size_t i = 0; i < sizeof(a) / sizeof(a[0]); ++i)
    {
        s.insert(a[i]);
    }
    set<int>::iterator it1 = s.begin();
    cout << "set:";
    while (it1 != s.end())
    {
        cout << *it1 << " ";
        ++it1;
    }
    cout << endl;

    multiset<int> ms;
    for (size_t i = 0; i < sizeof(a) / sizeof(a[0]); ++i)
    {
        ms.insert(a[i]);
    }
    multiset<int>::iterator it2 = ms.begin();
    cout << "multiset:";
    while (it2 != ms.end())
    {
        cout << *it2 << " ";
        ++it2;
    }
    cout << endl;
}

用上述代码对比二者的打印结果即可:
这里写图片描述

mutilmap的特性和用法和map也是完全相同,唯一的区别就在于它允许键值冗余,因此它的插入的底层机制采用RB_Tree的insert_equal.同样用代码来看效果.
这里写图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值