这次总结如何使用自己写的迭代器实现红黑树
一.什么是迭代器?
迭代器是连接容器和算法的纽带,为数据提供了抽象,使写算法的人不必关心各种数据结构的细节。迭代器提供了数据访问的标准模型——对象序列,使对容器更广泛的访问操作成为可能。
泛型编程的关键所在,就是如何找到一种通用的方法,来访问具有不同结构的各种容器中的每个元素,而这正是迭代器的功能。
迭代器是一种广义的指针,是指向序列元素指针概念的一种抽象。迭代器可以指向容器中的任意元素,还能遍历整个容器。
每种容器类型都定义了自己的C++迭代器类型,如vector:vector<int>::iterator iter;这符语句定义了一个名为 iter的变量,它的数据类型是 vector<int>定义的 iterator类型。每个标准库容器类型都定义了一个名为 iterator的成员,这里的 iterator与迭代器实际类型的含义相同。
二.迭代器的基本操作?
读——通过解除引用*来间接引用容器中的元素值,例如x = *p;
写——通过解除引用*来给容器中的元素赋值,例如*p= x;
访问——通过下标和指向引用容器中的元素及其成员,例如p[2]和p->m
迭代——利用增量和减量运算(++和--、+和-、+=和-=)在容器中遍历、漫游和跳跃,例如p++、--p、p+5、p-=8
比较——利用比较运算符(==、!=、<、>、<=、>=)来比较两个迭代器是否相等或谁大谁小,例如if(p < q)……;、wihle(p != c.end())……;
三.什么是红黑树?及如何实现
请参考我上一篇博客:
http://blog.youkuaiyun.com/sayhello_world/article/details/71550605
四.迭代器实现红黑树(这里在头节点前加一个结构体左begin指向最小的右end指向)
迭代器应该有的操作:
1. *
2. –>
3. 前置++ && 后置++
4. 前置-- && 后置—
5. != && ==
这里主要说++ 与 -- 操作
思路:红黑树自增遍历,按照中序遍历结果,左中右。
先找到最左边的结点,看此结点是否有右结点。
如果有右结点,则此结点下一个应该为右结点子树中最小的结点(右子树最左边的结点)。
如果没有右结点,则此结点应该逐层向上走。
代码实现:
//指针自增操作(按照中序遍历的结果输出)
//如图1所示
voidIncrement()
{
//如果此结点的右子树存在则应该找右子树最小的结点也就为右子树最左边的结点
if(_pNode->_pRight)
{
_pNode= _pNode->_pRight;
while(_pNode->_pLeft)
_pNode= _pNode->_pLeft;
}
//若不存在
//若此结点为父亲结点的右结点则应该一直向上找(因为上面的都比下面的小不为++的结果)
//否则为左节点时此时的父亲结点比pNode大此时父亲结点就为++的下一个节点
else
{
Node* pParent = _pNode->_pParent;
while(pParent->_pRight== _pNode)
{
_pNode= pParent;
pParent= pParent->_pParent;
}
//这里要特殊处理因为如果此时是跟跟的右子树不存在则应该再加就赋给跟的parent
if(pParent->_pRight!= _pNode)
_pNode= pParent;
}
}
思路:自减操作
从end开始自减,因为自减最后会减到跟(就是起始的结点 左为begin右为end),所以先判断此结点是否是跟。
如果是跟的话,再减就为最大的结点。
如果不是跟,判断此结点是否有左子树,如果有左子树,则应该找左子树中最大的结点为减减后的结点。
否则,不是跟也没有左子树,那就在右子树中逐层向上找。
代码实现:
void Decrement()
{
//如果是end()为起始结点的话起始结点自减就应该为根节点右子树的第一个结点
if(_pNode->_color== RED && _pNode->_pParent->_pParent== _pNode)
_pNode= _pNode->_pRight;
//否则此结点存在左子树就应该找左子树最右边的结点找左子树最大的结点
elseif(_pNode->_pLeft)
{
_pNode= _pNode->_pLeft;
while(_pNode->_pRight)
_pNode= _pNode->_pRight;
}
//否则不是根结点也没有左子树如图4 就应该找此子树的根节点
else
{
Node* pParent = _pNode->_pParent;
while(pParent->_pLeft== _pNode)
{
_pNode= pParent;
pParent= pParent->_pParent;
}
//此时就不用再判断如上加加的条件了因为走到这一步pParent一定是减减后最小的
_pNode= pParent;
}
}
代码下载:
github:
https://github.com/Noctis-xjw/Code-Cpp/blob/master/IteratorRBTree.h
有兴趣的点一个star
总代码:
#pragma once
#include <iostream>
using namespacestd;
enum Color
{
RED,
BLACK
};
template<classK, class V>
struct RBTreeNode
{
public:
RBTreeNode(const V&value, constK& key)
:_value(value)
, _key(value)
, _pLeft(NULL)
, _pRight(NULL)
, _pParent(NULL)
, _color(RED)
{}
V _value;
K _key;
RBTreeNode<K, V>* _pLeft;
RBTreeNode<K, V>* _pRight;
RBTreeNode<K, V>* _pParent;
Color _color;
};
template<classK,class V,class Ref,class Ptr>
class Iterator
{
typedefIterator<K, V, Ref, Ptr> Self;
typedefRBTreeNode<K, V> Node;
public:
Iterator()
:_pNode(NULL)
{}
Iterator(const Self& it)
:_pNode(it._pNode)
{}
Iterator(Node* node)
:_pNode(node)
{}
Ref operator*()
{
return_pNode->_key;
}
Ptr operator->()
{
return&(operator*());
}
//前置++
Self& operator++()
{
Increment();
return*this;
}
//后置++
Self operator++(int)
{
Self temp(*this);
Increment();
returntemp;
}
//前置--
Self& operator--()
{
Decrement();
return*this;
}
//后置--
Self operator--(int)
{
Self temp(*this);
Decrement();
returntemp;
}
booloperator!=(const Self&sf)
{
return_pNode!= sf._pNode;
}
booloperator==(const Self&sf)
{
return_pNode== sf._pNode;
}
protected:
//指针自增操作(按照中序遍历的结果输出)
//如图1所示
voidIncrement()
{
//如果此结点的右子树存在则应该找右子树最小的结点也就为右子树最左边的结点
if(_pNode->_pRight)
{
_pNode= _pNode->_pRight;
while(_pNode->_pLeft)
_pNode= _pNode->_pLeft;
}
//若不存在
//若此结点为父亲结点的右结点则应该一直向上找(因为上面的都比下面的小不为++的结果)
//否则为左节点时此时的父亲结点比pNode大此时父亲结点就为++的下一个节点
else
{
Node* pParent = _pNode->_pParent;
while(pParent->_pRight== _pNode)
{
_pNode= pParent;
pParent= pParent->_pParent;
}
//这里要特殊处理因为如果此时是跟跟的右子树不存在则应该再加就赋给跟的parent如图3
if(pParent->_pRight!= _pNode)
_pNode= pParent;
}
}
voidDecrement()
{
//如果是end()为起始结点的话起始结点自减就应该为根节点右子树的第一个结点
if(_pNode->_color== RED && _pNode->_pParent->_pParent== _pNode)
_pNode= _pNode->_pRight;
//否则此结点存在左子树就应该找左子树最右边的结点找左子树最大的结点
elseif(_pNode->_pLeft)
{
_pNode= _pNode->_pLeft;
while(_pNode->_pRight)
_pNode= _pNode->_pRight;
}
//否则不是根结点也没有左子树如图4 就应该找此子树的根节点
else
{
Node* pParent = _pNode->_pParent;
while(pParent->_pLeft== _pNode)
{
_pNode= pParent;
pParent= pParent->_pParent;
}
//此时就不用再判断如上加加的条件了因为走到这一步pParent一定是减减后最小的
_pNode= pParent;
}
}
private:
Node* _pNode;
};
template < classK, class V>
class RBTree
{
typedefIterator<K, V, K&, V*> Iterator;
typedefRBTreeNode<K, V> Node;
public:
RBTree()
{
_pHead= new Node(K(),V());
_pHead->_color= RED;
_pHead->_pLeft= _pHead;
_pHead->_pRight= _pHead;
_pHead->_pParent= NULL;
}
boolInsert(const K& key, constV& value)
{
//判断根节点是否为空
Node* _pRoot = GetRoot();
if(NULL == _pRoot)
{
_pRoot= new Node(key,value);
_pRoot->_pParent= _pHead;
_pHead->_pParent= _pRoot;
_pRoot->_color= BLACK;
returntrue;
}
Node* pCur = _pRoot;
Node* pParent = NULL;
//找插入位置
while(pCur)
{
if(key > pCur->_key)
{
pParent= pCur;
pCur= pCur->_pRight;
}
elseif(key < pCur->_key)
{
pParent= pCur;
pCur= pCur->_pLeft;
}
else
returnfalse;
}
//插入结点
pCur= new Node(key,value);
if(key < pParent->_key)
pParent->_pLeft= pCur;
elseif(key > pParent->_key)
pParent->_pRight= pCur;
pCur->_pParent= pParent;
//对结点的颜色进行处理
//从下往上修改颜色到根节点且根节点为红结束
while(_pRoot != pCur&& pParent->_color== RED)
{
Node* grandFather = pParent->_pParent;
if(pParent == grandFather->_pLeft)
{
Node* uncle = grandFather->_pRight;
//当前插得为红,双亲为红,叔叔也为红
//此时应该把祖先变为红,把双亲叔叔变为黑
if(uncle && uncle->_color== RED)
{
grandFather->_color= RED;
pParent->_color= BLACK;
uncle->_color= BLACK;
pCur= grandFather;
pParent= pCur->_pParent;
}
//否则叔叔不存在或者叔叔为黑
else
{
//如果cur在父母的右边则左单旋再右单旋
if(pParent->_pRight== pCur)
{
RotateLeft(pParent);
std::swap(pParent,pCur);
}
//否则只右单旋
pParent->_color= BLACK;
grandFather->_color= RED;
RotateRight(grandFather);
break;
}
}
//否则父母结点在祖先节点的右边
else
{
Node* uncle = grandFather->_pLeft;
if(uncle && uncle->_color== RED)
{
pParent->_color= BLACK;
uncle->_color= BLACK;
grandFather->_color= RED;
pCur= grandFather;
pParent= pCur->_pParent;
}
else
{
if(pCur == pParent->_pLeft)
{
RotateRight(pParent);
std::swap(pParent,pCur);
}
grandFather->_color= RED;
pParent->_color= BLACK;
RotateLeft(grandFather);
break;
}
}
}
//旋转后要把根节点重新获取一下
_pRoot= GetRoot();
//最后要把根节点换成黑色的
_pRoot->_color= BLACK;
_pHead->_pLeft= GetMin();
_pHead->_pRight= GetMax();
returntrue;
}
boolCheckRBTree()
{
Node* _pRoot = GetRoot();
if(_pRoot == NULL)
returntrue;
if(_pRoot->_color== RED)
{
cout<< "根为红色不满足" << endl;
returnfalse;
}
//计算黑色结点的个数应该每一条路径上数目都相同
intBlackCount= 0;
Node* pCur = _pRoot;
//只走最左边的那一条路
while(pCur)
{
if(pCur->_color== BLACK)
BlackCount++;
pCur= pCur->_pLeft;
}
intk= 0;
return_CheckRBTree(_pRoot, BlackCount,k);
}
bool_CheckRBTree(Node* pRoot,constsize_t blackCount, size_t k)
{
if(pRoot == NULL)
returntrue;
//如果两个连续的红色就违反规则
Node* Parent = pRoot->_pParent;
if(Parent && Parent->_color== RED && pRoot->_color== RED)
{
cout<< "两个红色不能相连接" << endl;
returnfalse;
}
//判断是否k=blackCount
//如果此时为黑色结点 k要++
if(pRoot->_color== BLACK)
k++;
if(pRoot->_pLeft== NULL && pRoot->_pRight== NULL)
{
if(k != blackCount)
{
cout<< "违反两个黑色结点相同原则" << endl;
returnfalse;
}
}
return_CheckRBTree(pRoot->_pLeft,blackCount,k)&& _CheckRBTree(pRoot->_pRight,blackCount,k);
}
voidInOrder()
{
cout<< "中序遍历:";
Node* _pRoot = GetRoot();
_InOrder(_pRoot);
}
Iterator Begin()
{
returnIterator(_pHead->_pLeft);
}
Iterator End()
{
returnIterator(_pHead);
}
private:
//获取根
Node*& GetRoot()
{
return_pHead->_pParent;
}
Node* GetMin()
{
Node* pRoot = _pHead->_pParent;
while(pRoot->_pLeft)
{
pRoot= pRoot->_pLeft;
}
returnpRoot;
}
Node* GetMax()
{
Node* pRoot = _pHead->_pParent;
while(pRoot->_pRight)
{
pRoot= pRoot->_pRight;
}
returnpRoot;
}
void_InOrder(Node* pRoot)
{
if(pRoot == NULL)
return;
_InOrder(pRoot->_pLeft);
cout<< pRoot->_key<< " ";
_InOrder(pRoot->_pRight);
}
voidRotateLeft(Node*& pRoot)
{
Node* SubR = pRoot->_pRight;
Node* SubRL = SubR->_pLeft;
pRoot->_pRight= SubRL;
if(SubRL)
SubRL->_pParent= pRoot;
SubR->_pLeft= pRoot;
SubR->_pParent= pRoot->_pParent;
pRoot->_pParent= SubR;
pRoot= SubR;
if(pRoot->_pParent== _pHead)
_pHead->_pParent= pRoot;
else
{
if(pRoot->_pParent->_key> pRoot->_key)
pRoot->_pParent->_pLeft= pRoot;
else
pRoot->_pParent->_pRight= pRoot;
}
}
voidRotateRight(Node*& pRoot)
{
Node* SubL = pRoot->_pLeft;
Node* SubLR = SubL->_pRight;
pRoot->_pLeft= SubLR;
if(SubLR)
SubLR->_pParent= pRoot;
SubL->_pRight= pRoot;
SubL->_pParent= pRoot->_pParent;
pRoot->_pParent= SubL;
pRoot= SubL;
if(pRoot->_pParent== _pHead)
_pHead->_pParent= pRoot;
else{
if(pRoot->_pParent->_key> pRoot->_key)
pRoot->_pParent->_pLeft= pRoot;
else
pRoot->_pParent->_pRight= pRoot;
}
}
private:
Node* _pHead;
//int_Size;
};