研究了几天终于写了自己的红黑树,主要参考 http://eternallyconfuzzled.com/tuts/datastructures/jsw_tut_rbtree.aspx Thank you, Julienne.
感谢 Julienne Walker 风趣加通俗易懂的语言描述红黑树,害我有了翻译这文章的冲动 ^-^
这玩意儿只在vs上测试过,g++要通过应该也是一下的事,没windows的库
all rights unreserved, enjoy
rbtree.h
//==============================================================
/*
author: lj
date: 2013.9.10
usage: rbtree* tree = rbtree::create(dup, del);
tree->insert(...);
......
void* elem = tree->search(...);
......
tree->remove(...);
......
...
rbtree::release(tree);
*/
//==============================================================
#ifndef _RED_BLACK_TREE_H_
#define _RED_BLACK_TREE_H_
// @ duplicating function for element
typedef void* (*func_dup)(void* elem);
// @ deleting function for element
typedef void (*func_del)(void* elem);
// @ it could be just a struct
class rbnode
{
friend class rbtree;
public:
static rbnode* create(int key, void* elem);
void release();
private:
rbnode(void);
~rbnode(void);
private:
int key;
void* elem;
bool red;
// @ link[0] for the left child, link[1] for the right one
rbnode* link[2];
};
class rbtree
{
public:
rbtree(void);
~rbtree(void);
// @ define the function for duplication and deletion
static rbtree* create(func_dup dup, func_del del);
inline void setFunc(func_dup dup, func_del del);
// @ destroy all nodes, loop left-rotate to make it a linked list
void destroy();
static void release(rbtree* tree);
void insert(int key, void* elem);
void remove(int key);
void* search(int key);
int size();
// @ print the whole tree, horizontally
void print();
private:
// @ helper functions
rbnode* make_node(int key, void* elem);
bool is_red(rbnode* node);
// @ single rotation
rbnode* rotate(rbnode* root, int direction);
// @ double rotation
rbnode* drotate(rbnode* root, int direction);
// @ search recursively, works with search()
rbnode* search_r(rbnode* root, int key);
// @ insert recursively, works with insert()
rbnode* insert_r(rbnode* root, int key, void* elem);
rbnode* insert_rebalance(rbnode* root, int directoin);
// @ remove recursively, works with remove()
rbnode* remove_r(rbnode* root, int key);
rbnode* remove_rebalance(rbnode* root, int direction);
// @ print recursively, works with print()
void print_r(rbnode* root, int level);
func_dup _dup;
func_del _del;
private:
rbnode* m_root;
int m_nSize;
bool m_bDone;
bool m_bFliped;
};
#endif // _RED_BLACK_TREE_H_
#include "rbtree.h"
#include <stdio.h>
//=====================================================
// @ rbnode
//=====================================================
rbnode::rbnode(void)
{
}
rbnode::~rbnode(void)
{
}
rbnode* rbnode::create(int key, void* elem)
{
rbnode* pRet = new rbnode();
if(pRet)
{
pRet->key = key;
pRet->elem = elem;
pRet->red = true;
pRet->link[0] = NULL;
pRet->link[1] = NULL;
}
return pRet;
}
//=====================================================
// @ rbtree
//=====================================================
rbtree::rbtree(void):
m_root(NULL),
m_nSize(0),
m_bDone(false),
m_bFliped(false)
{
}
rbtree::~rbtree(void)
{
}
rbtree* rbtree::create(func_dup dup, func_del del)
{
rbtree* pRet = new rbtree();
if(pRet)
{
pRet->setFunc(dup, del);
}
return pRet;
}
void rbtree::setFunc(func_dup dup, func_del del)
{
this->_dup = dup;
this->_del = del;
}
void rbtree::destroy()
{
rbnode* it = m_root;
while(it)
{
rbnode* temp;
// @ if there is left child, left rotate
if(it->link[0])
{
temp = it->link[0];
it->link[0] = temp->link[1];
temp->link[1] = it;
}
// @ delete node and its element
else
{
temp = it->link[1];
this->_del(it->elem);
delete it;
}
it = temp;
}
m_root = NULL;
m_nSize = 0;
}
int rbtree::size()
{
return m_nSize;
}
void rbtree::release(rbtree* tree)
{
if(tree)
{
tree->destroy();
delete tree;
tree = NULL;
}
}
bool rbtree::is_red(rbnode* node)
{
return (node != NULL && node->red);
}
rbnode* rbtree::rotate(rbnode* root, int direction)
{
rbnode* temp = root->link[!direction];
root->link[!direction] = temp->link[direction];
temp->link[direction] = root;
// @ old root set red, new root set black
root->red = 1;
temp->red = 0;
return temp;
}
rbnode* rbtree::drotate(rbnode* root, int direction)
{
root->link[!direction] = rotate(root->link[!direction], !direction);
return rotate(root, direction);
}
rbnode* rbtree::make_node(int key, void* elem)
{
void* copy = this->_dup(elem);
rbnode* pRet = rbnode::create(key, copy);
return pRet;
}
void* rbtree::search(int key)
{
rbnode* result = search_r(m_root, key);
return result->elem;
}
rbnode* rbtree::search_r(rbnode* root, int key)
{
// @ no such key
if(!root)
{
return NULL;
}
else
{
if(key == root->key)
{
return root;
}
int direction = key > root->key;
return search_r(root->link[direction], key);
//if(key > root->key)
//{
// return search_r(root->link[1], key);
//}
//else if(key < root->key)
//{
// return search_r(root->link[0], key);
//}
//else
//{
// return root;
//}
}
}
void rbtree::insert(int key, void* elem)
{
m_bDone = false;
m_bFliped = false;
m_root = insert_r(m_root, key, elem);
m_root->red = 0;
}
rbnode* rbtree::insert_r(rbnode* root, int key, void* elem)
{
if(root == NULL)
{
root = make_node(key, elem);
m_nSize ++;
}
else if(key != root->key)
{
int direction = key > root->key;
root->link[direction] = insert_r(root->link[direction], key, elem);
if(!m_bDone)
{
root = insert_rebalance(root, direction);
}
}
return root;
}
rbnode* rbtree::insert_rebalance(rbnode* root, int direction)
{
// @ if fliped once, skip parent, go to grandparent
if(m_bFliped)
{
m_bFliped = false;
return root;
}
// @ red violation maybe
if(is_red(root->link[direction]))
{
// @ case (1)
if(is_red(root->link[!direction]))
{
root->red = 1;
root->link[0]->red = 0;
root->link[1]->red = 0;
m_bFliped = true;
}
else
{
// @ case (2)
if(is_red(root->link[direction]->link[direction]))
{
root = rotate(root, !direction);
m_bDone = true;
}
// @ case (3)
else if(is_red(root->link[direction]->link[!direction]))
{
root = drotate(root, !direction);
m_bDone = true;
}
}
}
// @ no violation
else
{
m_bDone = true;
}
return root;
}
void rbtree::remove(int key)
{
m_bDone = false;
m_root = remove_r(m_root, key);
if(m_root)
{
m_root->red = 0;
}
}
rbnode* rbtree::remove_r(rbnode* root, int key)
{
if(root == NULL)
{
m_bDone = true;
}
else
{
// @ moved below
//int direction;
// @ found it !!! the node to be deleted
if(key == root->key)
{
// @ <= 1 child
if(root->link[0] == NULL || root->link[1] == NULL)
{
rbnode* temp = root->link[root->link[0] == NULL];
// @ case(_), delete a red node
if(is_red(root))
{
m_bDone = true;
}
// @ case(0), delete a black node with one red child
else if(is_red(temp))
{
temp->red = 0;
m_bDone = true;
}
this->_del(root->elem);
delete root;
root = NULL;
m_nSize --;
return temp;
}
// @ two children case
// @ description: find its sub(substitute), copy it to the
// node, then recurse again to find the sub and delete it
// @ note: the sub is the inorder predecessor
else
{
rbnode* sub = root->link[0];
while(sub->link[1])
{
sub = sub->link[1];
}
root->key = sub->key;
this->_del(root->elem);
root->elem = this->_dup(sub->elem);
// @ to find the sub's location
key = sub->key;
}
}
int direction = key > root->key;
root->link[direction] = remove_r(root->link[direction], key);
if(!m_bDone)
{
root = remove_rebalance(root, direction);
}
}
return root;
}
rbnode* rbtree::remove_rebalance(rbnode* root, int direction)
{
// @ if sibling is red, root will be changed.
// this case, p is the old parent, root is the new one.
rbnode* p = root;
rbnode* s = root->link[!direction];
if(is_red(s))
{
root = rotate(root, direction);
s = p->link[!direction];
}
if(s != NULL)
{
if(!is_red(s->link[0]) && !is_red(s->link[1]))
{
// @ if not, rebalance will go up and do it again
if(is_red(p))
{
m_bDone = true;
//p->red = 0;
}
p->red = 0; // this could be place as above
s->red = 1;
}
else
{
// @ cuz the "p" will be changed here
// @ note: "p" could be the old root
bool p_red = p->red;
bool isRootNewed = (root != p);
if(is_red(s->link[!direction]))
{
p = rotate(p, direction);
}
else
{
p = drotate(p, direction);
}
p->red = p_red;
p->link[0]->red = 0;
p->link[1]->red = 0;
// @ root changed because of case(4)
if(isRootNewed)
{
root->link[direction] = p;
}
// @ root not changed, not case(4)
else
{
root = p;
}
m_bDone = true;
}
}
return root;
}
void rbtree::print()
{
print_r(m_root, 0);
}
void padding ( char ch, int n )
{
int i;
for ( i = 0; i < n; i++ )
putchar ( ch );
}
void rbtree::print_r(rbnode* root, int level)
{
if ( root == NULL )
{
padding ( '\t', level );
puts ( "*" );
}
else
{
print_r ( root->link[1], level + 1 );
padding ( '\t', level );
printf ( "(%d)%d\n", root->red, root->key );
print_r ( root->link[0], level + 1 );
}
}
#include <memory.h>
#include <string.h>
#include <stdlib.h>
#include <stdio.h>
#include <time.h>
#include "rbtree.h"
//#include "vld.h"
#define name_size 16
class Person
{
public:
Person(void){};
Person(const char* name, int age);
void print();
~Person(void){};
char m_name[16];
int m_age;
};
Person::Person(const char* name, int age)
{
memset(m_name, 0, name_size);
int len = strlen(name) < name_size ? strlen(name) : name_size;
memcpy(m_name, name, len);
m_age = age;
}
void Person::print()
{
printf("person: %s, %d\n", m_name, m_age);
}
void* duplicate(void* elem)
{
Person* person = (Person*)elem;
Person* pDup = new Person(*person);
return pDup;
};
void deleate(void* elem)
{
Person* person = (Person*) elem;
if(person)
{
delete person;
}
elem = NULL;
}
// @ i am lazy ...
void print_arr(int a[], int len)
{
if(a)
{
for (int i = 0; i < len; i++)
{
printf("[%d]: %d \t", i, a[i]);
if((i + 1) % 5 == 0)
{
printf("\n");
}
}
printf("\n");
}
else
{
puts("invalid array");
}
}
int main()
{
unsigned int seed = (unsigned int)time(NULL);
srand(seed);
const int size = 20;
int random[size];
for (int i = 0; i < size; i++)
{
random[i] = rand() % 1000;
}
puts("=================================== random array ==============");
print_arr(random, size);
puts("===============================================================");
rbtree* tree = rbtree::create(duplicate, deleate);
for (int i = 0; i < size; i++)
{
Person person("ljoaquin", i * 7);
tree->insert(random[i], &person);
}
tree->print();
//puts("----------- press to delete [10] --------------");
//getchar();
@ removal test
//puts("===============================================");
//tree->remove(random[10]);
//tree->print( );
//puts("----------- press to delete [5] --------------");
//getchar();
//puts("===============================================");
//tree->remove(random[5]);
//tree->print( );
//puts("----------- press to delete [15] --------------");
//getchar();
//puts("===============================================");
//tree->remove(random[15]);
//tree->print( );
//puts("----------- press to delete [0] --------------");
//getchar();
//puts("===============================================");
//tree->remove(random[0]);
//tree->print( );
//getchar();
// @ search test
Person* me = (Person*)tree->search(random[10]);
if(me)
{
me->print();
}
getchar();
rbtree::release(tree);
}