// wzbtree.h #ifndef _PROGRAMCOMMON_WZBTREE_H_ #define _PROGRAMCOMMON_WZBTREE_H_ #include "wzbnode.h" //------------------------------------------------------------------------------ /** @class CWzBTree */ template class CWzBTree { private: struct ProcParam { T* data; S* cmpVal; long cnt; }; public: // »ý¼ºÀÚ/¼Ò¸êÀÚ CWzBTree( void ); CWzBTree( const CWzBTree& rhs ); ~CWzBTree( void ); // operator = CWzBTree& operator = ( const CWzBTree& rhs ); // µ¥ÀÌŸ Ãß°¡(Ãß°¡µÈ ³ëµå ¹Ýȯ) CWzBNode* Add( const T& data, const S& cmpVal ); // ³ëµå Á¦°Å(ÇØ´ç ³ëµå¸¸) T RemoveNode( CWzBNode* node ); // ³ëµå Á¦°Å(Àڽĵé ÀüºÎ) void ReleaseNode( CWzBNode* node ); // ¸ðµç ³ëµå Á¦°Å void RemoveAll( void ); // Çìµå ³ëµå ã±â CWzBNode* FindHead( void ) const; // ºñ±³°ª ÀÌ¿ë ³ëµå ã±â CWzBNode* FindNode( const S& cmpVal ) const; // ÇØ´ç ³ëµåÀÇ ¿ÞÂÊ ³ëµå ¾ò±â CWzBNode* GetLeft( CWzBNode* node ) const; // ÇØ´ç ³ëµåÀÇ ¿À¸¥ÂÊ ³ëµå ¾ò±â CWzBNode* GetRight( CWzBNode* node ) const; // ÇØ´ç ³ëµåÀÇ ºÎ¸ð ³ëµå ¾ò±â CWzBNode* GetParent( CWzBNode* node ) const; // ÇØ´ç ³ëµå µ¥ÀÌŸ ¼³Á¤ void SetData( CWzBNode* node, const T& data ); // ÇØ´ç ³ëµå µ¥ÀÌŸ ¾ò±â const T& GetData( CWzBNode* node ) const; // ÇØ´ç ³ëµå ºñ±³°ª ¾ò±â const S& GetValue( CWzBNode* node ) const; // Àüü ³ëµå ¼ö ¾ò±â long GetCount( void ) const; // ºó Æ®¸®Àΰ¡? BOOL IsEmpty( void ) const; // Á¤·ÄµÈ µ¥ÀÌŸ ¸®½ºÆ® ¾ò±â void GetSortedList( T* dstData ); // Æ®¸® ÃÖÀûÈ­ void Optimize( void ); private: // Æ®¸® ¼øÈ¸Áß Æ¯Á¤ ó¸® ÇÔ¼ö Á¤ÀÇ typedef void (CWzBTree::*fnProcess)( const T&, const S&, ProcParam& ); // ÇØ´ç ³ëµåºÎÅÍ Á¦°Å(Àڽĵé ÀüºÎ) void ReleaseNodeFrom( CWzBNode* node ); // ÇØ´ç ³ëµå º¹»ç void CopyFrom( CWzBNode* node ); // Æ®¸® ¼øÈ¸ void Cycle( fnProcess, ProcParam& param ); void CycleFrom( CWzBNode* node, ProcParam& param ); // Á¤·ÄµÈ µ¥ÀÌŸ ¾ò±â void fnGetSortData( const T& data, const S& cmpVal, ProcParam& param ); void fnGetSortList( const T& data, const S& cmpVal, ProcParam& param ); // Á¤·ÄµÈ µ¥ÀÌŸ Ãß°¡ void AddB( const T* data, const S* cmpVal, int left, int right ); private: // xxx: ±¸Â÷ÇÏ°Ô ÀÌ·± º¯¼ö¸¦ ¸¸µé°í ½ÍÁø ¾ÊÁö¸¸ // ±âÁ¸¿¡ ÀÌ¹Ì ¾²·¹±â °ªÀ» ¸®ÅÏÇØ¾ß ÇÏ´Â °æ¿ì°¡ Àֱ⠶§¹®¿¡ // Â÷¶ó¸® ÀÌ ¹æ¹ýÀÌ ÁÁÀº °Í °°¾Æ ÀÌ·¸°Ô °£´Ù. static T m_dummyData; static S m_dummyVal; private: CWzBNode* m_head; long m_numNodes; fnProcess m_fnProcess; }; template T CWzBTree::m_dummyData; template S CWzBTree::m_dummyVal; //------------------------------------------------------------------------------ /** */ template CWzBTree::CWzBTree( void ) : m_head( NULL ) , m_numNodes( 0 ) , m_fnProcess( NULL ) { // empty } //------------------------------------------------------------------------------ /** */ template CWzBTree::CWzBTree( const CWzBTree& rhs ) : m_head( NULL ) , m_numNodes( 0 ) , m_fnProcess( NULL ) { CopyFrom( rhs.m_head ); } //------------------------------------------------------------------------------ /** */ template CWzBTree::~CWzBTree( void ) { RemoveAll(); } //------------------------------------------------------------------------------ /** */ template void CWzBTree::RemoveAll( void ) { if( m_head ) { ReleaseNode( m_head ); m_head = NULL; } m_numNodes = 0; } //------------------------------------------------------------------------------ /** »èÁ¦ÇÒ ³ëµåÀÇ Àڽĵé ÀüºÎ Á¦°Å - Á¦°Å½Ã ºÎ¸ð ³ëµåÀÇ left ¶Ç´Â right¸µÅ©¸¦ ¼öÁ¤ÇØ¾ß Çϱ⠶§¹®¿¡ ¹Ýµå½Ã º» ÇÔ¼ö¸¦ ÅëÇØ¼­ Á¦°Å ÇØ¾ß ÇÔ */ template void CWzBTree::ReleaseNode( CWzBNode* node ) { WzAssert( node ); if( node ) { CWzBNode* parentNode = node->GetParent(); if( parentNode ) { if( node == parentNode->GetLeft() ) { parentNode->SetLeft( NULL ); } else if( node == parentNode->GetRight() ) { parentNode->SetRight( NULL ); } else { WZLOG( WZWAR, "CWzBTree::ReleaseNode() - ºÎ¸ð ³ëµå¿ÍÀÇ ¸µÅ© ¿À·ù!!" ); } } else { m_head = NULL; } ReleaseNodeFrom( node ); } } //------------------------------------------------------------------------------ /** */ template void CWzBTree::ReleaseNodeFrom( CWzBNode* node ) { WzAssert( node ); if( node ) { if( node->GetLeft() ) { ReleaseNodeFrom( node->GetLeft() ); } if( node->GetRight() ) { ReleaseNodeFrom( node->GetRight() ); } delete node; --m_numNodes; } } //------------------------------------------------------------------------------ /** */ template void CWzBTree::CopyFrom( CWzBNode* node ) { WzAssert( node ); if( node ) { Add( node->GetData(), node->GetValue() ); if( node->GetLeft() ) { CopyFrom( node->GetLeft() ); } if( node->GetRight() ) { CopyFrom( node->GetRight() ); } } } //------------------------------------------------------------------------------ /** */ template CWzBTree& CWzBTree::operator = ( const CWzBTree& rhs ) { if( &rhs == this ) { return *this; } RemoveAll(); if( rhs.m_head ) { CopyFrom( rhs.m_head ); } return *this; } //------------------------------------------------------------------------------ /** */ template CWzBNode* CWzBTree::Add( const T& data, const S& cmpVal ) { // Çìµå°¡ ¾ø´Â °æ¿ì, Çìµå¿¡ ¼¼ÆÃ if( !m_head ) { m_head = new CWzBNode( data, cmpVal ); WzAssert( m_head ); WzAssert( m_numNodes == 0 ); m_numNodes = 1; return m_head; } CWzBNode* curNode = m_head; CWzBNode* parentNode = m_head; // value ºñ±³ // ÇöÀç ³ëµå °ªº¸´Ù ÀÛÀ¸¸é ¿ÞÂÊ, Å©¸é ¿À¸¥ÂÊ ³ëµå ¼±Åà // xxx: °°Àº °æ¿ì´Â ¿À¸¥ÂÊ ³ëµå ¼±Åà (±âÁ¸ ȣȯ¼º À¯Áö) // ±âÁ¸°úÀÇ È£È¯¼ºÀ» À¯ÁöÇϱâ À§ÇØ Å° °ªÀÌ °°Àº °æ¿ì // ¿À¸¥ÂÊ ³ëµå¸¦ ¼±ÅÃÇÏ°Ô Çϱä ÇßÁö¸¸ ÀÌ °æ¿ì ۰¡ Áߺ¹µÇ±â // ¶§¹®¿¡ Æ®¸®°¡ ±úÁ® ¹ö¸°´Ù. while( curNode ) { parentNode = curNode; if( cmpVal < curNode->GetValue() ) { curNode = curNode->GetLeft(); } else { curNode = curNode->GetRight(); } } WzAssert( parentNode ); CWzBNode* newNode = new CWzBNode( data, cmpVal ); WzAssert( newNode ); // ºÎ¸ð °ªÀ̶û ºñ±³, ÀÛÀ¸¸é ¿ÞÂÊ ÀÚ½ÄÀ¸·Î if( cmpVal < parentNode->GetValue() ) { parentNode->SetLeft( newNode ); } else { parentNode->SetRight( newNode ); } ++m_numNodes; return newNode; } //------------------------------------------------------------------------------ /** »èÁ¦ÇÒ ³ëµåÀÇ ÀڽĵéÀ» ´Ù Á¦°ÅÇÏ´Â °ÍÀÌ ¾Æ´Ï´Ù. ´Ü¼øÈ÷ ÇØ´ç ³ëµå¸¸ »èÁ¦ ¶Ç´Â °ªÀ» º¯°æÇؼ­, Æ®¸®¸¦ À¯Áö½ÃŲ´Ù. */ template T CWzBTree::RemoveNode( CWzBNode* remNode ) { WzAssert( remNode ); if( !remNode ) { WZLOG( WZWAR, "CWzBTree::RemoveNode() - ½ÇÆÐ!! NULL Æ÷ÀÎÅÍ (¾²·¹±â°ª ¹Ýȯ)" ); return m_dummyData; } T retData = remNode->GetData(); // Æ®¸® ±¸Á¶ ÀçÁ¤ºñ // ¿ÞÂÊ ÀÚ½ÄÀÇ °¡Àå ¿À¸¥ÂÊ¿¡ ÀÖ´Â °ªÀ¸·Î ´ëü // »èÁ¦ÇÒ ³ëµåÀÇ ¿ÞÂÊ ÀÚ½ÄÀ» ¾ò°í CWzBNode* leftNode = remNode->GetLeft(); if( leftNode ) { // »èÁ¦ÇÒ ³ëµåÀÇ ¿À¸¥ÂÊ ÀÚ½ÄÀÌ ¾ø´Â °æ¿ì(¿ÞÂÊ Àڽĸ¸ ÀÖ´Â °æ¿ì) if( !remNode->GetRight() ) { // »èÁ¦ÇÒ ³ëµå°¡ Çìµå ³ëµåÀÎ °æ¿ì if( remNode == m_head ) { // ÀÌ °æ¿ì´Â ÇìµåÀÇ ¿ÞÂÊÀ¸·Î¸¸ ÀڽĵéÀÌ ÀÖ´Â °æ¿ì´Ù. // ÇìµåÀÇ ¿ÞÂÊ Àڽijëµå¸¦ Çìµå·Î ¼³Á¤ÇÏ¸é ³¡ m_head = leftNode; m_head->m_parent = NULL; } else { CWzBNode* parentNode = remNode->GetParent(); WzAssert( parentNode ); // »èÁ¦ÇÒ ³ëµå°¡ ºÎ¸ð ³ëµåÀÇ ¿ÞÂÊ ÀÚ½ÄÀÎ °æ¿ì if( remNode == parentNode->GetLeft() ) { // »èÁ¦ÇÒ ³ëµåÀÇ ¿ÞÂÊ ÀÚ½Ä ³ëµå¸¦ ºÎ¸ð ³ëµåÀÇ ¿ÞÂÊ ÀÚ½ÄÀ¸·Î ¼³Á¤ parentNode->SetLeft( leftNode ); } else if( remNode == parentNode->GetRight() ) { // »èÁ¦ÇÒ ³ëµåÀÇ ¿ÞÂÊ ÀÚ½Ä ³ëµå¸¦ ºÎ¸ð ³ëµåÀÇ ¿À¸¥ÂÊ ÀÚ½ÄÀ¸·Î ¼³Á¤ parentNode->SetRight( leftNode ) ; } else { WZLOG( WZWAR, "CWzBTree::RemoveNode() - ºÎ¸ð ³ëµå¿ÍÀÇ ¸µÅ© ¿À·ù!!" ); } } delete remNode; --m_numNodes; return retData; } // »èÁ¦ÇÒ ³ëµåÀÇ ¿ÞÂÊ, ¿À¸¥ÂÊ ÀÚ½Ä ´Ù ÀÖ´Â °æ¿ì // »èÁ¦ÇÒ ³ëµå ¿ÞÂÊ ÀÚ½Ä ³ëµåÀÇ °¡Àå ¿À¸¥ÂÊ¿¡ ÀÖ´Â °ªÀ» ±¸Çϰí // ±¸ÇÑ °ªÀ¸·Î »èÁ¦ÇÒ ³ëµåÀÇ °ª ¼³Á¤ // Á¤ÀÛ Á¦°ÅµÇ´Â ³ÑÀº »èÁ¦ÇÒ ³ëµå ¿ÞÂÊ ÀÚ½Ä ³ëµåÀÇ °¡Àå ¿À¸¥ÂÊ¿¡ ÀÖ´Â ³Ñ // ÀÏ´Ü ÇöÀç ³ëµå¸¦ »èÁ¦ÇÒ ³ëµå ¿ÞÂÊ ÀÚ½Ä ³ëµå·Î ¼³Á¤Çϰí // ±× ³ëµåÀÇ °¡Àå ¿À¸¥ÂÊ¿¡ ÀÖ´Â ÀÚ½Ä ³ëµå¸¦ ±¸ÇÑ´Ù. CWzBNode* curNode = leftNode; CWzBNode* rightLeafNode; while( curNode ) { rightLeafNode = curNode; curNode = curNode->GetRight(); } // ±× °ªÀ» ±¸ÇØ ³õ°í T data = rightLeafNode->m_data; S cmpVal = rightLeafNode->m_cmpVal; // ±× ³ëµå¸¦ Á¦°ÅÇÑ´Ù. // ¿À¸¥ÂÊ ³¡ ³ëµåÁö¸¸, ¿ÞÂÊ ÀÚ½Ä ³ëµå°¡ ÀÖÀ» ¼ö Àֱ⠶§¹®¿¡ // RemoveNode¸¦ ÅëÇØ¼­ Á¦°ÅÇØ¾ß ÇÑ´Ù. RemoveNode( rightLeafNode ); // »èÁ¦ÇÒ ³ëµåÀÇ °ªÀ» ±¸ÇØ ³õÀº °ªÀ¸·Î ´ëüÇÑ´Ù. remNode->m_data = data; remNode->m_cmpVal = cmpVal; return retData; } // ¿ÞÂÊ ÀÚ½ÄÀÌ ¾ø´Â °æ¿ì else { CWzBNode* rightNode = remNode->GetRight(); // ¿À¸¥ÂÊ ÀÚ½ÄÀÌ ÀÖ´Â °æ¿ì if( rightNode ) { // »èÁ¦ÇÒ ³ëµå°¡ Çìµå ³ëµåÀÎ °æ¿ì if( remNode == m_head ) { m_head = rightNode; m_head->m_parent = NULL; } else { CWzBNode* parentNode = remNode->GetParent(); WzAssert( parentNode ); // »èÁ¦ÇÒ ³ëµå°¡ ºÎ¸ð ³ëµåÀÇ ¿ÞÂÊ ÀÚ½ÄÀÎ °æ¿ì if( remNode == parentNode->GetLeft() ) { parentNode->SetLeft( rightNode ); } else if( remNode == parentNode->GetRight() ) { parentNode->SetRight( rightNode ); } else { WZLOG( WZWAR, "CWzBTree::RemoveNode() - ºÎ¸ð ³ëµå¿ÍÀÇ ¸µÅ© ¿À·ù!!" ); } } delete remNode; --m_numNodes; return retData; } } // ¾çÂÊ ÀÚ½Ä ´Ù ¾ø´Â °æ¿ì CWzBNode* parentNode = remNode->GetParent(); if( parentNode ) { if( remNode == parentNode->GetLeft() ) { parentNode->SetLeft( NULL ); } else if( remNode == parentNode->GetRight() ) { parentNode->SetRight( NULL ); } else { WZLOG( WZWAR, "CWzBTree::RemoveNode() - ºÎ¸ð ³ëµå¿ÍÀÇ ¸µÅ© ¿À·ù!!" ); } } else { m_head = NULL; } delete remNode; --m_numNodes; return retData; } //------------------------------------------------------------------------------ /** */ template CWzBNode* CWzBTree::FindHead( void ) const { return m_head; } //------------------------------------------------------------------------------ /** */ template CWzBNode* CWzBTree::FindNode( const S& cmpVal ) const { CWzBNode* node = m_head; while( node ) { if( node->GetValue() == cmpVal ) { return node; } if( cmpVal < node->GetValue() ) { node = node->GetLeft(); } else { node = node->GetRight(); } } return NULL; } //------------------------------------------------------------------------------ /** */ template CWzBNode* CWzBTree::GetLeft( CWzBNode* node ) const { WzAssert( node ); return ( node ? node->GetLeft() : NULL ); } //------------------------------------------------------------------------------ /** */ template CWzBNode* CWzBTree::GetRight( CWzBNode* node ) const { WzAssert( node ); return ( node ? node->GetRight() : NULL ); } //------------------------------------------------------------------------------ /** */ template CWzBNode* CWzBTree::GetParent( CWzBNode* node ) const { WzAssert( node ); return ( node ? node->GetParent() : NULL ); } //------------------------------------------------------------------------------ /** */ template void CWzBTree::SetData( CWzBNode* node, const T& data ) { WzAssert( node ); if( node ) { node->SetData( data ); } } //------------------------------------------------------------------------------ /** */ template const T& CWzBTree::GetData( CWzBNode* node ) const { WzAssert( node ); if( node ) { return node->GetData(); } WZLOG( WZWAR, "CWzBTree::GetData() - ½ÇÆÐ!! NULL Æ÷ÀÎÅÍ (¾²·¹±â°ª ¹Ýȯ)" ); return m_dummyData; } //------------------------------------------------------------------------------ /** */ template const S& CWzBTree::GetValue( CWzBNode* node ) const { WzAssert( node ); if( node ) { return node->GetValue(); } WZLOG( WZWAR, "CWzBTree::GetValue() - ½ÇÆÐ!! NULL Æ÷ÀÎÅÍ (¾²·¹±â°ª ¹Ýȯ)" ); return m_dummyVal; } //------------------------------------------------------------------------------ /** */ template long CWzBTree::GetCount( void ) const { return m_numNodes; } //------------------------------------------------------------------------------ /** */ template BOOL CWzBTree::IsEmpty( void ) const { return ( m_numNodes == 0 ); } //------------------------------------------------------------------------------ /** ÁßÀ§ ¼øÈ¸ (¿ÞÂÊ -> ÀڽŠ-> ¿À¸¥ÂÊ) */ template void CWzBTree::CycleFrom( CWzBNode* node, ProcParam& param ) { WzAssert( node ); WzAssert( m_fnProcess ); if( node->GetLeft() ) { CycleFrom( node->GetLeft(), param ); } (this->*m_fnProcess)( node->GetData(), node->GetValue(), param ); if( node->GetRight() ) { CycleFrom( node->GetRight(), param ); } } //------------------------------------------------------------------------------ /** */ template void CWzBTree::Cycle( fnProcess fn, ProcParam& param ) { WzAssert( fn ); m_fnProcess = fn; if( m_head ) { CycleFrom( m_head, param ); } } //------------------------------------------------------------------------------ /** */ template void CWzBTree::fnGetSortData( const T& data, const S& cmpVal, ProcParam& param ) { WzAssert( param.data ); param.data[param.cnt++] = data; } //------------------------------------------------------------------------------ /** Á¤·ÄµÈ µ¥ÀÌŸ¸¦ ¾ò´Â ÇÔ¼öÁö¸¸, ÀÌÀüºÎÅÍ GetSortedList¶ó´Â ÇÔ¼ö¸íÀ» ½è±â ¶§¹®¿¡, ±»ÀÌ ¹Ù²ÙÁö´Â ¾Ê¾Ò´Ù. */ template void CWzBTree::GetSortedList( T* dstData ) { ProcParam param; param.data = dstData; param.cnt = 0; Cycle( &CWzBTree::fnGetSortData, param ); } //------------------------------------------------------------------------------ /** */ template void CWzBTree::fnGetSortList( const T& data, const S& cmpVal, ProcParam& param ) { WzAssert( param.data ); WzAssert( param.cmpVal ); param.data[param.cnt] = data; param.cmpVal[param.cnt] = cmpVal; ++param.cnt; } //------------------------------------------------------------------------------ /** */ template void CWzBTree::AddB( const T* data, const S* cmpVal, int left, int right ) { if( left != right) { WzAssert( data ); WzAssert( cmpVal ); Add( data[(left + right) / 2], cmpVal[(left + right) / 2] ); AddB( data, cmpVal, left, (left + right) / 2 ); AddB( data, cmpVal, (left + right) / 2 + 1, right ); } } //------------------------------------------------------------------------------ /** */ template void CWzBTree::Optimize( void ) { if( m_numNodes <= 0 ) { WZLOG( WZDBG, "CWzBTree::Optimize() - µ¥ÀÌŸ ¾øÀ½" ); return; } int numNodes = m_numNodes; ProcParam param; memset( ¶m, 0, sizeof( param ) ); param.data = new T[numNodes]; param.cmpVal = new S[numNodes]; if( !param.data || !param.cmpVal ) { WZLOG( WZWAR, "CWzBTree::Optimize() - ¸Þ¸ð¸® È®º¸ ½ÇÆÐ" ); goto _cleanup; } Cycle( fnGetSortList, param ); if( param.cnt != numNodes ) { WZLOG( WZWAR, "CWzBTree::Optimize() - ¿À·ù!! µ¥ÀÌŸ ¼ö ºÒÀÏÄ¡" ); goto _cleanup; } RemoveAll(); AddB( param.data, param.cmpVal, 0, param.cnt ); _cleanup: if( param.data ) { delete [] param.data; } if( param.cmpVal ) { delete [] param.cmpVal; } } #endif // _PROGRAMCOMMON_WZBTREE_H_