都知道set与map的底层是红黑树,但是有一个问题,set是普通的去重哈希,map是kv结构,数据类型怎么办?答案是泛型
编程,把这俩看作两个不同的数据类型用模板类实现
enum Color
{
RED,
BLACK
};
template<class T>
struct RBTreeNode
{
RBTreeNode<T>* _left;
RBTreeNode<T>* _right;
RBTreeNode<T>* _parent;
T _data;
Color _col;
RBTreeNode(const T& data)
: _left(nullptr)
, _right(nullptr)
, _parent(nullptr)
, _data(data)
, _col(RED)
{}
};
map由于也是kv,所以它的insert函数和红黑树是一样的
class map
{
protected:
typedef RBTreeNode<K, V> Node;
public:
bool Insert(pair<K, V>& kv)
{
if (_root == nullptr)
{
_root = new Node(val);
_root->_col = BLACK;//根肯定是黑色的
return true;
}
else
{
Node* cur = _root;
Node* parent = nullptr
while (cur)
{
parent = cur;
if (cur->_val > val)
cur = cur->left;
else if (cur->_val < val)
cur = cur->_right;
else
return false;
}
cur = new Node(val);
if (parent->_val.first > cur->_val.first)
{
parent->_left = cur;
}
else
{
parent->_parent = cur;
}
cur->_parent = parent;
///从此处开始进行插入后的调整
while (parent && parent->_col == RED)//出问题了
{
Node* grandparent = parent->_parent;
Node* uncle = nullptr;
if (grandparent->_left == parent)//找叔叔分情况
uncle = grandparent->_right;
else
uncle = grandparent->_left;
if (uncle && uncle->_col == RED)//叔叔是红色的,变色
{
parent->_col = BLACK;
uncle->_col = BLACK;
grandparent->_col = RED;
cur = grandparent;
parent = cur->_parent;
}
else if (grandparent->_left == parent)//叔叔是黑色或者不存在,且p是左侧路径,第二
{
if (parent->_left = cur)
{
RotateR(grandparent);
grandparent->_col = RED;
parent->_col = BLACK;
}
else//此时p是右侧路径是情况3
{
RotateL(parent);
RotateR(grandparent);
grandparent->_col = RED;
cur->_col = BLACK;
}
}
else//叔叔是黑色或者不存在,且p是右侧路径
{
if (parent->_right = cur)//情况4
{
RotateL(grandparent);
grandparent->_col = RED;
parent->_col = BLACK;
}
else//情况5
{
RotateR(parent);
RotateL(grandparent);
grandparent->_col = RED;
cur->_col = BLACK;
}
}
void RotateL(RBTNode * parent)//左旋
{
Node* grandparent = parent->_parent;
Node* ChildR = parent->_right;
if (grandparent)
{
if (grandparent->_left == parent)
grandparent->_left = ChildR;
else
grandparent->_right = ChildR;
}
else
_root = ChildR;
ChildR->_parent = grandparent;
parent->_right = ChildR->_left;
ChildR->_left->_parent = parent;
ChildR->_left = parent;
parent->_parent = ChildR;
}
void RotateR(RBTNode * parent)//右旋
{
Node* grandparent = parent->_parent;
Node* ChildL = parent->_left;
if (grandparent)
{
if (grandparent->_left == parent)
grandparent->_left = ChildL;
else
grandparent->_right = ChildL;
}
else
_root = ChildL;
ChildL->_parent = grandparent;
//两两一组进行改变
parent->_left = ChildL->_right;
ChildL->_right->_parent = parent;
ChildL->_right = parent;
parent->_parent = ChildL;//
}
}
}
}
protected:
Node* _root;
};
set改一下数据类型即可
但是问题来了,pair比较大小和key是不一样的,它先比first再比second,这就不一样了,所以我们要写一个仿函数(一个执行函数功能的类,重载())
template <class K>
class set
{
struct setkeyof
{
const K& operator(const K& key )
{
return key;
}
};
};
class map
{
protected:
typedef RBTreeNode<K, pair<K,V>,mapkeyof> Node;
public:
struct mapkeyof
{
const K& operator(const pair<K, V>key)
{
return key.first;
}
};
相应的红黑树的参数也要把仿函数传进去
普通迭代器
template<class T, class Ref, class Ptr>
struct RBTreeIterator
{
typedef RBTreeNode<T> Node;
typedef RBTreeIterator<T, T&, T*> Iterator;
typedef RBTreeIterator<T, Ref, Ptr> Self;
Node* _node;
RBTreeIterator(Node* node)
: _node(node)
{}
RBTreeIterator(const Iterator& it)
: _node(it._node)
{}
Ref operator*()
{
return _node->_data;
}
Ptr operator->()
{
return &(operator*());
}
bool operator!=(const Self& s)
{
return _node != s._node;
}
bool operator==(const Self& s)
{
return _node == s._node;
}
bool operator=(const Self& s)
{
return swap(_node->_data,s._node->_data);
}
};
迭代器分为两种,普通和const类型,所以它们的返回参数不能一样,为了它们俩可以调用同一个函数,将类模板的参数设置为3个,其中Ref代表const T&,Ptr代表const T*一个是不可修改即二叉搜索树的性质,一个是返回值不可修改即二叉树查找的性质
++运算符重载:右不为空找右子树最左节点,如果为空则一直向上找到根节点或者一个节点,这个节点是它父亲的左子树
Self& operator++()
{
if (_node->right)//右不为空,找右子树的最左结点
{
_node = _node->right;
while (_node->_left)
_node = _node->_left;
}
else//右为空,向上找孩子是父亲左的那个父亲
{
while (_node->_parent && _node->_parent->right == _node)
{
_node = _node->_parent;
}
}
return *this;
}
Self operator++(int)
{
Iterator news = this;
this++:
return *news;
}
前置返回加之后的引用,后置返回临时对象并给自身调用前置++
--运算符重载:和++相反即可
Self& operator--()//左不为空,找左子树的最右结点
{
if (_node->left)
{
_node=_node->_left
while (_node->_right)
_node = _node->right;
}
else//左为空,向上找孩子是父亲右的那个父亲
{
while (_node->_parent && node->_parent->_left == _node)
_node = _node->_parent;
_node = _node->parent;
}
}
Self& operator--(int)
{
Self tmp = *this;
--*this;
return tmp;
}
红黑树的整体修改
1.成员变量:直接给nullptr,不写构造函数
2.模板参数第一个为K代表参数类型
3.模板参数第二个T可以同时储存键值和键值对
4.模板参数KEYOFT为仿函数,用于获取值
template<class K, class T, class KeyOfT>
class RBTree
{
protected:
typedef RBTreeNode<T> Node;
public:
protected:
Node* _root = nullptr;
};
5.begin返回最左节点的迭代器,end返回空迭代器
typedef RBTreeIterator<T, T&, T*>iterator;
typedef RBTreeIterator<T, const T&, const T *>const_iterator;
iterator begin()
{
Node* cur = _root;
if (cur == nullptr)
return iterator(nullptr);
while (cur->_left)
cur = cur->_left
return iterator(cur);
}
const_iterator begin()const
{
Node* cur = _root;
if (cur == nullptr)
return const_iterator(nullptr);
while (cur->_left)
cur = cur->_left;
return const_iterator(cur);
}
iterator end()
{
return iterator(nullptr);
}
const_iterator end()const
{
return const_iterator(nullptr);
}
6.find返回迭代器,用KEYOFT作为比较媒介适配map和set
iterator Find(const K& key)
{
if (_root == nullptr)
{
return iterator(nullptr);
}
KeyOfT kot;
Node* cur = _root;
while (cur)
{
if (kot(cur->_data) < key)
{
cur = cur->_right;
}
else if (kot(cur->_data) > key)
{
cur = cur->_left;
}
else
{
return iterator(cur);
}
}
return iterator(nullptr);
}
7.insert返回pair,第一个返回迭代器,后一个返回bool值,用于记录是否插入成功,也要用KEYOFT来比较
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->_right;
}
else if (kot(cur->_data) > kot(data))
{
parent = cur;
cur = cur->_left;
}
else
{
return make_pair(iterator(cur), false);
}
}
Node* newnode = new Node(data);
cur = newnode;
if (kot(parent->_data) < kot(data))
{
parent->_right = cur;
}
else
{
parent->_left = cur;
}
cur->_parent = parent;
while (parent && parent->_col == RED)
{
Node* grandparent = parent->_parent;
if (grandparent->_right == parent)//uncle在左,parent在右
{
Node* uncle = grandparent->_left;
if (uncle && uncle->_col == RED)//uncle为红,变色+向上调整
{
parent->_col = uncle->_col = BLACK;
grandparent->_col = RED;
cur = grandparent;
parent = cur->_parent;
}
else//uncle为空或为黑,变色+旋转
{
if (parent->_right == cur)//左单旋
{
RotateL(grandparent);
parent->_col = BLACK;
grandparent->_col = RED;
}
else//右左旋
{
RotateR(parent);
RotateL(grandparent);
cur->_col = BLACK;
grandparent->_col = RED;
}
}
}
else//parent在左,uncle在右
{
Node* uncle = grandparent->_right;
if (uncle && uncle->_col == RED)
{
parent->_col = uncle->_col = BLACK;
grandparent->_col = RED;
cur = grandparent;
parent = cur->_parent;
}
else
{
if (parent->_left == cur)//右单旋
{
RotateR(grandparent);
parent->_col = BLACK;
grandparent->_col = RED;
}
else//左右旋
{
RotateL(parent);
RotateR(grandparent);
cur->_col = BLACK;
grandparent->_col = RED;
}
}
}
}
_root->_col = BLACK;
return make_pair(iterator(newnode), true);
}
set
KEYOFT直接返回key,且K和T是一样的
template<class K>
class set
{
struct SetKeyOfT
{
const K& operator()(const K& key)
{
return key;
}
};
public:
protected:
RBTree<K, K, SetKeyOfT> _t;
};
begin和end
set的key不允许修改,所以set的迭代器和const迭代器的底层都是红黑树的const迭代器
begin()返回的迭代器类型是const类型,但是红黑树里面的begin返回的是普通类型,所以要拷贝构造,进行类型转换
typedef RBTree<K,K,SetKeyOfT>::const_iterator iterator;
typedef RBTree<K, K, SetKeyOfT>::const_iterator const_iterator;
iterator begin()
{
return _t.begin();
}
const_iterator begin()const
{
return _t.begin();
}
iterator end()
{
return _t.end();
}
const_iterator end()const
{
return _t.end();
}
find
iterator find(const K& key)
{
return _t.Find(key);
}
insert
pair<iterator, bool> insert(const K& key)
{
return _t.Insert(key);
}
map
仿函数返回first,T的类型是pair
template<class K, class V>
class map
{
struct MapKeyOfT
{
const K& operator()(const pair<const K, V>& kv)
{
return kv.first;
}
};
public:
protected:
RBTree<K, pair<const K, V>, MapKeyOfT> _t;
};
begin和end
typedef RBTree<K, pair<const K,V>, MapKeyOfT>::const_iterator iterator;
typedef RBTree<K, pair<const K,V>, MapKeyOfT>::const_iterator const_iterator;
iterator begin()
{
return _t.begin();
}
const_iterator begin()const
{
return _t.begin();
}
iterator end()
{
return _t.end();
}
const_iterator end()const
{
return _t.end();
}
find
map不允许修改key,所以除了属于const迭代器以外要对key进行修饰
iterator find(const K& key)
{
return _t.Find(key);
}
insert
pair<iterator, bool> Insert(pair<const K, V>kv)
{
return _t.Insert(kv);
}
operator[]
返回值可以直接修改second
V& operator[](const K& key)
{
pair<const K, V> kv(key,V());
return _t.Insert(kv).first->second;
}