您的位置:首页 > 理论基础 > 数据结构算法

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

2017-11-04 23:52 316 查看
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<
4000
/span>, 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.同样用代码来看效果.

内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  数据结构