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.同樣用程式碼來看效果.