红黑树C++实现

研究了几天终于写了自己的红黑树,主要参考 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);
}









  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值