主に以下の2サイトを参考に、赤黒木を実装しています。
http://www.geocities.jp/h2fujimura/mutt ... -tree.html
http://www.ece.uc.edu/~franco/C321/html ... black.html
一応うまくいっていそうなのですが、
1.このコードは本当に正しいでしょうか?
2.どうやって検証するのがいいでしょうか?
よろしくお願いします。
► スポイラーを表示
rbt.h
rbt.cpp
#include <cstdio>
#ifndef RBT_H_GUARD
#define RBT_H_GUARD
struct RedBlackTreeNode {
int key;
bool isRed;
RedBlackTreeNode* left;
RedBlackTreeNode* right;
RedBlackTreeNode() {
key=0;isRed=true;left=right=NULL;
}
RedBlackTreeNode(int initKey) {
key=initKey;isRed=true;left=right=NULL;
}
~RedBlackTreeNode() {
if(left)delete left;
if(right)delete right;
}
};
class RedBlackTree {
private:
RedBlackTreeNode* root;
bool enableBalance;
void rotate(RedBlackTreeNode** target,bool isLeft);
int insertInternal(RedBlackTreeNode** now,int key);
bool searchInternal(const RedBlackTreeNode* now,int key) const;
RedBlackTreeNode* searchPtr(RedBlackTreeNode* now,int key);
RedBlackTreeNode* searchMinNode(RedBlackTreeNode* now);
int removeInternal(RedBlackTreeNode** now,RedBlackTreeNode* target);
int calcuateDepthInternal(const RedBlackTreeNode* now) const;
int countElementsInternal(const RedBlackTreeNode* now) const;
public:
RedBlackTree() {
root=NULL;
enableBalance=true;
}
~RedBlackTree() {
if(root)delete root;
}
void clear();
void insert(int key);
bool search(int key) const;
bool remove(int key);
int calcuateDepth() const;
int countElements() const;
const RedBlackTreeNode* getRoot() const {
return root;
}
void setEnableBalance(bool eb) {
enableBalance=eb;
}
bool getEnableBalance() const {
return enableBalance;
}
};
#endif
#include "rbt.h"
/*
全体の解説
http://www.geocities.jp/h2fujimura/mutter/tree/red-black-tree.html
デモと細かいこと
http://www.ece.uc.edu/~franco/C321/html/RedBlack/redblack.html
*/
const int RBT_REQUEST_NONE = 0;
const int RBT_REQUEST_INIT = 1;
const int RBT_REQUEST_NEXTOFLEFT = 2;
const int RBT_REQUEST_NEXTOFRIGHT = 3;
const int RBT_REQUEST_ROTATE_LEFT = 0x100;
const int RBT_REQUEST_ROTATE_RIGHT = 0x200;
const int RBT_REQUEST_DEL_INIT = 1;
void RedBlackTree::clear() {
if(root)delete root;
root=NULL;
}
void RedBlackTree::rotate(RedBlackTreeNode** target,bool isLeft) {
if(isLeft && (*target)->right!=NULL) {
RedBlackTreeNode* top=*target;
RedBlackTreeNode* topRight=(*target)->right;
RedBlackTreeNode* topRightLeft=(*target)->right->left;
(*target)->right->left=top;
(*target)->right=topRightLeft;
*target=topRight;
} else if((*target)->left!=NULL) {
RedBlackTreeNode* top=*target;
RedBlackTreeNode* topLeft=(*target)->left;
RedBlackTreeNode* topLeftRight=(*target)->left->right;
(*target)->left->right=top;
(*target)->left=topLeftRight;
*target=topLeft;
}
}
int RedBlackTree::insertInternal(RedBlackTreeNode** now,int key) {
int ret=RBT_REQUEST_NONE;
bool isLeft;
if(*now==NULL) {
*now=new RedBlackTreeNode(key);
if(enableBalance) {
return RBT_REQUEST_INIT;
} else {
(*now)->isRed=false;
return RBT_REQUEST_NONE;
}
} else if((*now)->key==key) {
return RBT_REQUEST_NONE;
} else if((*now)->key<key) {
ret=insertInternal(&((*now)->right),key);
isLeft=false;
} else { // key<(*now)->key
ret=insertInternal(&((*now)->left),key);
isLeft=true;
}
if(ret==RBT_REQUEST_INIT) {
//ケース1
if((*now)->isRed) {
ret=isLeft?RBT_REQUEST_NEXTOFLEFT:RBT_REQUEST_NEXTOFRIGHT;
} else {
ret=RBT_REQUEST_NONE;
}
} else if(ret==RBT_REQUEST_NEXTOFLEFT) {
if(isLeft) {
if((*now)->right==NULL || !(*now)->right->isRed) {
//ケース4
(*now)->isRed=true;
(*now)->left->isRed=false;
rotate(now,false);
ret=RBT_REQUEST_NONE;
} else {
//ケース2
(*now)->left->isRed=false;
if((*now)->right)(*now)->right->isRed=false;
(*now)->isRed=true;
ret=RBT_REQUEST_INIT;
}
} else {
if((*now)->left==NULL || !(*now)->left->isRed) {
//ケース3
rotate(&((*now)->right),false);
//ケース4
(*now)->isRed=true;
(*now)->right->isRed=false;
rotate(now,true);
ret=RBT_REQUEST_NONE;
} else {
//ケース2
(*now)->right->isRed=false;
if((*now)->left)(*now)->left->isRed=false;
(*now)->isRed=true;
ret=RBT_REQUEST_INIT;
}
}
} else if(ret==RBT_REQUEST_NEXTOFRIGHT) {
if(isLeft) {
if((*now)->right==NULL || !(*now)->right->isRed) {
//ケース3
rotate(&((*now)->left),true);
//ケース4
(*now)->isRed=true;
(*now)->left->isRed=false;
rotate(now,false);
ret=RBT_REQUEST_NONE;
} else {
//ケース2
(*now)->left->isRed=false;
if((*now)->right)(*now)->right->isRed=false;
(*now)->isRed=true;
ret=RBT_REQUEST_INIT;
}
} else {
if((*now)->left==NULL || !(*now)->left->isRed) {
//ケース4
(*now)->isRed=true;
(*now)->right->isRed=false;
rotate(now,true);
ret=RBT_REQUEST_NONE;
} else {
//ケース2
(*now)->right->isRed=false;
if((*now)->left)(*now)->left->isRed=false;
(*now)->isRed=true;
ret=RBT_REQUEST_INIT;
}
}
}
return ret;
}
void RedBlackTree::insert(int key) {
insertInternal(&root,key);
root->isRed=false;
}
bool RedBlackTree::searchInternal(const RedBlackTreeNode* now,int key) const {
if(now==NULL)return false;
if(now->key==key)return true;
return now->key<key?
searchInternal(now->right,key):
searchInternal(now->left,key);
}
bool RedBlackTree::search(int key) const {
return searchInternal(root,key);
}
RedBlackTreeNode* RedBlackTree::searchPtr(RedBlackTreeNode* now,int key) {
if(now==NULL)return NULL;
if(now->key==key)return now;
return searchPtr(now->key<key?now->right:now->left,key);
}
RedBlackTreeNode* RedBlackTree::searchMinNode(RedBlackTreeNode* now) {
if(now->left==NULL)return now;
return searchMinNode(now->left);
}
int RedBlackTree::removeInternal(RedBlackTreeNode** now,RedBlackTreeNode* target) {
int ret=RBT_REQUEST_NONE;
bool isLeft=false;
if(*now==NULL)return RBT_REQUEST_NONE;
if(*now==target) {
RedBlackTreeNode* delNode=*now;
bool delNodeIsRed=delNode->isRed;
*now=(*now)->left?(*now)->left:(*now)->right;
delNode->left=delNode->right=NULL;
delete delNode;
//ケース0
if(delNodeIsRed) {
return RBT_REQUEST_NONE;
} else if(*now && (*now)->isRed) {
(*now)->isRed=false;
return RBT_REQUEST_NONE;
}
return enableBalance?RBT_REQUEST_DEL_INIT:RBT_REQUEST_NONE;
} else if((*now)->key<=target->key) {
ret=removeInternal(&((*now)->right),target);
isLeft=false;
} else {
ret=removeInternal(&((*now)->left),target);
isLeft=true;
}
if(ret==RBT_REQUEST_DEL_INIT) {
if(isLeft) {
if((*now)->right!=NULL && (*now)->right->isRed) {
//ケース2
(*now)->isRed=!(*now)->isRed;
(*now)->right->isRed=!(*now)->right->isRed;
rotate(now,true);
now=&((*now)->left);
}
ret=RBT_REQUEST_NONE;
if((*now)->right!=NULL) {
if(((*now)->right->left==NULL ||
!((*now)->right->left->isRed)) &&
((*now)->right->right==NULL ||
!((*now)->right->right->isRed))) {
if((*now)->isRed) {
//ケース4
(*now)->isRed=false;
(*now)->right->isRed=true;
} else {
//ケース3
(*now)->right->isRed=true;
ret=RBT_REQUEST_INIT;
}
} else if((*now)->right->right!=NULL &&
(*now)->right->right->isRed) {
//ケース6
bool colorTemp=(*now)->isRed;
(*now)->isRed=(*now)->right->isRed;
(*now)->right->isRed=colorTemp;
(*now)->right->right->isRed=false;
rotate(now,true);
} else {
//ケース5
(*now)->right->isRed=true;
(*now)->right->left->isRed=false;
rotate(&((*now)->right),false);
//ケース6
bool colorTemp=(*now)->isRed;
(*now)->isRed=(*now)->right->isRed;
(*now)->right->isRed=colorTemp;
(*now)->right->right->isRed=false;
rotate(now,true);
}
}
} else {
if((*now)->left!=NULL && (*now)->left->isRed) {
//ケース2
(*now)->isRed=!(*now)->isRed;
(*now)->left->isRed=!(*now)->left->isRed;
rotate(now,false);
now=&((*now)->right);
}
ret=RBT_REQUEST_NONE;
if((*now)->left!=NULL) {
if(((*now)->left->left==NULL ||
!((*now)->left->left->isRed)) &&
((*now)->left->right==NULL ||
!((*now)->left->right->isRed))) {
if((*now)->isRed) {
//ケース4
(*now)->isRed=false;
(*now)->left->isRed=true;
} else {
//ケース3
(*now)->left->isRed=true;
ret=RBT_REQUEST_INIT;
}
} else if((*now)->left->left!=NULL &&
(*now)->left->left->isRed) {
//ケース6
bool colorTemp=(*now)->isRed;
(*now)->isRed=(*now)->left->isRed;
(*now)->left->isRed=colorTemp;
(*now)->left->left->isRed=false;
rotate(now,false);
} else {
//ケース5
(*now)->left->isRed=true;
(*now)->left->right->isRed=false;
rotate(&((*now)->left),true);
//ケース6
bool colorTemp=(*now)->isRed;
(*now)->isRed=(*now)->left->isRed;
(*now)->left->isRed=colorTemp;
(*now)->left->left->isRed=false;
rotate(now,false);
}
}
}
}
return ret;
}
bool RedBlackTree::remove(int key) {
RedBlackTreeNode* target;
target=searchPtr(root,key);
if(target==NULL)return false;
if(target->left!=NULL && target->right!=NULL) {
RedBlackTreeNode* minNode;
minNode=searchMinNode(target->right);
target->key=minNode->key;
target=minNode;
}
removeInternal(&root,target);
return true;
}
int RedBlackTree::calcuateDepthInternal(const RedBlackTreeNode* now) const {
int depth1,depth2;
if(now==NULL)return 0;
depth1=calcuateDepthInternal(now->left);
depth2=calcuateDepthInternal(now->right);
return ((depth1>depth2)?depth1:depth2)+1;
}
int RedBlackTree::calcuateDepth() const {
return calcuateDepthInternal(root);
}
int RedBlackTree::countElementsInternal(const RedBlackTreeNode* now) const {
if(now==NULL)return 0;
return countElementsInternal(now->left)+countElementsInternal(now->right)+1;
}
int RedBlackTree::countElements() const {
return countElementsInternal(root);
}