From 0ece41a9e0a6e8120e81b31589a6e815f5d14e88 Mon Sep 17 00:00:00 2001 From: hyung-hwan Date: Sun, 1 Mar 2015 12:55:36 +0000 Subject: [PATCH] added RedBlackTable --- qse/include/qse/cmn/LinkedList.hpp | 4 +- qse/include/qse/cmn/Makefile.am | 2 +- qse/include/qse/cmn/Makefile.in | 4 +- qse/include/qse/cmn/RedBlackTable.hpp | 268 ++++++++++++++++++++++++++ qse/include/qse/cmn/RedBlackTree.hpp | 54 +++++- 5 files changed, 321 insertions(+), 11 deletions(-) create mode 100644 qse/include/qse/cmn/RedBlackTable.hpp diff --git a/qse/include/qse/cmn/LinkedList.hpp b/qse/include/qse/cmn/LinkedList.hpp index 21a516da..cabbe5f3 100644 --- a/qse/include/qse/cmn/LinkedList.hpp +++ b/qse/include/qse/cmn/LinkedList.hpp @@ -84,6 +84,7 @@ class LinkedListIterator { public: friend class LinkedList; + //typedef LinkedListNode Node; typedef NODE Node; typedef LinkedListIterator SelfType; @@ -162,11 +163,10 @@ public: return this->current->getValue(); } - SelfType& setValue (const T& v) + void setValue (const T& v) { QSE_ASSERT (this->current != QSE_NULL); this->current->setValue (v); - return *this; } Node* getNode () diff --git a/qse/include/qse/cmn/Makefile.am b/qse/include/qse/cmn/Makefile.am index ebfac3d4..4983d898 100644 --- a/qse/include/qse/cmn/Makefile.am +++ b/qse/include/qse/cmn/Makefile.am @@ -53,6 +53,6 @@ if ENABLE_CXX pkginclude_HEADERS += \ Mmgr.hpp StdMmgr.hpp HeapMmgr.hpp Mmged.hpp \ Mpool.hpp Association.hpp LinkedList.hpp HashList.hpp HashTable.hpp \ - RedBlackTree.hpp + RedBlackTree.hpp RedBlackTable.hpp endif diff --git a/qse/include/qse/cmn/Makefile.in b/qse/include/qse/cmn/Makefile.in index 40ec7ec4..a03648d0 100644 --- a/qse/include/qse/cmn/Makefile.in +++ b/qse/include/qse/cmn/Makefile.in @@ -53,7 +53,7 @@ host_triplet = @host@ @ENABLE_CXX_TRUE@am__append_1 = \ @ENABLE_CXX_TRUE@ Mmgr.hpp StdMmgr.hpp HeapMmgr.hpp Mmged.hpp \ @ENABLE_CXX_TRUE@ Mpool.hpp Association.hpp LinkedList.hpp HashList.hpp HashTable.hpp \ -@ENABLE_CXX_TRUE@ RedBlackTree.hpp +@ENABLE_CXX_TRUE@ RedBlackTree.hpp RedBlackTable.hpp subdir = include/qse/cmn DIST_COMMON = $(am__pkginclude_HEADERS_DIST) $(srcdir)/Makefile.am \ @@ -93,7 +93,7 @@ am__pkginclude_HEADERS_DIST = alg.h chr.h cp949.h cp950.h dir.h dll.h \ sll.h slmb.h str.h task.h time.h tio.h tmr.h tre.h uni.h uri.h \ utf8.h xma.h Mmgr.hpp StdMmgr.hpp HeapMmgr.hpp Mmged.hpp \ Mpool.hpp Association.hpp LinkedList.hpp HashList.hpp \ - HashTable.hpp RedBlackTree.hpp + HashTable.hpp RedBlackTree.hpp RedBlackTable.hpp am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`; am__vpath_adj = case $$p in \ $(srcdir)/*) f=`echo "$$p" | sed "s|^$$srcdirstrip/||"`;; \ diff --git a/qse/include/qse/cmn/RedBlackTable.hpp b/qse/include/qse/cmn/RedBlackTable.hpp new file mode 100644 index 00000000..ac74cda9 --- /dev/null +++ b/qse/include/qse/cmn/RedBlackTable.hpp @@ -0,0 +1,268 @@ +/* + * $Id$ + * + Copyright (c) 2006-2014 Chung, Hyung-Hwan. All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + 1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + THIS SOFTWARE IS PROVIDED BY THE AUTHOR "AS IS" AND ANY EXPRESS OR + IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef _QSE_CMN_REDBLACKTABLE_HPP_ +#define _QSE_CMN_REDBLACKTABLE_HPP_ + +#include +#include + +///////////////////////////////// +QSE_BEGIN_NAMESPACE(QSE) +///////////////////////////////// + +template +struct RedBlackTableComparator +{ + // it must return true if two values are equal + int operator() (const T& v1, const T& v2) const + { + if (v1 > v2) return 1; + if (v1 < v2) return -1; + QSE_ASSERT (v1 == v2); + return 0; + } +}; + + +template > +class RedBlackTable: public Mmged +{ +public: + typedef Association Pair; + typedef RedBlackTable SelfType; + + typedef RedBlackTableComparator DefaultComparator; + + struct PairComparator + { + qse_size_t operator() (const Pair& p1, const Pair& p2) const + { + COMPARATOR comparator; + return comparator (p1.key, p2.key); + } + }; + + struct PairHeteroComparator + { + qse_size_t operator() (const K& p1, const Pair& p2) const + { + COMPARATOR comparator; + return comparator (p1, p2.key); + } + }; + + template + struct MHeteroComparator + { + qse_size_t operator() (const MK& p1, const Pair& p2) const + { + MCOMPARATOR mcomparator; + return mcomparator (p1, p2.key); + } + }; + + typedef RedBlackTree PairTree; + typedef typename PairTree::Node PairNode; + typedef typename PairTree::Iterator Iterator; + typedef typename PairTree::ConstIterator ConstIterator; + + + RedBlackTable (Mmgr* mmgr = QSE_NULL, qse_size_t mpb_size = 0): + Mmged(mmgr), pair_tree (mmgr, mpb_size) + { + } + + RedBlackTable (const SelfType& table): Mmged (table), pair_tree (table.pair_tree) + { + } + + SelfType& operator= (const SelfType& table) + { + this->pair_tree = table.pair_tree; + return *this; + } + + Mpool& getMpool () + { + return this->pair_tree.getMpool (); + } + + const Mpool& getMpool () const + { + return this->pair_tree.getMpool (); + } + + qse_size_t getCapacity() const + { + return this->pair_tree.getCapacity (); + } + + qse_size_t getSize() const + { + return this->pair_tree.getSize (); + } + + bool isEmpty () const + { + return this->pair_tree.isEmpty (); + } + + PairNode* getHeadNode () + { + return this->pair_tree.getHeadNode (); + } + + const PairNode* getHeadNode () const + { + return this->pair_tree.getHeadNode (); + } + + PairNode* getTailNode () + { + return this->pair_tree.getTailNode (); + } + + const PairNode* getTailNode () const + { + return this->pair_tree.getTailNode (); + } + + Pair* inject (const K& key, const V& value, int mode, bool* injected = QSE_NULL) + { + PairNode* node = this->pair_tree.inject (Pair(key, value), mode, injected); + if (!node) return QSE_NULL; + return &node->value; + } + + Pair* insert (const K& key, const V& value) + { + PairNode* node = this->pair_tree.insert (Pair(key, value)); + if (!node) return QSE_NULL; + return &node->value; + } + + Pair* ensert (const K& key, const V& value) + { + PairNode* node = this->pair_tree.ensert (Pair(key, value)); + if (!node) return QSE_NULL; + return &node->value; + } + + Pair* upsert (const K& key, const V& value) + { + //PairNode* node = this->pair_tree.upsert (Pair(key, value)); + //if (!node) return QSE_NULL; + //return &node->value; + + // Don't call pair_tree.upsert() to make sure that the 'key' object + // itself remains identical after potential update operation. + // pair_tree.upsert() changes the Pair object as a whole. so this + // trick is required. + bool injected; + PairNode* node = this->pair_tree.inject (Pair(key, value), 0, &injected); + QSE_ASSERT (node != QSE_NULL); + Pair& pair = node->value; + if (injected) pair.value = value; + return &pair; + } + + Pair* update (const K& key, const V& value) + { + //PairNode* node = this->pair_tree.update (Pair(key, value)); + //if (!node) return QSE_NULL; + //return &node->value; + + PairNode* node = this->pair_tree.template heterofindNode (key); + if (!node) return QSE_NULL; + Pair& pair = node->value; + pair.value = value; + return &pair; + } + + Pair* search (const K& key) + { + //PairNode* node = this->pair_tree.update (Pair(key)); + PairNode* node = this->pair_tree.template heterofindNode (key); + if (!node) return QSE_NULL; + return &node->value; + } + + int remove (const K& key) + { + //return this->pair_tree.remove (Pair(key)); + return this->pair_tree.template heteroremove (key); + } + + template + Pair* heterosearch (const MK& key) + { + typedef MHeteroComparator MComparator; + PairNode* node = this->pair_tree.template heterosearch (key); + if (!node) return QSE_NULL; + return &node->value; + } + + template + const Pair* heterosearch (const MK& key) const + { + typedef MHeteroComparator MComparator; + PairNode* node = this->pair_tree.template heterosearch (key); + if (!node) return QSE_NULL; + return &node->value; + } + + template + int heteroremove (const MK& key) + { + typedef MHeteroComparator MComparator; + return this->pair_tree.template heteroremove (key); + } + + void clear (bool clear_mpool = false) + { + return this->pair_tree.clear (clear_mpool); + } + + Iterator getIterator (qse_size_t index = 0) + { + return this->pair_tree.getIterator (index); + } + + ConstIterator getConstIterator (qse_size_t index = 0) const + { + return this->pair_tree.getConstIterator (index); + } + +protected: + PairTree pair_tree; +}; + +///////////////////////////////// +QSE_END_NAMESPACE(QSE) +///////////////////////////////// + +#endif diff --git a/qse/include/qse/cmn/RedBlackTree.hpp b/qse/include/qse/cmn/RedBlackTree.hpp index 5cc7d18c..0aa70cfb 100644 --- a/qse/include/qse/cmn/RedBlackTree.hpp +++ b/qse/include/qse/cmn/RedBlackTree.hpp @@ -113,8 +113,10 @@ struct RedBlackTreeComparator { int operator() (const T& v1, const T& v2) const { - return (v1 > v2)? 1: - (v1 < v2)? -1: 0; + if (v1 > v2) return 1; + if (v1 < v2) return -1; + QSE_ASSERT (v1 == v2); + return 0; } }; @@ -250,6 +252,20 @@ public: // no operator-- + bool operator== (const SelfType& it) const + { + QSE_ASSERT (this->current != QSE_NULL); + return this->current == it.current && + this->previous == it.previous; + } + + bool operator!= (const SelfType& it) const + { + QSE_ASSERT (this->current != QSE_NULL); + return this->current != it.current || + this->previous != it.previous; + } + bool isLegit() const { return current->notNil(); @@ -302,7 +318,10 @@ public: typedef RedBlackTreeComparator DefaultComparator; - RedBlackTree (Mmgr* mmgr = QSE_NULL, qse_size_t mpb_size = 0): Mmged(mmgr), mp (mmgr, QSE_SIZEOF(Node), mpb_size), node_count (0) + RedBlackTree (Mmgr* mmgr = QSE_NULL, qse_size_t mpb_size = 0): + Mmged(mmgr), + mp (mmgr, QSE_SIZEOF(Node), mpb_size), + node_count (0) { // create a nil object this->nil = new(&this->mp) Node(); @@ -311,9 +330,25 @@ public: this->root = this->nil; } - RedBlackTree (const RedBlackTree& rbt) + RedBlackTree (const RedBlackTree& rbt): + Mmged(rbt.getMmgr()), + mp (rbt.getMmgr(), rbt.mp.getDatumSize(), rbt.mp.getBlockSize()), + node_count (0) { - /* TODO */ + + // create a nil object + this->nil = new(&this->mp) Node(); + + // set root to nil + this->root = this->nil; + + // TODO: do the level-order traversal to minize rebalancing. + Iterator it = rbt.getIterator(); + while (it.isLegit()) + { + this->insert (*it); + ++it; + } } ~RedBlackTree () @@ -326,7 +361,13 @@ public: { this->clear (); - /* TODO */ + // TODO: do the level-order traversal to minize rebalancing. + Iterator it = rbt.getIterator(); + while (it.isLegit()) + { + this->insert (*it); + ++it; + } return *this; } @@ -792,6 +833,7 @@ public: void clear (bool clear_mpool = false) { while (this->root->notNil()) this->remove_node (this->root); + QSE_ASSERT (this->root = this->nil); } Iterator getIterator (typename Iterator::Mode mode = Iterator::ASCENDING) const