1. 程式人生 > >map和set的使用以及模擬實現

map和set的使用以及模擬實現

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.同樣用程式碼來看效果.
這裡寫圖片描述