added RedBlackTree::remove()
partially added RedBlackTree::getIterator()
This commit is contained in:
		| @ -80,7 +80,8 @@ protected: | ||||
| }; | ||||
|  | ||||
| template <typename T, typename EQUALER, typename NODE, typename GET_T> | ||||
| class LinkedListIterator { | ||||
| class LinkedListIterator  | ||||
| { | ||||
| public: | ||||
| 	friend class LinkedList<T,EQUALER>; | ||||
| 	typedef NODE Node; | ||||
|  | ||||
| @ -36,7 +36,7 @@ QSE_BEGIN_NAMESPACE(QSE) | ||||
|  | ||||
| template <typename T, typename COMPARATOR> class RedBlackTree; | ||||
|  | ||||
| template <typename T, typename COMPARATOR>  | ||||
| template <typename T, typename COMPARATOR> | ||||
| class RedBlackTreeNode | ||||
| { | ||||
| public: | ||||
| @ -49,29 +49,25 @@ public: | ||||
| 		BLACK | ||||
| 	}; | ||||
|  | ||||
| 	enum Child | ||||
| 	{ | ||||
| 		LEFT, | ||||
| 		RIGHT | ||||
| 	}; | ||||
|  | ||||
| 	T value; // you can use this variable or accessor functions below | ||||
|  | ||||
| protected: | ||||
| 	Color color; | ||||
| 	SelfType* parent; | ||||
| 	SelfType* child[2]; // left and right | ||||
| 	SelfType* left; // left child | ||||
| 	SelfType* right; // right child | ||||
|  | ||||
| 	RedBlackTreeNode() | ||||
| 	RedBlackTreeNode(): color (BLACK), parent (this), left (this), right (this) | ||||
| 	{ | ||||
| 		// no initialization. make sure to initialize member variables later | ||||
| 		// no initialization on 'value' in this constructor. | ||||
| 	} | ||||
|  | ||||
| 	RedBlackTreeNode(const T& value, Color color, SelfType* parent, SelfType* left, SelfType* right): | ||||
| 		value (value), color (color), parent (parent) | ||||
| 		value (value), color (color), parent (parent), left (left), right (right) | ||||
| 	{ | ||||
| 		this->child[LEFT] = left; | ||||
| 		this->child[RIGHT] = right; | ||||
| 		QSE_ASSERT (parent != this); | ||||
| 		QSE_ASSERT (left != this); | ||||
| 		QSE_ASSERT (right != this); | ||||
| 	} | ||||
|  | ||||
| public: | ||||
| @ -79,49 +75,232 @@ public: | ||||
| 	const T& getValue () const { return this->value; } | ||||
| 	void setValue (const T& v) { this->value = v; } | ||||
|  | ||||
| 	bool isNil () const | ||||
| 	{ | ||||
| 		return this->parent == this; // && this->left == this && this->right == this; | ||||
| 	} | ||||
|  | ||||
| 	bool notNil () const | ||||
| 	{ | ||||
| 		return !this->isNil (); | ||||
| 	} | ||||
|  | ||||
| 	bool isBlack () const  { return this->color == BLACK; } | ||||
| 	bool isRed () const { return this->color == RED; } | ||||
| 	void setBlack () { this->color = BLACK; } | ||||
| 	void setRed () { this->color = RED; } | ||||
|  | ||||
| 	SelfType* getParent () { return this->parent; } | ||||
| 	const SelfType* getParent () const { return this->parent; } | ||||
|  | ||||
| 	SelfType* getLeft () { return this->child[LEFT]; } | ||||
| 	const SelfType* getLeft () const { return this->child[LEFT]; } | ||||
| 	SelfType* getLeft () { return this->left; } | ||||
| 	const SelfType* getLeft () const { return this->left; } | ||||
|  | ||||
| 	SelfType* getRight () { return this->child[RIGHT]; } | ||||
| 	const SelfType* getRight () const { return this->child[RIGHT]; } | ||||
| 	SelfType* getRight () { return this->right; } | ||||
| 	const SelfType* getRight () const { return this->right; } | ||||
|  | ||||
| 	SelfType* getChild (int idx) { return idx == 0? this->left: this->right; } | ||||
| #if 0 | ||||
| 	void setBlack () { this->color = BLACK; } | ||||
| 	void setRed () { this->color = RED; } | ||||
| 	void setParent (SelfType* node) { this->parent = node; } | ||||
| 	void setLeft (SelfType* node) { this->child[LEFT] = node; } | ||||
| 	void setRight (SelfType* node) { this->child[RIGHT] = node; } | ||||
|  | ||||
| 	void setAll (Color color, SelfType* parent, SelfType* left, SelfType* right) | ||||
| 	{ | ||||
| 		this->color = color; | ||||
| 		this->parent = parent; | ||||
| 		this->child[LEFT] = left; | ||||
| 		this->child[RIGHT] = right; | ||||
| 	} | ||||
| 	void setLeft (SelfType* node) { this->left = node; } | ||||
| 	void setRight (SelfType* node) { this->right = node; } | ||||
| #endif | ||||
| }; | ||||
|  | ||||
| template<typename T> | ||||
| template <typename T> | ||||
| struct RedBlackTreeComparator | ||||
| { | ||||
| 	int operator() (const T& v1, const T& v2) const | ||||
| 	{ | ||||
| 		return (v1 > v2)? 1:  | ||||
| 		return (v1 > v2)? 1: | ||||
| 		       (v1 < v2)? -1: 0; | ||||
| 	} | ||||
| }; | ||||
|  | ||||
| template <typename T, typename COMPARATOR, typename NODE, typename GET_T> | ||||
| class RedBlackTreeIterator | ||||
| { | ||||
| public: | ||||
| 	typedef NODE Node; | ||||
| 	typedef RedBlackTreeIterator<T,COMPARATOR,NODE,GET_T> SelfType; | ||||
|  | ||||
| 	RedBlackTreeIterator (): current (QSE_NULL), previous (QSE_NULL), next_action (0) {} | ||||
| 	RedBlackTreeIterator (Node* root): current (root)  | ||||
| 	{ | ||||
| 		this->previous = root->getParent(); | ||||
| 		this->__get_next_node (); | ||||
| 	} | ||||
|  | ||||
| protected: | ||||
| 	void __get_next_node () | ||||
| 	{ | ||||
| 		int l = 1, r = 0;  // TODO: | ||||
|  | ||||
| 		while (/*this->current &&*/ this->current->notNil()) | ||||
| 		{ | ||||
| 			if (this->previous == this->current->getParent()) | ||||
| 			{ | ||||
| 				/* the previous node is the parent of the current node. | ||||
| 				 * it indicates that we're going down to the getChild(l) */ | ||||
| 				if (this->current->getChild(l)->notNil()) | ||||
| 				{ | ||||
| 					/* go to the getChild(l) child */ | ||||
| 					this->previous = this->current; | ||||
| 					this->current = this->current->getChild(l); | ||||
| 				} | ||||
| 				else | ||||
| 				{ | ||||
| 					this->next_action = 1; | ||||
| 					break; | ||||
| 					//if (walker (rbt, this->current, ctx) == QSE_RBT_WALK_STOP) break; | ||||
|  | ||||
| #if 0 | ||||
| 					if (this->current->getChild(r)->notNil()) | ||||
| 					{ | ||||
| 						/* go down to the right node if exists */ | ||||
| 						this->previous = this->current; | ||||
| 						this->current = this->current->getChild(r); | ||||
| 					} | ||||
| 					else | ||||
| 					{ | ||||
| 						/* otherwise, move up to the parent */ | ||||
| 						this->previous = this->current; | ||||
| 						this->current = this->current->getParent(); | ||||
| 					} | ||||
| #endif | ||||
| 				} | ||||
| 			} | ||||
| 			else if (this->previous == this->current->getChild(l)) | ||||
| 			{ | ||||
| 				/* the left child has been already traversed */ | ||||
|  | ||||
| 				this->next_action = 2; | ||||
| 				break; | ||||
| 				//if (walker (rbt, this->current, ctx) == QSE_RBT_WALK_STOP) break; | ||||
|  | ||||
| #if 0 | ||||
| 				if (this->current->getChild(r)->notNil()) | ||||
| 				{ | ||||
| 					/* go down to the right node if it exists */  | ||||
| 					this->previous = this->current; | ||||
| 					this->current = this->current->getChild(r); | ||||
| 				} | ||||
| 				else | ||||
| 				{ | ||||
| 					/* otherwise, move up to the parent */ | ||||
| 					this->previous = this->current; | ||||
| 					this->current = this->current->getParent(); | ||||
| 				} | ||||
| #endif | ||||
| 			} | ||||
| 			else | ||||
| 			{ | ||||
| 				/* both the left child and the right child have been traversed */ | ||||
| 				QSE_ASSERT (this->previous == this->current->getChild(r)); | ||||
| 				/* just move up to the parent */ | ||||
| 				this->previous = this->current; | ||||
| 				this->current = this->current->getParent(); | ||||
| 			} | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	void get_next_node () | ||||
| 	{ | ||||
| 		int l = 1, r = 0;  // TODO: | ||||
|  | ||||
| 		if (next_action ==  1) | ||||
| 		{ | ||||
| 			if (this->current->getChild(r)->notNil()) | ||||
| 			{ | ||||
| 				/* go down to the right node if exists */ | ||||
| 				this->previous = this->current; | ||||
| 				this->current = this->current->getChild(r); | ||||
| 			} | ||||
| 			else | ||||
| 			{ | ||||
| 				/* otherwise, move up to the parent */ | ||||
| 				this->previous = this->current; | ||||
| 				this->current = this->current->getParent(); | ||||
| 			} | ||||
| 		} | ||||
| 		else if (next_action == 2) | ||||
| 		{ | ||||
| 			if (this->current->getChild(r)->notNil()) | ||||
| 			{ | ||||
| 				/* go down to the right node if it exists */  | ||||
| 				this->previous = this->current; | ||||
| 				this->current = this->current->getChild(r); | ||||
| 			} | ||||
| 			else | ||||
| 			{ | ||||
| 				/* otherwise, move up to the parent */ | ||||
| 				this->previous = this->current; | ||||
| 				this->current = this->current->getParent(); | ||||
| 			} | ||||
| 		} | ||||
|  | ||||
| 		this->__get_next_node (); | ||||
| 	} | ||||
|  | ||||
| public: | ||||
| 	SelfType& operator++ () // prefix increment | ||||
| 	{ | ||||
| 		this->get_next_node (); | ||||
| 		return *this; | ||||
| 	} | ||||
|  | ||||
| 	SelfType operator++ (int) // postfix increment | ||||
| 	{ | ||||
| 		SelfType saved (*this); | ||||
| 		this->get_next_node (); | ||||
| 		return saved; | ||||
| 	} | ||||
|  | ||||
| 	bool isLegit() const | ||||
| 	{ | ||||
| 		return current->notNil(); | ||||
| 	} | ||||
|  | ||||
| 	GET_T& operator* () // dereference | ||||
| 	{ | ||||
| 		return this->current->getValue(); | ||||
| 	} | ||||
|  | ||||
| 	GET_T& getValue () | ||||
| 	{ | ||||
| 		return this->current->getValue(); | ||||
| 	} | ||||
|  | ||||
| 	// no setValue(). | ||||
|  | ||||
| 	Node* getNode () | ||||
| 	{ | ||||
| 		return this->current; | ||||
| 	} | ||||
|  | ||||
| protected: | ||||
| 	Node* current; | ||||
| 	Node* previous; | ||||
| 	int next_action; | ||||
| }; | ||||
|  | ||||
|  | ||||
| /// | ||||
| /// | ||||
| ///   A node is either red or black. | ||||
| ///   The root is black. | ||||
| ///   All leaves (NIL) are black. (All leaves are same color as the root.) | ||||
| ///   Every red node must have two black child nodes. | ||||
| ///   Every path from a given node to any of its descendant NIL nodes contains the same number of black nodes. | ||||
| /// | ||||
| template <typename T, typename COMPARATOR = RedBlackTreeComparator<T> > | ||||
| class RedBlackTree: public Mmged | ||||
| { | ||||
| public: | ||||
| 	typedef RedBlackTree<T,COMPARATOR> SelfType; | ||||
| 	typedef RedBlackTreeNode<T,COMPARATOR> Node; | ||||
| 	typedef RedBlackTreeIterator<T,COMPARATOR,Node,T> Iterator; | ||||
| 	typedef RedBlackTreeIterator<T,COMPARATOR,const Node,const T> ConstIterator; | ||||
|  | ||||
| 	typedef RedBlackTreeComparator<T> DefaultComparator; | ||||
|  | ||||
| @ -129,7 +308,7 @@ public: | ||||
| 	{ | ||||
| 		// initialize nil | ||||
| 		this->nil = new(&this->mp) Node(); | ||||
| 		this->nil->setAll (Node::BLACK, this->nil, this->nil, this->nil); | ||||
| //		this->nil->setAll (Node::BLACK, this->nil, this->nil, this->nil); | ||||
|  | ||||
| 		// set root to nil | ||||
| 		this->root = this->nil; | ||||
| @ -137,10 +316,13 @@ public: | ||||
|  | ||||
| 	RedBlackTree (const RedBlackTree& rbt) | ||||
| 	{ | ||||
| 		/* TODO */ | ||||
| 	} | ||||
|  | ||||
| 	~RedBlackTree () | ||||
| 	{ | ||||
| 		this->clear (); | ||||
| 		this->dispose_node (this->nil); | ||||
| 	} | ||||
|  | ||||
| 	RedBlackTree& operator= (const RedBlackTree& rbt) | ||||
| @ -159,27 +341,17 @@ public: | ||||
| 		return this->mp; | ||||
| 	} | ||||
|  | ||||
| 	qse_size_t getSize () const  | ||||
| 	qse_size_t getSize () const | ||||
| 	{ | ||||
| 		return this->node_count; | ||||
| 	} | ||||
|  | ||||
| 	bool isEmpty () const  | ||||
| 	bool isEmpty () const | ||||
| 	{ | ||||
| 		return this->node_count <= 0; | ||||
| 	} | ||||
|  | ||||
| 	bool isNil (Node* node) const | ||||
| 	{ | ||||
| 		return node == this->nil; | ||||
| 	} | ||||
|  | ||||
| 	bool notNil (Node* node) const | ||||
| 	{ | ||||
| 		return node != this->nil; | ||||
| 	} | ||||
|  | ||||
| 	Node* getRoot ()  | ||||
| 	Node* getRoot () | ||||
| 	{ | ||||
| 		return this->root; | ||||
| 	} | ||||
| @ -190,18 +362,26 @@ public: | ||||
| 	} | ||||
|  | ||||
| protected: | ||||
| 	void dispose_node (Node* node) | ||||
| 	{ | ||||
| 		//call the destructor | ||||
| 		node->~Node ();  | ||||
| 		// free the memory | ||||
| 		::operator delete (node, &this->mp); | ||||
| 	} | ||||
|  | ||||
| 	Node* find_node (const T& datum) const | ||||
| 	{ | ||||
| 		Node* node = this->root; | ||||
|  | ||||
| 		// normal binary tree search | ||||
| 		while (notNil (node)) | ||||
| 		while (node->notNil()) | ||||
| 		{ | ||||
| 			int n = this->comparator (datum, node->value); | ||||
| 			if (n == 0) return node; | ||||
|  | ||||
| 			if (n > 0) node = node->getRight(); | ||||
| 			else /* if (n < 0) */ node = node->getLeft(); | ||||
| 			if (n > 0) node = node->right; | ||||
| 			else /* if (n < 0) */ node = node->left; | ||||
| 		} | ||||
|  | ||||
| 		return QSE_NULL; | ||||
| @ -211,11 +391,11 @@ protected: | ||||
| 	{ | ||||
| 		/* | ||||
| 		 * == leftwise rotation | ||||
| 		 * move the pivot pair down to the poistion of the pivot's original  | ||||
| 		 * left child(x). move the pivot's right child(y) to the pivot's original  | ||||
| 		 * position. as 'c1' is between 'y' and 'pivot', move it to the right  | ||||
| 		 * move the pivot pair down to the poistion of the pivot's original | ||||
| 		 * left child(x). move the pivot's right child(y) to the pivot's original | ||||
| 		 * position. as 'c1' is between 'y' and 'pivot', move it to the right | ||||
| 		 * of the new pivot position. | ||||
| 		 *       parent                   parent  | ||||
| 		 *       parent                   parent | ||||
| 		 *        | | (left or right?)      | | | ||||
| 		 *       pivot                      y | ||||
| 		 *       /  \                     /  \ | ||||
| @ -224,56 +404,56 @@ protected: | ||||
| 		 *         c1  c2            x   c1 | ||||
| 		 * | ||||
| 		 * == rightwise rotation | ||||
| 		 * move the pivot pair down to the poistion of the pivot's original  | ||||
| 		 * right child(y). move the pivot's left child(x) to the pivot's original  | ||||
| 		 * position. as 'c2' is between 'x' and 'pivot', move it to the left  | ||||
| 		 * move the pivot pair down to the poistion of the pivot's original | ||||
| 		 * right child(y). move the pivot's left child(x) to the pivot's original | ||||
| 		 * position. as 'c2' is between 'x' and 'pivot', move it to the left | ||||
| 		 * of the new pivot position. | ||||
| 		 * | ||||
| 		 *       parent                   parent  | ||||
| 		 *       parent                   parent | ||||
| 		 *        | | (left or right?)      | | | ||||
| 		 *       pivot                      x | ||||
| 		 *       /  \                     /  \ | ||||
| 		 *     x     y    =====>        c1   pivot           | ||||
| 		 *     x     y    =====>        c1   pivot | ||||
| 		 *    / \                            /  \ | ||||
| 		 *   c1  c2                         c2   y | ||||
| 		 * | ||||
| 		 * | ||||
| 		 * the actual implementation here resolves the pivot's relationship to | ||||
| 		 * its parent by comparaing pointers as it is not known if the pivot pair | ||||
| 		 * is the left child or the right child of its parent,  | ||||
| 		 * is the left child or the right child of its parent, | ||||
| 		 */ | ||||
|  | ||||
| 		Node* parent, * z, * c; | ||||
|  | ||||
| 		QSE_ASSERT (pivot != QSE_NULL); | ||||
|  | ||||
| 		parent = pivot->getParent(); | ||||
| 		parent = pivot->parent; | ||||
| 		if (leftwise) | ||||
| 		{ | ||||
| 			// y for leftwise rotation | ||||
| 			z = pivot->getRight(); | ||||
| 			z = pivot->right; | ||||
| 			// c1 for leftwise rotation | ||||
| 			c = z->getLeft(); | ||||
| 			c = z->left; | ||||
| 		} | ||||
| 		else | ||||
| 		{ | ||||
| 			// x for rightwise rotation | ||||
| 			z = pivot->getLeft(); | ||||
| 			z = pivot->left; | ||||
| 			// c2 for rightwise rotation | ||||
| 			c = z->getRight(); | ||||
| 			c = z->right; | ||||
| 		} | ||||
|  | ||||
| 		z->setParent (parent); | ||||
| 		if (notNil (parent)) | ||||
| 		z->parent = parent; | ||||
| 		if (parent->notNil()) | ||||
| 		{ | ||||
| 			if (parent->getLeft() == pivot) | ||||
| 			if (parent->left == pivot) | ||||
| 			{ | ||||
| 				parent->setLeft (z); | ||||
| 				parent->left = z; | ||||
| 			} | ||||
| 			else | ||||
| 			{ | ||||
| 				QSE_ASSERT (parent->getRight() == pivot); | ||||
| 				parent->setRight (z); | ||||
| 				QSE_ASSERT (parent->right == pivot); | ||||
| 				parent->right = z; | ||||
| 			} | ||||
| 		} | ||||
| 		else | ||||
| @ -284,51 +464,61 @@ protected: | ||||
|  | ||||
| 		if (leftwise) | ||||
| 		{ | ||||
| 			z->setLeft (pivot); | ||||
| 			pivot->setRight (c); | ||||
| 			z->left = pivot; | ||||
| 			pivot->right = c; | ||||
| 		} | ||||
| 		else | ||||
| 		{ | ||||
| 			z->setRight (pivot); | ||||
| 			pivot->setLeft (c); | ||||
| 			z->right = pivot; | ||||
| 			pivot->left = c; | ||||
| 		} | ||||
|  | ||||
| 		if (notNil(pivot)) pivot->setParent (z); | ||||
| 		if (notNil(c)) c->setParent (pivot); | ||||
| 		if (pivot->notNil()) pivot->parent = z; | ||||
| 		if (c->notNil()) c->parent = pivot; | ||||
| 	} | ||||
|  | ||||
| 	void adjust (Node* node) | ||||
| 	void rotate_left (Node* pivot) | ||||
| 	{ | ||||
| 		this->rotate (pivot, true); | ||||
| 	} | ||||
|  | ||||
| 	void rotate_right (Node* pivot) | ||||
| 	{ | ||||
| 		this->rotate (pivot, false); | ||||
| 	} | ||||
|  | ||||
| 	void rebalance_for_injection (Node* node) | ||||
| 	{ | ||||
| 		while (node != this->root) | ||||
| 		{ | ||||
| 			Node* tmp, * tmp2, * x_par, * x_par_par; | ||||
| 			Node* tmp, * tmp2, * x_par, * x_grand_par; | ||||
| 			bool leftwise; | ||||
|  | ||||
| 			x_par = node->getParent (); | ||||
| 			if (x_par->isBlack()) break; | ||||
| 			x_par = node->parent; | ||||
| 			if (x_par->color == Node::BLACK) break; | ||||
|  | ||||
| 			QSE_ASSERT (notNil (x_par->parent)); | ||||
| 			QSE_ASSERT (x_par->parent->notNil()); | ||||
|  | ||||
| 			x_par_par = x_par->getParent (); | ||||
| 			if (x_par == x_par_par->getLeft ())  | ||||
| 			x_grand_par = x_par->parent; | ||||
| 			if (x_par == x_grand_par->left) | ||||
| 			{ | ||||
| 				tmp = x_par_par->getRight (); | ||||
| 				tmp2 = x_par->getRight (); | ||||
| 				tmp = x_grand_par->right; | ||||
| 				tmp2 = x_par->right; | ||||
| 				leftwise = true; | ||||
| 			} | ||||
| 			else | ||||
| 			{ | ||||
| 				tmp = x_par_par->getLeft (); | ||||
| 				tmp2 = x_par->getLeft (); | ||||
| 				tmp = x_grand_par->left; | ||||
| 				tmp2 = x_par->left; | ||||
| 				leftwise = false; | ||||
| 			} | ||||
|  | ||||
| 			if (tmp->isRed ()) | ||||
| 			if (tmp->color == Node::RED) | ||||
| 			{ | ||||
| 				x_par->setBlack (); | ||||
| 				tmp->setBlack (); | ||||
| 				x_par_par->setRed (); | ||||
| 				node = x_par_par; | ||||
| 				x_par->color = Node::BLACK; | ||||
| 				tmp->color = Node::BLACK; | ||||
| 				x_grand_par->color = Node::RED; | ||||
| 				node = x_grand_par; | ||||
| 			} | ||||
| 			else | ||||
| 			{ | ||||
| @ -336,17 +526,173 @@ protected: | ||||
| 				{ | ||||
| 					node = x_par; | ||||
| 					this->rotate (node, leftwise); | ||||
| 					x_par = node->getParent(); | ||||
| 					x_par_par = x_par->getParent(); | ||||
| 					x_par = node->parent; | ||||
| 					x_grand_par = x_par->parent; | ||||
| 				} | ||||
|  | ||||
| 				x_par->setBlack(); | ||||
| 				x_par_par->setRed(); | ||||
| 				this->rotate (x_par_par, !leftwise); | ||||
| 				x_par->color = Node::BLACK; | ||||
| 				x_grand_par->color = Node::RED; | ||||
| 				this->rotate (x_grand_par, !leftwise); | ||||
| 			} | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	void rebalance_for_removal (Node* node, Node* par) | ||||
| 	{ | ||||
| 		while (node != this->root && node->color == Node::BLACK) | ||||
| 		{ | ||||
| 			Node* tmp; | ||||
|  | ||||
| 			if (node == par->left) | ||||
| 			{ | ||||
| 				tmp = par->right; | ||||
| 				if (tmp->color == Node::RED) | ||||
| 				{ | ||||
| 					tmp->color = Node::BLACK; | ||||
| 					par->color = Node::RED; | ||||
| 					this->rotate_left (par); | ||||
| 					tmp = par->right; | ||||
| 				} | ||||
|  | ||||
| 				if (tmp->left->color == Node::BLACK && | ||||
| 				    tmp->right->color == Node::BLACK) | ||||
| 				{ | ||||
| 					if (tmp->notNil()) tmp->color = Node::RED; | ||||
| 					node = par; | ||||
| 					par = node->parent; | ||||
| 				} | ||||
| 				else | ||||
| 				{ | ||||
| 					if (tmp->right->color == Node::BLACK) | ||||
| 					{ | ||||
| 						if (tmp->left->notNil()) | ||||
| 							tmp->left->color = Node::BLACK; | ||||
| 						tmp->color = Node::RED; | ||||
| 						this->rotate_right (tmp); | ||||
| 						tmp = par->right; | ||||
| 					} | ||||
|  | ||||
| 					tmp->color = par->color; | ||||
| 					if (par->notNil()) par->color = Node::BLACK; | ||||
| 					if (tmp->right->color == Node::RED) | ||||
| 						tmp->right->color = Node::BLACK; | ||||
|  | ||||
| 					this->rotate_left (par); | ||||
| 					node = this->root; | ||||
| 				} | ||||
| 			} | ||||
| 			else | ||||
| 			{ | ||||
| 				QSE_ASSERT (node == par->right); | ||||
| 				tmp = par->left; | ||||
| 				if (tmp->color == Node::RED) | ||||
| 				{ | ||||
| 					tmp->color = Node::BLACK; | ||||
| 					par->color = Node::RED; | ||||
| 					this->rotate_right (par); | ||||
| 					tmp = par->left; | ||||
| 				} | ||||
|  | ||||
| 				if (tmp->left->color == Node::BLACK && | ||||
| 				    tmp->right->color == Node::BLACK) | ||||
| 				{ | ||||
| 					if (tmp->notNil()) tmp->color = Node::RED; | ||||
| 					node = par; | ||||
| 					par = node->parent; | ||||
| 				} | ||||
| 				else | ||||
| 				{ | ||||
| 					if (tmp->left->color == Node::BLACK) | ||||
| 					{ | ||||
| 						if (tmp->right->notNil()) | ||||
| 							tmp->right->color = Node::BLACK; | ||||
| 						tmp->color = Node::RED; | ||||
| 						this->rotate_left (tmp); | ||||
| 						tmp = par->left; | ||||
| 					} | ||||
| 					tmp->color = par->color; | ||||
| 					if (par->notNil()) par->color = Node::BLACK; | ||||
| 					if (tmp->left->color == Node::RED) | ||||
| 						tmp->left->color = Node::BLACK; | ||||
|  | ||||
| 					this->rotate_right (par); | ||||
| 					node = this->root; | ||||
| 				} | ||||
| 			} | ||||
| 		} | ||||
|  | ||||
| 		node->color = Node::BLACK; | ||||
| 	} | ||||
|  | ||||
| 	void remove_node (Node* node) | ||||
| 	{ | ||||
| 		Node* x, * y, * par; | ||||
|  | ||||
| 		QSE_ASSERT (node && node->notNil()); | ||||
|  | ||||
| 		if (node->left->isNil() || node->right->isNil()) | ||||
| 		{ | ||||
| 			y = node; | ||||
| 		} | ||||
| 		else | ||||
| 		{ | ||||
| 			/* find a successor with NIL as a child */ | ||||
| 			y = node->right; | ||||
| 			while (y->left->notNil()) y = y->left; | ||||
| 		} | ||||
|  | ||||
| 		x = (y->left->isNil())? y->right: y->left; | ||||
|  | ||||
| 		par = y->parent; | ||||
| 		if (x->notNil()) x->parent = par; | ||||
|  | ||||
| 		if (par->notNil()) // if (par) | ||||
| 		{ | ||||
| 			if (y == par->left) | ||||
| 				par->left = x; | ||||
| 			else | ||||
| 				par->right = x; | ||||
| 		} | ||||
| 		else | ||||
| 		{ | ||||
| 			this->root = x; | ||||
| 		} | ||||
|  | ||||
| 		if (y == node) | ||||
| 		{ | ||||
| 			if (y->color == Node::BLACK && x->notNil()) | ||||
| 				this->rebalance_for_removal (x, par);  | ||||
|  | ||||
| 			this->dispose_node (y); | ||||
| 		} | ||||
| 		else | ||||
| 		{ | ||||
| 			if (y->color == Node::BLACK && x->notNil()) | ||||
| 				this->rebalance_for_removal (x, par); | ||||
|  | ||||
| 			if (node->parent->notNil()) //if (node->parent) | ||||
| 			{ | ||||
| 				if (node->parent->left == node) node->parent->left = y; | ||||
| 				if (node->parent->right == node) node->parent->right = y; | ||||
| 			} | ||||
| 			else | ||||
| 			{ | ||||
| 				this->root = y; | ||||
| 			} | ||||
|  | ||||
| 			y->parent = node->parent; | ||||
| 			y->left = node->left; | ||||
| 			y->right = node->right; | ||||
| 			y->color = node->color; | ||||
|  | ||||
| 			if (node->left->parent == node) node->left->parent = y; | ||||
| 			if (node->right->parent == node) node->right->parent = y; | ||||
|  | ||||
| 			this->dispose_node (node); | ||||
| 		} | ||||
|  | ||||
| 		this->node_count--; | ||||
| 	} | ||||
|  | ||||
| public: | ||||
| 	Node* search (const T& datum) | ||||
| @ -364,41 +710,27 @@ public: | ||||
| 		Node* x_cur = this->root; | ||||
| 		Node* x_par = this->nil; | ||||
|  | ||||
| 		while (notNil (x_cur)) | ||||
| 		while (x_cur->notNil()) | ||||
| 		{ | ||||
| 			int n = this->comparator (datum, x_cur->value); | ||||
| 			if (n == 0)  | ||||
| 			if (n == 0) | ||||
| 			{ | ||||
| 			#if 0 | ||||
| 				switch (opt) | ||||
| 				{ | ||||
| 					case UPSERT: | ||||
| 					case UPDATE: | ||||
| 						return change_pair_val (rbt, x_cur, vptr, vlen); | ||||
|  | ||||
| 					case ENSERT: | ||||
| 						/* return existing pair */ | ||||
| 						return x_cur;  | ||||
|  | ||||
| 					case INSERT: | ||||
| 						/* return failure */ | ||||
| 						return QSE_NULL; | ||||
| 				} | ||||
| 			#endif | ||||
| 				if (injected) *injected = false; | ||||
| 				if (mode <= -1) return QSE_NULL; // return failure | ||||
| 				if (mode >= 1) x_cur->value = datum; | ||||
| 				return x_cur; | ||||
| 			} | ||||
|  | ||||
| 			x_par = x_cur; | ||||
|  | ||||
| 			if (n > 0) x_cur = x_cur->getRight (); | ||||
| 			else /* if (n < 0) */ x_cur = x_cur->getLeft (); | ||||
| 			if (n > 0) x_cur = x_cur->right; | ||||
| 			else /* if (n < 0) */ x_cur = x_cur->left; | ||||
| 		} | ||||
|  | ||||
| 		//if (opt == UPDATE) return QSE_NULL; | ||||
|  | ||||
| 		Node* x_new = new(&this->mp) Node (datum, Node::RED, this->nil, this->nil, this->nil); | ||||
| 		if (isNil (x_par)) | ||||
| 		if (x_par->isNil()) | ||||
| 		{ | ||||
| 			QSE_ASSERT (isNil (this->root)); | ||||
| 			QSE_ASSERT (this->root->isNil()); | ||||
| 			this->root = x_new; | ||||
| 		} | ||||
| 		else | ||||
| @ -406,22 +738,23 @@ public: | ||||
| 			int n = this->comparator (datum, x_par->value); | ||||
| 			if (n > 0) | ||||
| 			{ | ||||
| 				QSE_ASSERT (isNil (x_par->getRight ())); | ||||
| 				x_par->setRight (x_new); | ||||
| 				QSE_ASSERT (x_par->right->isNil()); | ||||
| 				x_par->right = x_new; | ||||
| 			} | ||||
| 			else | ||||
| 			{ | ||||
| 				QSE_ASSERT (isNil (x_par->getLeft ())); | ||||
| 				x_par->setLeft (x_new); | ||||
| 				QSE_ASSERT (x_par->left->isNil()); | ||||
| 				x_par->left = x_new; | ||||
| 			} | ||||
|  | ||||
| 			x_new->setParent (x_par); | ||||
| 			this->adjust (x_new); | ||||
| 			x_new->parent = x_par; | ||||
| 			this->rebalance_for_injection (x_new); | ||||
| 		} | ||||
|  | ||||
| 		this->root->setBlack (); | ||||
| 		this->root->color = Node::BLACK; | ||||
| 		this->node_count++; | ||||
|  | ||||
| 		if (injected) *injected = true; // indicate that a new node has been injected | ||||
| 		return x_new; | ||||
| 	} | ||||
|  | ||||
| @ -440,20 +773,37 @@ public: | ||||
| 		return this->inject (datum, 1, QSE_NULL); | ||||
| 	} | ||||
|  | ||||
| #if 0 | ||||
| 	Node* update (const T& datum) | ||||
| 	{ | ||||
| 		Node* node = this->find_node (datum); | ||||
| 		if (node) node->value = datum; | ||||
| 		return node; | ||||
| 	} | ||||
| #endif | ||||
|  | ||||
| 	int remove (const T& datum) | ||||
| 	{ | ||||
| 		Node* node = this->find_node (datum); | ||||
| 		if (node == QSE_NULL) return -1; | ||||
|  | ||||
| 		this->remove_node (node); | ||||
| 		return 0; | ||||
| 	} | ||||
|  | ||||
| 	void clear (bool clear_mpool = false) | ||||
| 	{ | ||||
| 		while (this->root->notNil()) this->remove_node (this->root); | ||||
| 	} | ||||
|  | ||||
| 	Iterator getIterator () const | ||||
| 	{ | ||||
| 		return Iterator (this->root); | ||||
| 	} | ||||
|  | ||||
| 	void dump (Node* node) | ||||
| 	{ | ||||
| 		printf ("%d %d\n", node->value.getX(), node->value.getY()); | ||||
| 		if (notNil(node->getLeft())) dump (node->getLeft()); | ||||
| 		if (notNil(node->getRight())) dump (node->getRight()); | ||||
| 		if (node->left->notNil()) this->dump (node->left); | ||||
| 		if (node->right->notNil()) this->dump (node->right); | ||||
| 	} | ||||
|  | ||||
| protected: | ||||
| @ -461,7 +811,7 @@ protected: | ||||
| 	COMPARATOR comparator; | ||||
|  | ||||
| 	qse_size_t node_count; | ||||
| 	Node*      nil; // internal node to present nil  | ||||
| 	Node*      nil; // internal node to present nil | ||||
| 	Node*      root; // root node. | ||||
|  | ||||
| }; | ||||
|  | ||||
| @ -95,7 +95,7 @@ QSE_INLINE pair_t* qse_rbt_allocpair ( | ||||
| 		KPTR(n) = n + 1; | ||||
| 		if (kptr) QSE_MEMCPY (KPTR(n), kptr, KTOB(rbt,klen)); | ||||
| 	} | ||||
| 	else  | ||||
| 	else | ||||
| 	{ | ||||
| 		KPTR(n) = kcop (rbt, kptr, klen); | ||||
| 		if (KPTR(n) == QSE_NULL) | ||||
| @ -113,11 +113,11 @@ QSE_INLINE pair_t* qse_rbt_allocpair ( | ||||
| 	else if (vcop == QSE_RBT_COPIER_INLINE) | ||||
| 	{ | ||||
| 		VPTR(n) = n + 1; | ||||
| 		if (kcop == QSE_RBT_COPIER_INLINE)  | ||||
| 		if (kcop == QSE_RBT_COPIER_INLINE) | ||||
| 			VPTR(n) = (byte_t*)VPTR(n) + KTOB(rbt,klen); | ||||
| 		if (vptr) QSE_MEMCPY (VPTR(n), vptr, VTOB(rbt,vlen)); | ||||
| 	} | ||||
| 	else  | ||||
| 	else | ||||
| 	{ | ||||
| 		VPTR(n) = vcop (rbt, vptr, vlen); | ||||
| 		if (VPTR(n) != QSE_NULL) | ||||
| @ -134,7 +134,7 @@ QSE_INLINE pair_t* qse_rbt_allocpair ( | ||||
|  | ||||
| QSE_INLINE void qse_rbt_freepair (rbt_t* rbt, pair_t* pair) | ||||
| { | ||||
| 	if (rbt->style->freeer[QSE_RBT_KEY] != QSE_NULL)  | ||||
| 	if (rbt->style->freeer[QSE_RBT_KEY] != QSE_NULL) | ||||
| 		rbt->style->freeer[QSE_RBT_KEY] (rbt, KPTR(pair), KLEN(pair)); | ||||
| 	if (rbt->style->freeer[QSE_RBT_VAL] != QSE_NULL) | ||||
| 		rbt->style->freeer[QSE_RBT_VAL] (rbt, VPTR(pair), VLEN(pair)); | ||||
| @ -235,7 +235,7 @@ int qse_rbt_init (rbt_t* rbt, mmgr_t* mmgr, int kscale, int vscale) | ||||
| 	rbt->size = 0; | ||||
|  | ||||
| 	rbt->style = &style[0]; | ||||
| 	 | ||||
|  | ||||
| 	/* self-initializing nil */ | ||||
| 	QSE_MEMSET(&rbt->xnil, 0, QSE_SIZEOF(rbt->xnil)); | ||||
| 	rbt->xnil.color = QSE_RBT_BLACK; | ||||
| @ -299,11 +299,11 @@ static void rotate (rbt_t* rbt, pair_t* pivot, int leftwise) | ||||
| { | ||||
| 	/* | ||||
| 	 * == leftwise rotation | ||||
| 	 * move the pivot pair down to the poistion of the pivot's original  | ||||
| 	 * left child(x). move the pivot's right child(y) to the pivot's original  | ||||
| 	 * position. as 'c1' is between 'y' and 'pivot', move it to the right  | ||||
| 	 * move the pivot pair down to the poistion of the pivot's original | ||||
| 	 * left child(x). move the pivot's right child(y) to the pivot's original | ||||
| 	 * position. as 'c1' is between 'y' and 'pivot', move it to the right | ||||
| 	 * of the new pivot position. | ||||
| 	 *       parent                   parent  | ||||
| 	 *       parent                   parent | ||||
| 	 *        | | (left or right?)      | | | ||||
| 	 *       pivot                      y | ||||
| 	 *       /  \                     /  \ | ||||
| @ -312,23 +312,23 @@ static void rotate (rbt_t* rbt, pair_t* pivot, int leftwise) | ||||
| 	 *         c1  c2            x   c1 | ||||
| 	 * | ||||
| 	 * == rightwise rotation | ||||
| 	 * move the pivot pair down to the poistion of the pivot's original  | ||||
| 	 * right child(y). move the pivot's left child(x) to the pivot's original  | ||||
| 	 * position. as 'c2' is between 'x' and 'pivot', move it to the left  | ||||
| 	 * move the pivot pair down to the poistion of the pivot's original | ||||
| 	 * right child(y). move the pivot's left child(x) to the pivot's original | ||||
| 	 * position. as 'c2' is between 'x' and 'pivot', move it to the left | ||||
| 	 * of the new pivot position. | ||||
| 	 * | ||||
| 	 *       parent                   parent  | ||||
| 	 *       parent                   parent | ||||
| 	 *        | | (left or right?)      | | | ||||
| 	 *       pivot                      x | ||||
| 	 *       /  \                     /  \ | ||||
| 	 *     x     y    =====>        c1   pivot           | ||||
| 	 *     x     y    =====>        c1   pivot | ||||
| 	 *    / \                            /  \ | ||||
| 	 *   c1  c2                         c2   y | ||||
| 	 * | ||||
| 	 * | ||||
| 	 * the actual implementation here resolves the pivot's relationship to | ||||
| 	 * its parent by comparaing pointers as it is not known if the pivot pair | ||||
| 	 * is the left child or the right child of its parent,  | ||||
| 	 * is the left child or the right child of its parent, | ||||
| 	 */ | ||||
|  | ||||
| 	pair_t* parent, * z, * c; | ||||
| @ -349,9 +349,9 @@ static void rotate (rbt_t* rbt, pair_t* pivot, int leftwise) | ||||
|  | ||||
| 	parent = pivot->parent; | ||||
| 	/* y for leftwise rotation, x for rightwise rotation */ | ||||
| 	z = pivot->child[cid1];  | ||||
| 	z = pivot->child[cid1]; | ||||
| 	/* c1 for leftwise rotation, c2 for rightwise rotation */ | ||||
| 	c = z->child[cid2];  | ||||
| 	c = z->child[cid2]; | ||||
|  | ||||
| 	z->parent = parent; | ||||
| 	if (parent) | ||||
| @ -391,7 +391,7 @@ static void adjust (rbt_t* rbt, pair_t* pair) | ||||
|  | ||||
| 		QSE_ASSERT (x_par->parent != QSE_NULL); | ||||
|  | ||||
| 		if (x_par == x_par->parent->child[LEFT])  | ||||
| 		if (x_par == x_par->parent->child[LEFT]) | ||||
| 		{ | ||||
| 			tmp = x_par->parent->child[RIGHT]; | ||||
| 			tmp2 = x_par->child[RIGHT]; | ||||
| @ -430,10 +430,10 @@ static void adjust (rbt_t* rbt, pair_t* pair) | ||||
| static pair_t* change_pair_val ( | ||||
| 	rbt_t* rbt, pair_t* pair, void* vptr, size_t vlen) | ||||
| { | ||||
| 	if (VPTR(pair) == vptr && VLEN(pair) == vlen)  | ||||
| 	if (VPTR(pair) == vptr && VLEN(pair) == vlen) | ||||
| 	{ | ||||
| 		/* if the old value and the new value are the same, | ||||
| 		 * it just calls the handler for this condition.  | ||||
| 		 * it just calls the handler for this condition. | ||||
| 		 * No value replacement occurs. */ | ||||
| 		if (rbt->style->keeper != QSE_NULL) | ||||
| 		{ | ||||
| @ -461,7 +461,7 @@ static pair_t* change_pair_val ( | ||||
| 			else | ||||
| 			{ | ||||
| 				/* need to reconstruct the pair */ | ||||
| 				pair_t* p = qse_rbt_allocpair (rbt,  | ||||
| 				pair_t* p = qse_rbt_allocpair (rbt, | ||||
| 					KPTR(pair), KLEN(pair), | ||||
| 					vptr, vlen); | ||||
| 				if (p == QSE_NULL) return QSE_NULL; | ||||
| @ -477,7 +477,7 @@ static pair_t* change_pair_val ( | ||||
| 					{ | ||||
| 						pair->parent->left = p; | ||||
| 					} | ||||
| 					else  | ||||
| 					else | ||||
| 					{ | ||||
| 						QSE_ASSERT (pair->parent->right == pair); | ||||
| 						pair->parent->right = p; | ||||
| @ -492,7 +492,7 @@ static pair_t* change_pair_val ( | ||||
| 				return p; | ||||
| 			} | ||||
| 		} | ||||
| 		else  | ||||
| 		else | ||||
| 		{ | ||||
| 			void* nvptr = vcop (rbt, vptr, vlen); | ||||
| 			if (nvptr == QSE_NULL) return QSE_NULL; | ||||
| @ -501,7 +501,7 @@ static pair_t* change_pair_val ( | ||||
| 		} | ||||
|  | ||||
| 		/* free up the old value */ | ||||
| 		if (rbt->style->freeer[QSE_RBT_VAL] != QSE_NULL)  | ||||
| 		if (rbt->style->freeer[QSE_RBT_VAL] != QSE_NULL) | ||||
| 		{ | ||||
| 			rbt->style->freeer[QSE_RBT_VAL] (rbt, ovptr, ovlen); | ||||
| 		} | ||||
| @ -515,12 +515,12 @@ static pair_t* insert ( | ||||
| { | ||||
| 	pair_t* x_cur = rbt->root; | ||||
| 	pair_t* x_par = QSE_NULL; | ||||
| 	pair_t* x_new;  | ||||
| 	pair_t* x_new; | ||||
|  | ||||
| 	while (!IS_NIL(rbt,x_cur)) | ||||
| 	{ | ||||
| 		int n = rbt->style->comper (rbt, kptr, klen, KPTR(x_cur), KLEN(x_cur)); | ||||
| 		if (n == 0)  | ||||
| 		if (n == 0) | ||||
| 		{ | ||||
| 			switch (opt) | ||||
| 			{ | ||||
| @ -530,7 +530,7 @@ static pair_t* insert ( | ||||
|  | ||||
| 				case ENSERT: | ||||
| 					/* return existing pair */ | ||||
| 					return x_cur;  | ||||
| 					return x_cur; | ||||
|  | ||||
| 				case INSERT: | ||||
| 					/* return failure */ | ||||
| @ -609,18 +609,18 @@ pair_t* qse_rbt_cbsert ( | ||||
| { | ||||
| 	pair_t* x_cur = rbt->root; | ||||
| 	pair_t* x_par = QSE_NULL; | ||||
| 	pair_t* x_new;  | ||||
| 	pair_t* x_new; | ||||
|  | ||||
| 	while (!IS_NIL(rbt,x_cur)) | ||||
| 	{ | ||||
| 		int n = rbt->style->comper (rbt, kptr, klen, KPTR(x_cur), KLEN(x_cur)); | ||||
| 		if (n == 0)  | ||||
| 		if (n == 0) | ||||
| 		{ | ||||
| 			/* back up the contents of the current pair  | ||||
| 			/* back up the contents of the current pair | ||||
| 			 * in case it is reallocated */ | ||||
| 			pair_t tmp; | ||||
|  | ||||
| 			tmp = *x_cur;	  | ||||
| 			tmp = *x_cur; | ||||
|  | ||||
| 			/* call the callback function to manipulate the pair */ | ||||
| 			x_new = cbserter (rbt, x_cur, kptr, klen, ctx); | ||||
| @ -647,7 +647,7 @@ pair_t* qse_rbt_cbsert ( | ||||
| 					{ | ||||
| 						tmp.parent->left = x_new; | ||||
| 					} | ||||
| 					else  | ||||
| 					else | ||||
| 					{ | ||||
| 						QSE_ASSERT (tmp.parent->right == x_cur); | ||||
| 						tmp.parent->right = x_new; | ||||
| @ -730,7 +730,7 @@ static void adjust_for_delete (rbt_t* rbt, pair_t* pair, pair_t* par) | ||||
| 			{ | ||||
| 				if (tmp->right->color == QSE_RBT_BLACK) | ||||
| 				{ | ||||
| 					if (!IS_NIL(rbt,tmp->left))  | ||||
| 					if (!IS_NIL(rbt,tmp->left)) | ||||
| 						tmp->left->color = QSE_RBT_BLACK; | ||||
| 					tmp->color = QSE_RBT_RED; | ||||
| 					rotate_right (rbt, tmp); | ||||
| @ -946,7 +946,7 @@ static QSE_INLINE void walk ( | ||||
| 				{ | ||||
| 					/* otherwise, move up to the parent */ | ||||
| 					prev = x_cur; | ||||
| 					x_cur = x_cur->parent;	 | ||||
| 					x_cur = x_cur->parent; | ||||
| 				} | ||||
| 			} | ||||
| 		} | ||||
| @ -958,15 +958,15 @@ static QSE_INLINE void walk ( | ||||
|  | ||||
| 			if (!IS_NIL(rbt,x_cur->child[r])) | ||||
| 			{ | ||||
| 				/* go down to the right node if it exists */  | ||||
| 				/* go down to the right node if it exists */ | ||||
| 				prev = x_cur; | ||||
| 				x_cur = x_cur->child[r];	 | ||||
| 				x_cur = x_cur->child[r]; | ||||
| 			} | ||||
| 			else | ||||
| 			{ | ||||
| 				/* otherwise, move up to the parent */ | ||||
| 				prev = x_cur; | ||||
| 				x_cur = x_cur->parent;	 | ||||
| 				x_cur = x_cur->parent; | ||||
| 			} | ||||
| 		} | ||||
| 		else | ||||
|  | ||||
		Reference in New Issue
	
	Block a user