#ifndef __ZNSMAIN_ZTOBJAVL_H__ #define __ZNSMAIN_ZTOBJAVL_H__ #include "ZCppMain/ZMainAVL.H" namespace ZNsMain { /*///////////////////////////////////////////////////////////////////////////////////////// ■ 이 AVL tree 는 각 노드가 트리 구조를 이루며, 동시에 이중 원형 연결리스트를 이루고 있다. 자료를 기본적으로 오름차순 정렬한다. ■ Type 자료형에는 <,>,== 연산이 가능해야 한다. ■ 어떤 클래스에 비교연산자를 정의할 때 bool operator>(const CStringHash& rhs) const 와 같 이 하면 인수에도 const, 멤버함수에도 const 를 잊지 말 것. ■ 접미어 Key 가 붙어있는 멤버 함수는 Type 보다는 크기가 작은 어떤 자료형이다. 삽입, 삭제 시에 메모리를 절약하기 위해서 사용한다. Type 자료형과 Key 자료형 사이에는 <,>,==,= 의 연 산이 가능해야 한다. ■ multi set 으로 활용하는 코드는 MainAVL.H 파일의 주석에 예시하였다. typename TNodeBase 를 std::NsInterface::CAVL_Multi_NodeBase_T<> 으로 지정하고 있다. /////////////////////////////////////////////////////////////////////////////////////////*/ template< typename Type , typename TTypArg =const Type& , typename TTypBase =ZNsMain::ZNsIFace::ZtCAVL_BASE , typename TNodeBase =ZNsMain::ZNsIFace::ZtCAVL_NodeBase , typename TAlloc =ZNsMain::ZCAllocator , typename TSize =ZNsMain::ZTypLong , typename TCompare =ZNsMain::ZNsFunc::ZtCCompare, typename TMoveObj =ZNsMain::ZNsFunc::ZtCMoveObj > class ZtCObjAVL : public TTypBase /////////////////////////////////////////////////////// { public: typedef Type TypeData ; typedef TTypArg TypeArg ; typedef TTypBase TypeBase ; typedef TNodeBase TypeNodeBase; typedef TAlloc TypeAlloc ; typedef TSize TypeSize ; typedef TCompare TypeCompare ; typedef TMoveObj TypeMoveObj ; public: class ZCNode : public TNodeBase, public TAlloc /* ZCNode object 는 이중 원형 연결리스트로 관리된다. */ { public : friend class ZtCObjAVL; protected: ZCNode* mp_PrevNode; /* 이전 노드 */ ZCNode* mp_NextNode; /* 다음 노드 */ ZCNode* mp_LeftNode; /* 왼쪽 노드 */ ZCNode* mp_RighNode; /* 오른쪽 노드 */ ZCNode* mp_HighNode; /* 상위 노드 */ Type mo_Type ; int mi_Balance ; /* 오른쪽 노드에 삽입될 때마다 mi_Balance 는 1 씩 증가하고 * 왼쪽 노드에 삽입될 때마다 mi_Balance 는 1 씩 감소한다. * 이 값이 +2 나 -2 가 될 때 노드의 회전을 수행하여 평형을 맞춘다. * 결과적으로 -1<=mi_Balance && mi_Balance<=1 이 되게 한다. */ inline void InsertBefore(ZCNode* AP_Node) { ZCNode* VP_PrevNode=this->mp_PrevNode; JoinNode(VP_PrevNode, AP_Node); JoinNode(AP_Node , this ); }/* inline void InsertBefore(ZCNode* AP_Node)*/ inline void InsertAfter(ZCNode* AP_Node) { ZCNode* VP_NextNode=this->mp_NextNode; JoinNode(this , AP_Node ); JoinNode(AP_Node, VP_NextNode); }/* inline void InsertAfter(ZCNode* AP_Node)*/ inline static void JoinNode(ZCNode* AP_Before, ZCNode* AP_After) { AP_Before->mp_NextNode=AP_After ; AP_After ->mp_PrevNode=AP_Before; }/* inline static void JoinNode(ZCNode* AP_Before, ZCNode* AP_After)*/ inline static void MakeRing(ZCNode* AP_Head, ZCNode* AP_Tail) { AP_Head->mp_PrevNode=AP_Tail; AP_Tail->mp_NextNode=AP_Head; }/* inline static void MakeRing(ZCNode* AP_Head, ZCNode* AP_Tail)*/ ZCNode() { mp_NextNode = mp_PrevNode = mp_LeftNode = mp_RighNode = mp_HighNode = 0; mi_Balance = 0; }/* ZCNode()*/ ZCNode(const ZCNode& rhs) { mp_NextNode = mp_PrevNode = mp_LeftNode = mp_RighNode = mp_HighNode = 0; mi_Balance = 0; }/* ZCNode(const ZCNode& rhs)*/ ZCNode& operator=(const ZCNode& rhs) { // AVL 상태를 해칠 수 있기 때문에 아무 짓도 하지 않는다. return *this; }/* ZCNode& operator=(const ZCNode& rhs)*/ /*private:*/ public : ~ZCNode() { mp_NextNode = mp_PrevNode = mp_LeftNode = mp_RighNode = mp_HighNode = 0; mi_Balance = 0; }/* ~ZCNode()*/ ZCNode* GetNextPrevPtr(TypeSize AL_FarNum) // AL_FarNum 은 0 이거나 음수일 수 있다. { ZCNode* VP_TmpNode=this; if(AL_FarNum>=0) { while(--AL_FarNum>=0) VP_TmpNode=VP_TmpNode->mp_NextNode; /*end while*/ } else /* AL_FarNum<0 인 경우. */ { while(++AL_FarNum<=0) VP_TmpNode=VP_TmpNode->mp_PrevNode; /*end while*/ } //else /* AL_FarNum<0 인 경우. */ return VP_TmpNode; }/* ZCNode* GetNextPrevPtr(TypeSize AL_FarNum)*/ const ZCNode* GetNextPrevPtr(TypeSize AL_FarNum) const { ZCNode* VP_TmpNode=const_cast(this); /* 이 함수는 뒤에 const keyword 가 붙어 있는데 이것 때문에 this pointer 는 상수 포인터로 간주된다. 윗줄에서 이 this 포인터를 비상수 포인터로 먼저 형변환하였다. ZCNode* VP_TmpNode=const_castthis; 라 하면 g++ 2.96 에서는 에러 ###############################################*/ if(AL_FarNum>=0) { while(--AL_FarNum>=0) { VP_TmpNode=VP_TmpNode->mp_NextNode; } } else // AL_FarNum<0 { while(++AL_FarNum<=0) { VP_TmpNode=VP_TmpNode->mp_PrevNode; } } //else // AL_FarNum<0 return VP_TmpNode; }/* const ZCNode* GetNextPrevPtr(TypeSize AL_FarNum) const*/ ZCNode* GetPrevPtr (){return mp_PrevNode;} ZCNode* GetNextPtr (){return mp_NextNode;} ZCNode* GetLeftPtr (){return mp_LeftNode;} ZCNode* GetRightPtr(){return mp_RighNode;} ZCNode* GetHighPtr (){return mp_HighNode;} const ZCNode* GetPrevPtr () const{return mp_PrevNode;} const ZCNode* GetNextPtr () const{return mp_NextNode;} const ZCNode* GetLeftPtr () const{return mp_LeftNode;} const ZCNode* GetRightPtr() const{return mp_RighNode;} const ZCNode* GetHighPtr () const{return mp_HighNode;} int GetDepthBalance() const { return mi_Balance; }/* int GetDepthBalance() const*/ bool IsFullNode() const { /* 양쪽 노드가 차 있어야 true */ return (mp_LeftNode!=0 && mp_RighNode!=0); }/* bool IsFullNode() const*/ TTypArg GetData() const { return mo_Type; }/* TTypArg GetData() const*/ bool operator==(TTypArg AR_Type) const{return mo_Type==AR_Type;} bool operator> (TTypArg AR_Type) const{return mo_Type> AR_Type;} bool operator< (TTypArg AR_Type) const{return mo_Type< AR_Type;} template static void IterInOrder (ZCNode* AP_Node, TFunctor AO_Functor) { if(AP_Node!=0) { ZCNode::template IterInOrder(AP_Node->mp_LeftNode, AO_Functor); { ZNsMain::ZtCTypeData::GetObjRef(AO_Functor)(AP_Node->mo_Type); } ZCNode::template IterInOrder(AP_Node->mp_RighNode, AO_Functor); }/* if(AP_Node!=0)*/ }/* template static void IterInOrder (ZCNode* AP_Node, TFunctor AO_Functor) */ template static void IterPreOrder(ZCNode* AP_Node, TFunctor AO_Functor) { if(AP_Node!=0) { ZNsMain::ZtCTypeData::GetObjRef(AO_Functor)(AP_Node->mo_Type); ZCNode::template IterPreOrder(AP_Node->mp_LeftNode, AO_Functor); ZCNode::template IterPreOrder(AP_Node->mp_RighNode, AO_Functor); }/* if(AP_Node!=0)*/ }/* template static void IterPreOrder(ZCNode* AP_Node,TFunctor AO_Functor) */ template static void IterPostOrder(ZCNode* AP_Node, TFunctor AO_Functor) { if(AP_Node!=0) { ZCNode::template IterPostOrder(AP_Node->mp_LeftNode, AO_Functor); ZCNode::template IterPostOrder(AP_Node->mp_RighNode, AO_Functor); ZNsMain::ZtCTypeData::GetObjRef(AO_Functor)(AP_Node->mo_Type); }/* if(AP_Node!=0)*/ }/* template static void IterPostOrder(ZCNode* AP_Node, TFunctor AO_Functor) */ template static void IterInOrder (ZCNode* AP_Node, TFunctor AO_Functor, THelpObj AR_HelpObj) /*####################################################################*/ { if(AP_Node!=0) { ZCNode::template IterInOrder (AP_Node->mp_LeftNode, AO_Functor, AR_HelpObj); { ZNsMain::ZtCTypeData:: GetObjRef(AO_Functor)(AP_Node->mo_Type, AR_HelpObj); } ZCNode::template IterInOrder (AP_Node->mp_RighNode, AO_Functor, AR_HelpObj); }/* if(AP_Node!=0)*/ }/* template static void IterInOrder (ZCNode* AP_Node, TFunctor AO_Functor, THelpObj AR_HelpObj) ######################################################################*/ template static void IterPreOrder (ZCNode* AP_Node, TFunctor AO_Functor, THelpObj AR_HelpObj) /*####################################################################*/ { if(AP_Node!=0) { ZNsMain::ZtCTypeData:: GetObjRef(AO_Functor)(AP_Node->mo_Type, AR_HelpObj); ZCNode::template IterPreOrder (AP_Node->mp_LeftNode, AO_Functor, AR_HelpObj); ZCNode::template IterPreOrder (AP_Node->mp_RighNode, AO_Functor, AR_HelpObj); }/* if(AP_Node!=0)*/ }/* template static void IterPreOrder (ZCNode* AP_Node, TFunctor AO_Functor, THelpObj AR_HelpObj) ######################################################################*/ template static void IterPostOrder (ZCNode* AP_Node, TFunctor AO_Functor, THelpObj AR_HelpObj) /*####################################################################*/ { if(AP_Node!=0) { ZCNode::template IterPostOrder ( AP_Node->mp_LeftNode, AO_Functor, AR_HelpObj ); ZCNode::template IterPostOrder ( AP_Node->mp_RighNode, AO_Functor, AR_HelpObj ); ZNsMain::ZtCTypeData:: GetObjRef(AO_Functor)(AP_Node->mo_Type, AR_HelpObj); }/* if(AP_Node!=0)*/ }/* template static void IterPostOrder (ZCNode* AP_Node, TFunctor AO_Functor, THelpObj AR_HelpObj) ######################################################################*/ public: };/* class ZCNode*/ ////////////////////////////////////////////// /************** end class ZCNode ************/ ////////////////////////////////////////////// /*public :*/ protected: ZCNode* mp_RootNode ; ZCNode* mp_HeadNode ; TypeSize ml_NodeSize ; protected: ZCNode* CutEmptyNode(ZCNode* AP_CutNode) { #ifdef _DEBUG if(AP_CutNode->IsFullNode()==true) { // 양쪽 연결 노드 중 어느 한 쪽은 비어 있어야 한다. std::fstream fileout("DEBUG.txt",std::ios::in | std::ios::out | std::ios::app); fileout<IsFullNode()==true)*/ #endif //_DEBUG /* * 7 * * * * * * * 4 8 * * * * * * * * * 2 6 9 * * * * * 1 */ /* 위 예에서 7 을 삭제한다고 생각해 보자 * 그러자면 일단 6 의 트리 연결을 끊는 사전작업을 해두고 * 6 를 7 의 자리로 옮겨야 한다. * CutEmptyNode() 함수는 노드 6 과 같이 * 최소한 어느 한쪽의 연결노드가 비어 있는 노드를 자를 때 쓴다. * 이중 연결 리스트 상태를 그대로 두고 트리 노드 상태만 자른다. */ /*/////////////////////////////////////////////////////////////////////////// ■ ZCNode* VP_ApexNode 는 디폴트로 VP_HighNode 이거나 회전이 이루어진 다음에 다시 꼭지점으로 오게 되는 노드다. 위의 예에서 7 이 삭제되면 6 이 올라와 야 되는데 그러자면 1, 2, 4 에 노드에 회전이 발생해서 2 가 1, 2, 4 의 꼭 지점으로 오게 되는데 이때의 2 가 해당한다. 이 노드의 평형계수가 0 이 되면 상위노드로 순회하면서 평형계수를 바꾸어 주어야 한다. 왜 그런지는 종이에 그려서 확인해보자. ///////////////////////////////////////////////////////////////////////////*/ ZCNode* VP_HighNode=AP_CutNode->mp_HighNode ; ZCNode* VP_ApexNode=VP_HighNode ; if(AP_CutNode->mp_LeftNode==0) { if(AP_CutNode->mp_RighNode==0) { // 양쪽 노드가 다 비어있는 경우 /* VP_HighNode==0 즉 AP_CutNode==mp_RootNode(이때 ml_NodeSize==1) 인 경우는 이중 원형 연결상태를 조정할 때 따질 것이므로 여기서는 다루지 않는다. */ if(AP_CutNode==VP_HighNode->mp_LeftNode) { // VP_HighNode->mi_Balance 이 1 증가 VP_HighNode->mp_LeftNode=0; if(VP_HighNode->mi_Balance==1) { /* * 4 (VP_HighNode) * * * * * * *(AP_CutNode) 3 5 * * * * * 6 */ VP_ApexNode=Balance(VP_HighNode, VP_HighNode->mp_RighNode->mi_Balance); } else { ++VP_HighNode->mi_Balance ; }/* else*/ /* 지금 VP_ApexNode==VP_HighNode 이다. 따라서 VP_HighNode 는 더 상위노드로 옮겨야 합리적이다. */ VP_HighNode=VP_ApexNode->mp_HighNode; } else // AP_CutNode==VP_HighNode->mp_RighNode { // VP_HighNode->mi_Balance 이 1 감소 VP_HighNode->mp_RighNode=0; if(VP_HighNode->mi_Balance==-1) { /* * 4 (VP_HighNode) * * * * * * * 3 5 (AP_CutNode) * * * * * 2 */ VP_ApexNode=Balance(VP_HighNode, VP_HighNode->mp_LeftNode->mi_Balance); } else // VP_HighNode->mi_Balance!=-1 { --VP_HighNode->mi_Balance; }/* else // VP_HighNode->mi_Balance!=-1*/ /* 지금 VP_ApexNode==VP_HighNode 이다. 따라서 VP_HighNode 는 더 상위노드로 옮겨야 합리적이다. */ VP_HighNode=VP_ApexNode->mp_HighNode; }/* else // AP_CutNode==VP_HighNode->mp_RighNode*/ // 지금까지 양쪽 노드가 비어 있는 경우를 다루었다. } else // AP_CutNode->mp_LeftNode==0 && AP_CutNode->mp_RighNode!=0 { // 오른쪽 연결 노드만 있는 경우 if(VP_HighNode==0) // AP_CutNode==mp_RootNode { mp_RootNode=AP_CutNode->mp_RighNode; mp_RootNode->mp_RighNode=0; mp_RootNode->mp_HighNode=0; mp_RootNode->mi_Balance =0; return AP_CutNode; } else if(AP_CutNode==VP_HighNode->mp_LeftNode) { // VP_HighNode->mi_Balance 이 1 증가 /* 7 (VP_HighNode) * * * * * * * 5 (AP_CutNode) * * * * * 6 */ VP_HighNode->mp_LeftNode=AP_CutNode->mp_RighNode; AP_CutNode->mp_RighNode->mp_HighNode=VP_HighNode; if(VP_HighNode->mi_Balance==1) { VP_ApexNode=Balance(VP_HighNode, VP_HighNode->mp_RighNode->mi_Balance); VP_HighNode=VP_ApexNode->mp_HighNode; } else // VP_HighNode->mi_Balance==1 { ++VP_HighNode->mi_Balance ; VP_ApexNode=VP_HighNode ; VP_HighNode=VP_ApexNode->mp_HighNode; }/* else // VP_HighNode->mi_Balance==1*/ } else { // AP_CutNode->mp_LeftNode==0 && // AP_CutNode->mp_RighNode!=0 && // AP_CutNode==VP_HighNode->mp_RighNode // VP_HighNode->mi_Balance 이 1 감소 /* 4 (VP_HighNode) * * * * * * * 5 (AP_CutNode) * * * * * 6 */ VP_HighNode->mp_RighNode=AP_CutNode->mp_RighNode; AP_CutNode->mp_RighNode->mp_HighNode=VP_HighNode; if(VP_HighNode->mi_Balance==-1) { VP_ApexNode=Balance(VP_HighNode, VP_HighNode->mp_LeftNode->mi_Balance); VP_HighNode=VP_ApexNode->mp_HighNode; } else // VP_HighNode->mi_Balance==-1 { --VP_HighNode->mi_Balance ; VP_ApexNode=VP_HighNode ; VP_HighNode=VP_ApexNode->mp_HighNode; }/* else // VP_HighNode->mi_Balance==-1*/ }/* else*/ }/* else*/ } else if(AP_CutNode->mp_RighNode==0) { // AP_CutNode->mp_LeftNode!=0 왼쪽 연결노드만 차있는 경우 if(VP_HighNode==0) // AP_CutNode==mp_RootNode { mp_RootNode=AP_CutNode->mp_LeftNode; mp_RootNode->mp_LeftNode=0; mp_RootNode->mp_HighNode=0; mp_RootNode->mi_Balance =0; return AP_CutNode; } else if(AP_CutNode==VP_HighNode->mp_LeftNode) { // VP_HighNode->mi_Balance 이 1 증가 /* 7 (VP_HighNode) * * * * * * * 5 (AP_CutNode) * * * * * 4 */ VP_HighNode->mp_LeftNode=AP_CutNode->mp_LeftNode; AP_CutNode->mp_LeftNode->mp_HighNode=VP_HighNode; if(VP_HighNode->mi_Balance==1) { VP_ApexNode=Balance(VP_HighNode, VP_HighNode->mp_RighNode->mi_Balance); VP_HighNode=VP_ApexNode->mp_HighNode; } else // VP_HighNode->mi_Balance!=1 { ++VP_HighNode->mi_Balance ; VP_ApexNode=VP_HighNode ; VP_HighNode=VP_ApexNode->mp_HighNode; }/* else // VP_HighNode->mi_Balance!=1*/ } else { // AP_CutNode->mp_RighNode==0 && // AP_CutNode->mp_LeftNode!=0 && // AP_CutNode==VP_HighNode->mp_RighNode // VP_HighNode->mi_Balance 이 1 감소 /* 4 (VP_HighNode) * * * * * * * 6 (AP_CutNode) * * * * * 5 */ VP_HighNode->mp_RighNode=AP_CutNode->mp_LeftNode; AP_CutNode->mp_LeftNode->mp_HighNode=VP_HighNode; if(VP_HighNode->mi_Balance==-1) { VP_ApexNode=Balance(VP_HighNode, VP_HighNode->mp_LeftNode->mi_Balance); VP_HighNode=VP_ApexNode->mp_HighNode; } else // VP_HighNode->mi_Balance==-1 { --VP_HighNode->mi_Balance; VP_ApexNode=VP_HighNode; VP_HighNode=VP_ApexNode->mp_HighNode; }/* else // VP_HighNode->mi_Balance==-1*/ }/* else*/ }/* else*/ /* VP_ApexNode->mi_Balance==0 인 경우 상위노드로 순회하면서 평형계수를 조정하거나 평형을 맞춘다. VP_ApexNode->mi_Balance!=0 이면 순회를 멈춘다. */ while(VP_HighNode!=0 && VP_ApexNode->mi_Balance==0) { if(VP_ApexNode==VP_HighNode->mp_LeftNode) { if(VP_HighNode->mi_Balance==1) { VP_ApexNode=Balance(VP_HighNode, VP_HighNode->mp_RighNode->mi_Balance); } else // VP_HighNode->mi_Balance==1 { VP_ApexNode=VP_HighNode; ++VP_HighNode->mi_Balance; }/* else // VP_HighNode->mi_Balance==1*/ } else // VP_ApexNode==VP_HighNode->mp_RighNode { if(VP_HighNode->mi_Balance==-1) { VP_ApexNode=Balance(VP_HighNode, VP_HighNode->mp_LeftNode->mi_Balance); } else // VP_HighNode->mi_Balance==-1 { VP_ApexNode=VP_HighNode; --VP_HighNode->mi_Balance; }/* else // VP_HighNode->mi_Balance==-1*/ }/* else // VP_ApexNode==VP_HighNode->mp_RighNode*/ VP_HighNode=VP_ApexNode->mp_HighNode; }/* while(VP_HighNode!=0 && VP_ApexNode->mi_Balance==0)*/ return AP_CutNode; }/* ZCNode* CutEmptyNode(ZCNode* AP_CutNode)*/ ZCNode* CutNode(ZCNode* AP_CutNode) { #ifdef _DEBUG if(FindNode(AP_CutNode)==0) { std::fstream fileout("DEBUG.txt",std::ios::in | std::ios::out | std::ios::app); fileout<mi_Balance == 1 이면 AP_CutNode 의 오른쪽 노드에서 가장 왼쪽 노드가 AP_CutNode 위치로 올라오는 것으로 한다. AP_CutNode->mi_Balance == -1 이나 0 이면 AP_CutNode 의 왼쪽 노드에서 가장 오른쪽 노드가 AP_CutNode 위치로 올라오는 것으로 한다. */ if(AP_CutNode==mp_HeadNode && ml_NodeSize==1) { mp_HeadNode=0; mp_RootNode=0; ml_NodeSize=0; return AP_CutNode; } if(AP_CutNode->mp_LeftNode==0 || AP_CutNode->mp_RighNode==0) { CutEmptyNode(AP_CutNode); } else //(AP_CutNode->mp_LeftNode!=0 && AP_CutNode->mp_RighNode!=0) { /*///////////////////////////////////////////////////////////////// ■ CutEmptyNode(AP_CutNode) 멤버 함수는 AP_CutNode 의 트리연결 상태만 끊는다. ■ AP_CutNode->mp_PrevNode 이거나 AP_CutNode->mp_NextNode 인 노드는 왼쪽 노드, 오른쪽 노드 어느 한쪽이 반드시 비어있다. ■ 언뜻 생각하기에 AP_CutNode->mp_PrevNode==AP_CutNode->mp_LeftNode AP_CutNode->mp_NextNode==AP_CutNode->mp_RighNode 라고 생각하기 쉬운데 아래 그림을 보면 그렇지 않다는 것을 알 수 있다. AP_CutNode 를 5 라고 생각해보자. AP_CutNode->mp_NextNode 는 6 인데 AP_CutNode->mp_RighNode 는 7 이다. 5 * * * * 3 7 * * * * * * * * * * * * 2 4 6 8 * * 1 /////////////////////////////////////////////////////////////////*/ ZCNode* VP_TempCut; if(AP_CutNode->mi_Balance<=0) { VP_TempCut=CutEmptyNode(AP_CutNode->mp_PrevNode); } else { VP_TempCut=CutEmptyNode(AP_CutNode->mp_NextNode); } if(AP_CutNode==mp_RootNode) { mp_RootNode=VP_TempCut; }/* if(AP_CutNode==mp_RootNode)*/ // VP_TempCut 와 AP_CutNode 의 위치를 바꾼다. VP_TempCut->mp_HighNode=AP_CutNode->mp_HighNode; VP_TempCut->mp_RighNode=AP_CutNode->mp_RighNode; VP_TempCut->mp_LeftNode=AP_CutNode->mp_LeftNode; VP_TempCut->mi_Balance =AP_CutNode->mi_Balance ; if(AP_CutNode->mp_HighNode!=0) { if(AP_CutNode->mp_HighNode->mp_LeftNode==AP_CutNode) AP_CutNode->mp_HighNode->mp_LeftNode=VP_TempCut; else AP_CutNode->mp_HighNode->mp_RighNode=VP_TempCut; //else } if(AP_CutNode->mp_LeftNode!=0) { AP_CutNode->mp_LeftNode->mp_HighNode=VP_TempCut; } if(AP_CutNode->mp_RighNode!=0) { AP_CutNode->mp_RighNode->mp_HighNode=VP_TempCut; }/* if(AP_CutNode->mp_RighNode!=0)*/ }/* else // AP_CutNode->mp_LeftNode!=0 && AP_CutNode->mp_RighNode!=0*/ // 이중 원형 상태를 끊는다. if(AP_CutNode==mp_HeadNode) { // ml_NodeSize==1 인 경우는 위에서 이미 조사했다. ZCNode* VP_EndNode=mp_HeadNode->GetPrevPtr(); mp_HeadNode =mp_HeadNode->GetNextPtr(); ZCNode::MakeRing(mp_HeadNode, VP_EndNode) ; } else { ZCNode::JoinNode(AP_CutNode->GetPrevPtr(), AP_CutNode->GetNextPtr()); }/* else*/ --ml_NodeSize; return AP_CutNode; }/* ZCNode* CutNode(ZCNode* AP_CutNode)*/ /*private:*/ public : ZtCObjAVL() { Init(); mp_RootNode =0 ; mp_HeadNode =0 ; ml_NodeSize =0 ; }/* ZtCObjAVL()*/ ZtCObjAVL(const ZtCObjAVL& rhs) { Init(); mp_RootNode =0 ; mp_HeadNode =0 ; ml_NodeSize =0 ; if(rhs.mp_HeadNode==0) return ; ZCNode* VP_Temp=rhs.mp_HeadNode ; ZCNode* VP_Tail=rhs.mp_HeadNode->mp_PrevNode; do /**/ { AddData(VP_Temp->mo_Type); if(VP_Temp==VP_Tail) return; VP_Temp=VP_Temp->mp_NextNode; } while(true); }/* ZtCObjAVL(const ZtCObjAVL& rhs)*/ ZtCObjAVL& operator=(const ZtCObjAVL& rhs) { if(this==&rhs) {return ;} DeleteAll(); if(rhs.mp_HeadNode==0){ return; } ZCNode* VP_Temp=rhs.mp_HeadNode; ZCNode* VP_Tail=rhs.mp_HeadNode->mp_PrevNode; do /**/ { AddData(VP_Temp->mo_Type); if(VP_Temp==VP_Tail) return *this; VP_Temp=VP_Temp->mp_NextNode; } while(true); return *this; }/* ZtCObjAVL& operator=(const ZtCObjAVL& rhs)*/ ~ZtCObjAVL() { DeleteAll(); }/* ~ZtCObjAVL()*/ void Init() { // add initial codes here }/* void Init()*/ bool operator()(TTypArg AR_Type) { return AddData(AR_Type); }/* bool operator()(TTypArg AR_Type)*/ inline ZCNode* GetRootNodePtr() { return mp_RootNode; }/* inline ZCNode* GetRootNodePtr()*/ inline const ZCNode* GetRootNodePtr() const { return mp_RootNode; }/* inline const ZCNode* GetRootNodePtr() const*/ inline ZCNode* GetHeadNodePtr() { return mp_HeadNode; }/* inline ZCNode* GetHeadNodePtr()*/ inline const ZCNode* GetHeadNodePtr() const { return mp_HeadNode; }/* inline inline const ZCNode* GetHeadNodePtr() const*/ inline ZCNode* GetTailNodePtr() { return mp_HeadNode==0 ? 0 : mp_HeadNode->mp_PrevNode ; }/* inline ZCNode* GetTailNodePtr()*/ inline const ZCNode* GetTailNodePtr() const { return mp_HeadNode==0 ? 0 : mp_HeadNode->mp_PrevNode ; }/* inline const ZCNode* GetTailNodePtr() const*/ ZCNode* GetNodePtr(TypeSize AL_Index) { #ifdef _DEBUG if(AL_Index<1 || AL_Index>ml_NodeSize) { std::fstream fileout("DEBUG.txt",std::ios::out | std::ios::app); fileout<ml_NodeSize)*/ #endif // _DEBUG TypeSize VI_LeftDistance =AL_Index-1 ; TypeSize VI_RightDistance=ml_NodeSize-AL_Index+1; TypeSize VI_ShortDistance=(VI_LeftDistance<=VI_RightDistance ? VI_LeftDistance : -VI_RightDistance); return (static_cast(mp_HeadNode->GetNextPrevPtr(VI_ShortDistance))); }/* ZCNode* GetNodePtr(TypeSize AL_Index)*/ const ZCNode* GetNodePtr(TypeSize AL_Index) const // or 'ZCNode const * const GetNodePtr(TypeSize AL_Index) const' { #ifdef _DEBUG if(AL_Index<1 || AL_Index>ml_NodeSize) { std::fstream fileout("DEBUG.txt",std::ios::out | std::ios::app); fileout<ml_NodeSize)*/ #endif //_DEBUG TypeSize VI_LeftDistance =AL_Index-1 ; TypeSize VI_RightDistance=ml_NodeSize-AL_Index+1; TypeSize VI_ShortDistance=(VI_LeftDistance<=VI_RightDistance ? VI_LeftDistance : -VI_RightDistance); return mp_HeadNode->GetNextPrevPtr(VI_ShortDistance); }/* const ZCNode* GetNodePtr(TypeSize AL_Index) const*/ ZtCObjAVL& Minus(const ZtCObjAVL& rhs) { if(this==&rhs || mp_HeadNode==0 || rhs.mp_HeadNode==0) { return *this; } ZCNode* VP_Temp=rhs.mp_HeadNode ; ZCNode* VP_Tail=rhs.mp_HeadNode->mp_PrevNode; do /**/ { DeleteData(VP_Temp->mo_Type); if(VP_Temp==VP_Tail) return *this; VP_Temp=VP_Temp->mp_NextNode; } while(true); return *this; }/* ZtCObjAVL& Minus(const ZtCObjAVL& rhs)*/ void DeleteNode(ZCNode* AP_DelNode) { #ifdef _DEBUG if(FindNode(AP_DelNode)==0) { std::fstream fileout("DEBUG.txt", std::ios::in | std::ios::out | std::ios::app); fileout<mp_NextNode; delete VP_NodeCut; VP_NodeCut=VP_NodeNext; }/* __for0(TypeSize, i, ml_NodeSize)*/ ml_NodeSize =0; mp_HeadNode =0; mp_RootNode =0; }/* if(mp_HeadNode!=0)*/ }/* void DeleteAll()*/ void clear() { this->DeleteAll(); }/* void clear()*/ template void IterNode(TFunctor AO_Functor) const { if(mp_HeadNode==0) return ; const ZCNode* VP_Temp=mp_HeadNode ; const ZCNode* VP_Tail=mp_HeadNode->mp_PrevNode; do /*#####*/ { /* 아래 줄에서 VP_Temp->mo_Type 을 받는 인수는 복사로 받거나 const Type& 으로 받아야 한다. */ ZNsMain::ZtCTypeData:: GetObjRef(AO_Functor)(VP_Temp->mo_Type); if(VP_Temp==VP_Tail) return; VP_Temp=VP_Temp->mp_NextNode; } while(true); }/* template void IterNode(TFunctor AO_Functor) const */ template void IterNode(TFunctor AO_Functor, TypeHelp AO_HelpType) const { if(mp_HeadNode==0) return ; const ZCNode* VP_Temp=mp_HeadNode ; const ZCNode* VP_Tail=mp_HeadNode->mp_PrevNode; do /*#####*/ { /* 아래 줄에서 VP_Temp->mo_Type 을 받는 인수는 복사로 받거나 const Type& 으로 받아야 한다. */ ZNsMain::ZtCTypeData:: GetObjRef(AO_Functor)(VP_Temp->mo_Type, AO_HelpType) ; if(VP_Temp==VP_Tail) return; VP_Temp=VP_Temp->mp_NextNode; } while(true); }/* template void IterNode(TFunctor AO_Functor, TypeHelp AO_HelpType) const */ template void IterNodeRef(TFunctor AO_Functor, TypeHelp& AR_HelpType) const { if(mp_HeadNode==0) return ; const ZCNode* VP_Temp=mp_HeadNode ; const ZCNode* VP_Tail=mp_HeadNode->mp_PrevNode; do /*#####*/ { ZNsMain::ZtCTypeData:: GetObjRef(AO_Functor)(VP_Temp->mo_Type, AR_HelpType) ; if(VP_Temp==VP_Tail) return; VP_Temp=VP_Temp->mp_NextNode; } while(true); }/* template void IterNodeRef(TFunctor AO_Functor, TypeHelp& AR_HelpType) const */ template void IterInOrder (TFunctor AO_Functor) const{ ZCNode::template IterInOrder (mp_RootNode, AO_Functor);} template void IterPreOrder (TFunctor AO_Functor) const{ ZCNode::template IterPreOrder (mp_RootNode, AO_Functor);} template void IterPostOrder(TFunctor AO_Functor) const{ ZCNode::template IterPostOrder(mp_RootNode, AO_Functor);} template void IterInOrder (TFunctor AO_Functor, THelpObj AR_HelpObj) const{ ZCNode::template IterInOrder (mp_RootNode, AO_Functor, AR_HelpObj);} template void IterPreOrder (TFunctor AO_Functor, THelpObj AR_HelpObj) const{ ZCNode::template IterPreOrder (mp_RootNode, AO_Functor, AR_HelpObj);} template void IterPostOrder(TFunctor AO_Functor, THelpObj AR_HelpObj) const{ ZCNode::template IterPostOrder(mp_RootNode, AO_Functor, AR_HelpObj);} TypeSize GetSize() const{return ml_NodeSize;} TypeSize size () const{return ml_NodeSize;} bool IsEmpty() const { return mp_HeadNode==0; }/* bool IsEmpty() const*/ bool AddData(TTypArg AR_Type) { if(mp_RootNode==0) { mp_RootNode=new ZCNode ; mp_HeadNode=mp_RootNode ; ZCNode::MakeRing(mp_HeadNode, mp_HeadNode); mp_RootNode->mo_Type=AR_Type; ++ml_NodeSize; return true; } else // mp_RootNode!=0 { return AddData(*mp_RootNode, AR_Type)!=ZNsMain::ZNsEnum::ZEAVL_INSERT_NONE ; }/* else // mp_RootNode!=0*/ }/* bool AddData(TTypArg AR_Type)*/ template ZCNode* AddKey(TKey AR_Key) { if(mp_RootNode==0) { mp_RootNode=new ZCNode ; mp_HeadNode=mp_RootNode; ZCNode::MakeRing(mp_HeadNode, mp_HeadNode); mp_RootNode->mo_Type=AR_Key; ++ml_NodeSize; return mp_RootNode; /*///////////////////*/ } else // mp_RootNode==0 { ZCNode* VP_CNode=0; // 삽입된 링크를 대입받는다. AddKey(*mp_RootNode, AR_Key, RR(VP_CNode)); return VP_CNode; /*////////////////////////////*/ }/* else // mp_RootNode==0*/ }/* template ZCNode* AddKey(TKey AR_Key) */ ZCNode* UpdateData(TTypArg AR_Type, TTypArg AR_NewType) { /* AR_Type 값을 가지고 있는 노드를 찾아내어 AR_NewType 로 업데이트한다. AR_Type 값을 가지고 있는 노드를 찾아내어 잘라낸 다음, AR_NewType 로 업데이트하고 다시 삽입한다. */ ZCNode* VP_FindNode=FindData(AR_Type); if(VP_FindNode==0) return 0; ///////// (void)CutNode(VP_FindNode); VP_FindNode->mo_Type=AR_NewType; // 같은 값을 가진 노드가 있어서 삽입에 실패했다면, 잘라낸 노드를 지워버린다. const ZNsMain::ZNsEnum::ZEAVL_INSERT CE_EAVL_INSERT = AddNode(*mp_RootNode, *VP_FindNode); if(CE_EAVL_INSERT==ZNsMain::ZNsEnum::ZEAVL_INSERT_NONE) { delete VP_FindNode; return 0; }/* if(CE_EAVL_INSERT==ZNsMain::ZNsEnum::ZEAVL_INSERT_NONE)*/ return VP_FindNode; }/* ZCNode* UpdateData(TTypArg AR_Type, TTypArg AR_NewType)*/ template ZCNode* UpdateKey(TKey AR_Key, TKey AR_NewKey) { /* AR_Key 값을 가지고 있는 노드를 찾아내어 AR_NewKey 로 업데이트한다. AR_Key 값을 가지고 있는 노드를 찾아내어 잘라낸 다음, AR_NewKey 로 업데이트하고 다시 삽입한다. */ ZCNode* VP_FindNode=FindKey(AR_Key); if(VP_FindNode==0) return 0; //////////// (void)CutNode(VP_FindNode); VP_FindNode->mo_Type=AR_NewKey; // 같은 키 값을 가진 노드가 있어서 삽입에 실패했다면, 잘라낸 노드를 지워버린다. const ZNsMain::ZNsEnum::ZEAVL_INSERT CE_EAVL_INSERT = AddNode(*mp_RootNode, *VP_FindNode) ; if(CE_EAVL_INSERT==ZNsMain::ZNsEnum::ZEAVL_INSERT_NONE) { delete VP_FindNode; return 0; }/* if(CE_EAVL_INSERT==ZNsMain::ZNsEnum::ZEAVL_INSERT_NONE)*/ return VP_FindNode; }/* template ZCNode* UpdateKey(TKey AR_Key, TKey AR_NewKey) */ TypeSize FindNode /*#######################*/ ( const ZCNode* AP_SearchNode , TypeSize AL_FirstFindIndex =1, bool AB_DoFindFromFront=true ) const /*#########################################*/ { /* 맨 앞 링크부터 이중 원형 상태를 따라서 순회하면서 찾는다. 이 경우 AVL 트리 상태로 순회하면서 찾는 것이 좋으나 DEBUG 용 함수로 사용하고 그냥 내버려 둔다. */ const bool CB_IsBad = ( mp_HeadNode ==0 || AL_FirstFindIndex< 1 || AL_FirstFindIndex> ml_NodeSize ); if(CB_IsBad) { return 0; } TypeSize VL_FindIndex= AL_FirstFindIndex ; ZCNode* VP_TempNode = const_cast ( GetNodePtr(AL_FirstFindIndex) ) ; if(AB_DoFindFromFront==true) { do /**/ { if(VP_TempNode ==AP_SearchNode) return VL_FindIndex; if(VL_FindIndex==ml_NodeSize ) return 0 ; VP_TempNode=VP_TempNode->mp_NextNode; ++VL_FindIndex; } while(true); } else // AB_DoFindFromFront!=true { do /**/ { if(VP_TempNode ==AP_SearchNode) return VL_FindIndex; if(VL_FindIndex==1 ) return 0 ; VP_TempNode=VP_TempNode->mp_PrevNode; --VL_FindIndex; } while(true); }/* else // AB_DoFindFromFront!=true*/ }/* TypeSize FindNode ########################### ( const ZCNode* AP_SearchNode , TypeSize AL_FirstFindIndex =1, bool AB_DoFindFromFront=true ) const #########################################*/ ZCNode* FindData(TTypArg AR_Type) const { /* mp_RootNode 부터 하위 노드로 순회하면서 mo_Type 를 가지는 노드를 찾는다. */ return FindData(AR_Type, mp_RootNode); }/* ZCNode* FindData(TTypArg AR_Type) const*/ ZCNode* FindData(TTypArg AR_Type, ZCNode* AP_StartNode) const { /* AP_StartNode 부터 하위 노드로 순회하면서 mo_Type 를 가지는 노드를 찾는다. */ #ifdef _DEBUG if(AP_StartNode!=0 && FindNode(AP_StartNode)==0) { std::fstream fileout("DEBUG.txt",std::ios::out | std::ios::app); fileout<mo_Type==AR_Type) { return AP_StartNode; } else if(AP_StartNode->mo_Type>AR_Type) { AP_StartNode=AP_StartNode->mp_LeftNode; } else { AP_StartNode=AP_StartNode->mp_RighNode; }/* else*/ }/* while(AP_StartNode!=0)*/ return 0; }/* ZCNode* FindData(TTypArg AR_Type, ZCNode* AP_StartNode) const*/ bool DeleteData(TTypArg AR_Type) { ZCNode* VP_FindNode=FindData(AR_Type); if(VP_FindNode) { DeleteNode(VP_FindNode); return true; }/* if(VP_FindNode)*/ return false; }/* bool DeleteData(TTypArg AR_Type)*/ template bool DeleteKey(TKey AR_Key) { /*//////////////////////////////////////////////// ■ cf) bool DeleteData(TTypArg AR_Type) AR_Key 가 AR_Type 보다 작은 크기의 object 라면 아래 FindKey() 함수에서 성능향상이 있는 것이다. ////////////////////////////////////////////////*/ ZCNode* VP_FindNode=FindKey(AR_Key); if(VP_FindNode) { DeleteNode(VP_FindNode); return true; }/* if(VP_FindNode)*/ return false; }/* template bool DeleteKey(TKey AR_Key) */ template const ZCNode* FindKey(TKey AR_Key, ZCNode* AP_StartNode) const { /*////////////////////////////////////////////////////////////////////////////// ■ AP_StartNode 부터 하위 노드로 순회하면서 AR_Key 를 가지는 노드를 찾는다. FindData(TTypArg AR_Type,ZCNode* AP_StartNode) 같은 함수는 찾으려는 object 가 AR_Type 이 크기가 큰 object 일 수 있는데, 이를 피하기 위해 그 보다 작은 크기 의 자료형 TKey 로부터 해당 데이타를 찾는다. 물론 mo_Type 과 TKey 에 대한 비 교 연산이 정의되어 있어야 한다. //////////////////////////////////////////////////////////////////////////////*/ #ifdef _DEBUG if(AP_StartNode!=0 && FindNode(AP_StartNode)==0) { std::fstream fileout("DEBUG.txt",std::ios::out | std::ios::app); fileout< const ZCNode* ZtCObjAVL::FindKey(TKey AR_Key,ZCNode* AP_StartNode) const'"<mo_Type==AR_Key) return AP_StartNode; if(AP_StartNode->mo_Type>AR_Key) AP_StartNode=AP_StartNode->mp_LeftNode; else AP_StartNode=AP_StartNode->mp_RighNode; //else }/* while(AP_StartNode!=0)*/ return 0; }/* template const ZCNode* FindKey(TKey AR_Key, ZCNode* AP_StartNode) const */ template ZCNode* FindKey(TKey AR_Key, ZCNode* AP_StartNode) { /*////////////////////////////////////////////////////////////////////////////// ■ AP_StartNode 부터 하위 노드로 순회하면서 AR_Key 를 가지는 노드를 찾는다. FindData(TTypArg AR_Type,ZCNode* AP_StartNode) 같은 함수는 찾으려는 object 가 AR_Type 이 크기가 큰 object 일 수 있는데, 이를 피하기 위해 그 보다 작은 크기 의 자료형 TKey 로부터 해당 데이타를 찾는다. 물론 mo_Type 과 TKey 에 대한 비 교 연산이 정의되어 있어야 한다. //////////////////////////////////////////////////////////////////////////////*/ #ifdef _DEBUG if(AP_StartNode!=0 && FindNode(AP_StartNode)==0) { std::fstream fileout("DEBUG.txt",std::ios::out | std::ios::app); fileout< ZCNode* ZtCObjAVL::FindKey(TKey AR_Key,ZCNode* AP_StartNode)'"<mo_Type==AR_Key) return AP_StartNode; if(AP_StartNode->mo_Type>AR_Key) AP_StartNode=AP_StartNode->mp_LeftNode; else AP_StartNode=AP_StartNode->mp_RighNode; //else }/* while(AP_StartNode!=0)*/ return 0; }/* template ZCNode* FindKey(TKey AR_Key, ZCNode* AP_StartNode) */ template const ZCNode* FindKey(TKey AR_Key) const { return FindKey(AR_Key, mp_RootNode); }/* template const ZCNode* FindKey(TKey AR_Key) const */ template ZCNode* FindKey(TKey AR_Key) { return FindKey(AR_Key,mp_RootNode); }/* template ZCNode* FindKey(TKey AR_Key) */ const ZCNode* find(TTypArg AR_Type) const // for stl { return FindData(AR_Type,mp_RootNode); }/* const ZCNode* find(TTypArg AR_Type) const*/ const ZCNode* end() const // for stl { return 0; }/* const ZCNode* end() const*/ bool erase(TTypArg AR_Type) { return DeleteData(AR_Type); }/* bool erase(TTypArg AR_Type)*/ #ifdef _DEBUG void DEBUG_WriteNodeStatus() { std::fstream fileout("DEBUG.txt",std::ios::out | std::ios::app); fileout<0 ? TypeCompare::Exec(AR_Node.GetData(), AR_Type) : ZECompareResult_Equal ); ////////////////////////// const bool CB_IsEqual = ( TypeCompare::ZEUseCompareObj>0 ? VI_CompareResultCode==ZECompareResult_Equal : AR_Node.GetData() ==AR_Type ); /*///////////////////*/ #endif #if(_CODE_OLD_) if(AR_Node.GetData()==AR_Type) #else if(CB_IsEqual) #endif { /*/////////////////////////////////////////////////////////////////// ■ 기초 클래스 TTypBase 에서 OnEqual 멤버를 정의할 때, ZCNode 자료형을 모른다. 따라서 템플릿 멤버로 정의해야 한다. template void TTypBase ::OnEqual(TTypArg AR_Data,TNode* AP_Node) { } ///////////////////////////////////////////////////////////////////*/ this->TTypBase::OnEqual(AR_Type, &AR_Node); return ZNsMain::ZNsEnum::ZEAVL_INSERT_NONE; }/* if(CB_IsEqual)*/ const bool CB_IsLess = ( TypeCompare::ZEUseCompareObj>0 ? VI_CompareResultCodemp_HighNode=&AR_Node; if(++AR_Node.mi_Balance==0) return ZNsMain::ZNsEnum::ZEAVL_INSERT_OK; else return ZNsMain::ZNsEnum::ZEAVL_INSERT_RIGHT; } else // AR_Node.mp_RighNode!=0 { int VI_AddState = AddData(*AR_Node.mp_RighNode, AR_Type); if(VI_AddState==ZNsMain::ZNsEnum::ZEAVL_INSERT_NONE) { return ZNsMain::ZNsEnum::ZEAVL_INSERT_NONE; } if(VI_AddState!=ZNsMain::ZNsEnum::ZEAVL_INSERT_OK) { if(AR_Node.mi_Balance==1) { Balance(&AR_Node, VI_AddState); return ZNsMain::ZNsEnum::ZEAVL_INSERT_OK; } else if(++AR_Node.mi_Balance==0) { return ZNsMain::ZNsEnum::ZEAVL_INSERT_OK ; } else { return ZNsMain::ZNsEnum::ZEAVL_INSERT_RIGHT; } }/* if(VI_AddState!=ZNsMain::ZNsEnum::ZEAVL_INSERT_OK)*/ return ZNsMain::ZNsEnum::ZEAVL_INSERT_OK; }/* else // AR_Node.mp_RighNode!=0*/ }/* if(CB_IsLess)*/ // AR_Node.mo_Type>AR_Type) if(AR_Node.mp_LeftNode==0) { ZCNode* VP_Temp=JoinBefore(&AR_Node, AR_Type); AR_Node.mp_LeftNode =VP_Temp ; VP_Temp->mp_HighNode=&AR_Node; if(--AR_Node.mi_Balance==0) return ZNsMain::ZNsEnum::ZEAVL_INSERT_OK ; else return ZNsMain::ZNsEnum::ZEAVL_INSERT_LEFT; } else // AR_Node.mp_RighNode!=0 { int VI_AddState = AddData(*AR_Node.mp_LeftNode, AR_Type); if(VI_AddState==ZNsMain::ZNsEnum::ZEAVL_INSERT_NONE) { return ZNsMain::ZNsEnum::ZEAVL_INSERT_NONE; } if(VI_AddState!=ZNsMain::ZNsEnum::ZEAVL_INSERT_OK) { if(AR_Node.mi_Balance==-1) { Balance(&AR_Node,VI_AddState); return ZNsMain::ZNsEnum::ZEAVL_INSERT_OK; } else if(--AR_Node.mi_Balance==0) { return ZNsMain::ZNsEnum::ZEAVL_INSERT_OK ; } else { return ZNsMain::ZNsEnum::ZEAVL_INSERT_LEFT; } }/* if(VI_AddState!=ZNsMain::ZNsEnum::ZEAVL_INSERT_OK)*/ return ZNsMain::ZNsEnum::ZEAVL_INSERT_OK; }/* else // AR_Node.mp_RighNode!=0*/ }/* int AddData(ZCNode& AR_Node, TTypArg AR_Type)*/ template int AddKey(ZCNode& AR_Node, TKey AR_Key, ZCNode*& APR_CNode) { using ZNsMain::ZNsEnum::ZECompareResult_Equal; #if(_CODE_NEW_) int VI_CompareResultCode = ( TypeCompare::ZEUseCompareObj>0 ? TypeCompare::Exec(AR_Node.GetData(), AR_Key) : ZECompareResult_Equal ); ////////////////////////// const bool CB_IsEqual = ( TypeCompare::ZEUseCompareObj>0 ? VI_CompareResultCode==ZECompareResult_Equal : AR_Node.GetData() ==AR_Key ); /////////////////////// #endif #if(_CODE_OLD_) if(AR_Node.GetData()==AR_Key) #else if(CB_IsEqual) #endif { this->TTypBase::OnEqualKey(AR_Key, &AR_Node); return ZNsMain::ZNsEnum::ZEAVL_INSERT_NONE; }/* if(CB_IsEqual)*/ const bool CB_IsLess = ( TypeCompare::ZEUseCompareObj>0 ? VI_CompareResultCodemp_HighNode=&AR_Node; if(++AR_Node.mi_Balance==0) return ZNsMain::ZNsEnum::ZEAVL_INSERT_OK; else return ZNsMain::ZNsEnum::ZEAVL_INSERT_RIGHT; //else } else /* AR_Node.mp_RighNode!=0 */ { int VI_AddState = AddKey (*AR_Node.mp_RighNode, AR_Key, APR_CNode); if(VI_AddState==ZNsMain::ZNsEnum::ZEAVL_INSERT_NONE) { return ZNsMain::ZNsEnum::ZEAVL_INSERT_NONE; } if(VI_AddState!=ZNsMain::ZNsEnum::ZEAVL_INSERT_OK) { if(AR_Node.mi_Balance==1) { Balance(&AR_Node, VI_AddState); return ZNsMain::ZNsEnum::ZEAVL_INSERT_OK; } else if(++AR_Node.mi_Balance==0) { return ZNsMain::ZNsEnum::ZEAVL_INSERT_OK; } else { return ZNsMain::ZNsEnum::ZEAVL_INSERT_RIGHT; }/* else*/ }/* if(VI_AddState!=ZNsMain::ZNsEnum::ZEAVL_INSERT_OK)*/ return ZNsMain::ZNsEnum::ZEAVL_INSERT_OK; }/* else // AR_Node.mp_RighNode!=0 */ }/* if(CB_IsLess)*/ // AR_Node.mo_Type>AR_Type if(AR_Node.mp_LeftNode==0) { APR_CNode=JoinBeforeKey(&AR_Node, AR_Key); AR_Node. mp_LeftNode=APR_CNode; APR_CNode->mp_HighNode=&AR_Node ; if(--AR_Node.mi_Balance==0) return ZNsMain::ZNsEnum::ZEAVL_INSERT_OK; else return ZNsMain::ZNsEnum::ZEAVL_INSERT_LEFT; //else } else /* AR_Node.mp_RighNode!=0 */ { int VI_AddState = AddKey (*AR_Node.mp_LeftNode, AR_Key, APR_CNode); if(VI_AddState==ZNsMain::ZNsEnum::ZEAVL_INSERT_NONE) { return ZNsMain::ZNsEnum::ZEAVL_INSERT_NONE; } if(VI_AddState!=ZNsMain::ZNsEnum::ZEAVL_INSERT_OK) { if(AR_Node.mi_Balance==-1) { Balance(&AR_Node, VI_AddState); return ZNsMain::ZNsEnum::ZEAVL_INSERT_OK; } else if(--AR_Node.mi_Balance==0) { return ZNsMain::ZNsEnum::ZEAVL_INSERT_OK; } else { return ZNsMain::ZNsEnum::ZEAVL_INSERT_LEFT; }/* else*/ }/* if(VI_AddState!=ZNsMain::ZNsEnum::ZEAVL_INSERT_OK)*/ return ZNsMain::ZNsEnum::ZEAVL_INSERT_OK; }/* else // AR_Node.mp_RighNode!=0 */ }/* template int AddKey(ZCNode& AR_Node, TKey AR_Key, ZCNode*& APR_CNode) */ int AddNode(ZCNode& AR_Node, ZCNode& AR_AddNode) { using ZNsMain::ZNsEnum::ZECompareResult_Equal ; #if(_CODE_NEW_) int VI_CompareResultCode = ( TypeCompare::ZEUseCompareObj>0 ? TypeCompare::Exec (AR_Node.GetData(), AR_AddNode.GetData()) : ZECompareResult_Equal ); ////////////////////////// const bool CB_IsEqual = ( TypeCompare::ZEUseCompareObj>0 ? VI_CompareResultCode==ZECompareResult_Equal : AR_Node.GetData() ==AR_AddNode.GetData() ) ; /////////////////////// #endif #if(_CODE_OLD_) if(AR_Node.GetData()==AR_AddNode.GetData()) #else if(CB_IsEqual) #endif { this->TTypBase::OnEqual(AR_AddNode.GetData(), &AR_Node); return ZNsMain::ZNsEnum::ZEAVL_INSERT_NONE; }/* if(CB_IsEqual)*/ const bool CB_IsLess = ( TypeCompare::ZEUseCompareObj>0 ? VI_CompareResultCodeAR_Type) if(AR_Node.mp_LeftNode==0) { (void)JoinBefore(&AR_Node, &AR_AddNode); AR_Node. mp_LeftNode=&AR_AddNode; AR_AddNode.mp_HighNode=&AR_Node ; if(--AR_Node.mi_Balance==0) return ZNsMain::ZNsEnum::ZEAVL_INSERT_OK; else return ZNsMain::ZNsEnum::ZEAVL_INSERT_LEFT; //else } else /* AR_Node.mp_RighNode!=0 */ { int VI_AddState = AddNode(*AR_Node.mp_LeftNode, AR_AddNode); if(VI_AddState==ZNsMain::ZNsEnum::ZEAVL_INSERT_NONE) { return ZNsMain::ZNsEnum::ZEAVL_INSERT_NONE; } if(VI_AddState!=ZNsMain::ZNsEnum::ZEAVL_INSERT_OK) { if(AR_Node.mi_Balance==-1) { Balance(&AR_Node,VI_AddState); return ZNsMain::ZNsEnum::ZEAVL_INSERT_OK; } else if(--AR_Node.mi_Balance==0) { return ZNsMain::ZNsEnum::ZEAVL_INSERT_OK; } else { return ZNsMain::ZNsEnum::ZEAVL_INSERT_LEFT; }/* else*/ }/* if(VI_AddState!=ZNsMain::ZNsEnum::ZEAVL_INSERT_OK)*/ return ZNsMain::ZNsEnum::ZEAVL_INSERT_OK; }/* else // AR_Node.mp_RighNode!=0 */ }/* int AddNode(ZCNode& AR_Node, ZCNode& AR_AddNode)*/ inline ZCNode* JoinBefore(ZCNode* AP_StdNode, ZCNode* AP_Insert) { /* AP_StdNode 앞에 AP_Insert 를 삽입 */ #ifdef _DEBUG /* AP_StdNode 는 현재의 리스트에 속해 있어야 하며 */ /* AP_Insert 는 현재의 리스트에 속해 있지 않아야 한다. */ if(FindNode(AP_StdNode)==0 || FindNode(AP_Insert)!=0) { std::fstream fileout("DEBUG.txt",std::ios::out | std::ios::app); fileout<InsertBefore(AP_Insert), ++ml_NodeSize); return (AP_StdNode==mp_HeadNode) ? mp_HeadNode=AP_Insert : AP_Insert ; }/* inline ZCNode* JoinBefore(ZCNode* AP_StdNode, ZCNode* AP_Insert)*/ inline ZCNode* JoinBefore(ZCNode* AP_StdNode, TTypArg AR_Type) { ZCNode* VP_NewNode=new ZCNode; #if(_CODE_NEW_) if(TypeMoveObj::ZEUseMoveObj>0) TypeMoveObj::Exec(VP_NewNode->mo_Type, AR_Type); else #endif VP_NewNode->mo_Type=AR_Type; return JoinBefore(AP_StdNode, VP_NewNode); }/* inline ZCNode* JoinBefore(ZCNode* AP_StdNode, TTypArg AR_Type)*/ template inline ZCNode* JoinBeforeKey(ZCNode* AP_StdNode, TKey AR_Key) { ZCNode* VP_NewNode=new ZCNode; #if(_CODE_NEW_) if(TypeMoveObj::ZEUseMoveObj>0) TypeMoveObj::Exec(VP_NewNode->mo_Type, AR_Key); else #endif VP_NewNode->mo_Type=AR_Key; return JoinBefore(AP_StdNode, VP_NewNode); }/* template inline ZCNode* JoinBeforeKey(ZCNode* AP_StdNode, TTypArg AR_Key) */ inline ZCNode* JoinAfter(ZCNode* AP_StdNode, ZCNode* AP_Insert) { /* AP_StdNode 뒤에 AP_Insert 를 삽입 */ #ifdef _DEBUG /* AP_StdNode 는 현재의 리스트에 속해 있어야 하며 */ /* AP_Insert 는 현재의 리스트에 속해 있지 않아야 한다. */ if(FindNode(AP_StdNode)==0 || FindNode(AP_Insert)!=0) { std::fstream fileout("DEBUG.txt",std::ios::out | std::ios::app); fileout<InsertAfter(AP_Insert), ++ml_NodeSize); return AP_Insert; }/* inline ZCNode* JoinAfter(ZCNode* AP_StdNode, ZCNode* AP_Insert)*/ inline ZCNode* JoinAfter(ZCNode* AP_StdNode, TTypArg AR_Type) { ZCNode* VP_NewNode=new ZCNode; #if(_CODE_NEW_) if(TypeMoveObj::ZEUseMoveObj>0) TypeMoveObj::Exec(VP_NewNode->mo_Type, AR_Type); else #endif VP_NewNode->mo_Type=AR_Type; return JoinAfter(AP_StdNode, VP_NewNode); }/* inline ZCNode* JoinAfter(ZCNode* AP_StdNode, TTypArg AR_Type)*/ template inline ZCNode* JoinAfterKey(ZCNode* AP_StdNode, TKey AR_Key) { ZCNode* VP_NewNode=new ZCNode; #if(_CODE_NEW_) if(TypeMoveObj::ZEUseMoveObj>0) TypeMoveObj::Exec(VP_NewNode->mo_Type, AR_Key); else #endif VP_NewNode->mo_Type=AR_Key; return JoinAfter(AP_StdNode, VP_NewNode); }/* template inline ZCNode* JoinAfterKey(ZCNode* AP_StdNode, TTypArg AR_Key) */ #ifdef _DEBUG static void DEBUG_EachNode(ZCNode& AR_Node, std::fstream& fileout) { fileout<<"Node Ptr = "<<&AR_Node<mp_LeftNode, fileout, pf_DEBUG_EachNode); DEBUG_PreOrder(AP_Node->mp_RighNode, fileout, pf_DEBUG_EachNode); }/* if(AP_Node!=0)*/ }/* static void DEBUG_PreOrder( ZCNode* AP_Node, std::fstream& fileout, void pf_DEBUG_EachNode(ZCNode&, std::fstream&) ///////////////////////// ) */ #endif //_DEBUG ZCNode* Balance(ZCNode* AP_Node, int AI_AddState) { /*////////////////////////////////////////////// ■ 평형을 맞추는 멤버 함수다. AI_AddState 은 아래 두 값 중의 하나다. ZNsMain::ZNsEnum::ZEAVL_INSERT_LEFT -1 ZNsMain::ZNsEnum::ZEAVL_INSERT_RIGHT +1 AP_Node 은 회전하는 노드 중에서 가장 높은 노드. 평형을 이루는 꼭지점에 해당하는 노드를 반환한다. 이 정보는 노드를 삭제한 다음에 평형을 다시 이루어야 할 때 필요하다. //////////////////////////////////////////////*/ ZCNode* VP_HighNode=AP_Node->mp_HighNode; ZCNode* VP_DownNode=0; ZCNode* VP_DownDown=0; // AI_AddState 은 VP_DownNode 의 평형계수와 같다. if(AP_Node->mi_Balance==1) { if(AI_AddState>=0) // AI_AddState==ZNsMain::ZNsEnum::ZEAVL_INSERT_RIGHT || AI_AddState==0 { /* AI_AddState==ZNsMain::ZNsEnum::ZEAVL_INSERT_RIGHT * * 1 (AP_Node) * * * * * 2 (VP_DownNode) * * * * * 3 (VP_DownDown) */ /* AI_AddState==0 이때는 AP_Node->mp_LeftNode 가 삭제되는 때이다. * * 1 (AP_Node) * * * * * 3 (VP_DownNode) * * * * * * * 2 4 (VP_DownDown) */ VP_DownNode=AP_Node->mp_RighNode ; VP_DownDown=VP_DownNode->mp_RighNode; AP_Node ->mi_Balance = (AI_AddState==ZNsMain::ZNsEnum::ZEAVL_INSERT_RIGHT ? 0 : 1 ); --VP_DownNode->mi_Balance ; AP_Node ->mp_RighNode=VP_DownNode->mp_LeftNode; AP_Node ->mp_HighNode=VP_DownNode; VP_DownNode->mp_LeftNode=AP_Node ; if(AP_Node->mp_RighNode!=0) AP_Node->mp_RighNode->mp_HighNode=AP_Node; /*endif*/ VP_DownNode->mp_HighNode=VP_HighNode; if(VP_HighNode==0) /* AP_Node==mp_RootNode */ { mp_RootNode=VP_DownNode; } else if(VP_HighNode->mp_RighNode==AP_Node) { VP_HighNode->mp_RighNode=VP_DownNode; } else { VP_HighNode->mp_LeftNode=VP_DownNode; }/* else*/ return VP_DownNode; } else // if(AI_AddState<0) { /* '>' 형태 * * 1 (AP_Node) * * * * * * * 0 3 (VP_DownNode) * * * * * * * 2 (VP_DownDown) * * * * * 1.5 */ VP_DownNode=AP_Node->mp_RighNode ; VP_DownDown=VP_DownNode->mp_LeftNode; AP_Node ->mi_Balance =(VP_DownDown->mi_Balance<=0 ? 0 : -1); VP_DownNode->mi_Balance =(VP_DownDown->mi_Balance>=0 ? 0 : 1); VP_DownDown->mi_Balance =0 ; AP_Node ->mp_RighNode=VP_DownDown->mp_LeftNode; VP_DownNode->mp_LeftNode=VP_DownDown->mp_RighNode; VP_DownDown->mp_LeftNode=AP_Node ; VP_DownDown->mp_RighNode=VP_DownNode; AP_Node ->mp_HighNode=VP_DownDown; VP_DownNode->mp_HighNode=VP_DownDown; VP_DownDown->mp_HighNode=VP_HighNode; if(AP_Node->mp_RighNode!=0) AP_Node->mp_RighNode->mp_HighNode=AP_Node; if(VP_DownNode->mp_LeftNode!=0) VP_DownNode->mp_LeftNode->mp_HighNode=VP_DownNode; if(VP_HighNode==0) /* AP_Node==mp_RootNode */ { mp_RootNode=VP_DownDown; } else if(VP_HighNode->mp_RighNode==AP_Node) { VP_HighNode->mp_RighNode=VP_DownDown; } else { VP_HighNode->mp_LeftNode=VP_DownDown; }/* else*/ return VP_DownDown; }/* else // if(AI_AddState<0)*/ } else // AP_Node->mi_Balance==-1 { // 위 주석에서도 설명했지만 AI_AddState 은 VP_DownNode 의 평형계수와 같다. if(AI_AddState==ZNsMain::ZNsEnum::ZEAVL_INSERT_RIGHT) // ZNsMain::ZNsEnum::ZEAVL_INSERT_RIGHT==1 { /* '<' 형태 * * 3 (AP_Node) * * * * * * *(VP_DownNode) 1 4 * * * * * * * * * (VP_DownDown) 2 5 * * * * * * * * * -1 1.5 2.5 * * * * * 2.6 * */ VP_DownNode=AP_Node->mp_LeftNode ; VP_DownDown=VP_DownNode->mp_RighNode; AP_Node ->mi_Balance =(VP_DownDown->mi_Balance>=0 ? 0 : 1); VP_DownNode->mi_Balance =(VP_DownDown->mi_Balance<=0 ? 0 : -1); VP_DownDown->mi_Balance =0 ; AP_Node ->mp_LeftNode=VP_DownDown->mp_RighNode; VP_DownNode->mp_RighNode=VP_DownDown->mp_LeftNode; VP_DownDown->mp_RighNode=AP_Node ; VP_DownDown->mp_LeftNode=VP_DownNode; VP_DownNode->mp_HighNode=VP_DownDown; AP_Node ->mp_HighNode=VP_DownDown; VP_DownDown->mp_HighNode=VP_HighNode; if(AP_Node->mp_LeftNode!=0) AP_Node->mp_LeftNode->mp_HighNode=AP_Node; if(VP_DownNode->mp_RighNode!=0) VP_DownNode->mp_RighNode->mp_HighNode=VP_DownNode; if(VP_HighNode==0) /* AP_Node==mp_RootNode */ { mp_RootNode=VP_DownDown; } else if(VP_HighNode->mp_RighNode==AP_Node) { VP_HighNode->mp_RighNode=VP_DownDown; } else { VP_HighNode->mp_LeftNode=VP_DownDown; }/* else*/ return VP_DownDown; } else // AI_AddState==ZNsMain::ZNsEnum::ZEAVL_INSERT_LEFT || AI_AddState==0 { /* AI_AddState==ZNsMain::ZNsEnum::ZEAVL_INSERT_LEFT * * 3 (AP_Node) * * * * * 2 (VP_DownNode) * * * * * 1 (VP_DownDown) */ /* AI_AddState==0 이때는 AP_Node->mp_RighNode 가 삭제되는 경우이다. * * 4 (AP_Node) * * * * * 2 (VP_DownNode) * * * * * * *(VP_DownDown)1 3 */ VP_DownNode=AP_Node->mp_LeftNode ; VP_DownDown=VP_DownNode->mp_LeftNode; AP_Node ->mi_Balance = ( AI_AddState==ZNsMain::ZNsEnum::ZEAVL_INSERT_LEFT ? 0 : -1 ) ; ++VP_DownNode->mi_Balance ; AP_Node ->mp_LeftNode=VP_DownNode->mp_RighNode; VP_DownNode->mp_RighNode=AP_Node ; AP_Node ->mp_HighNode=VP_DownNode; if(AP_Node->mp_LeftNode!=0) { AP_Node->mp_LeftNode->mp_HighNode=AP_Node; } VP_DownNode->mp_HighNode=VP_HighNode; if(VP_HighNode==0) /* AP_Node==mp_RootNode */ { mp_RootNode=VP_DownNode; } else if(VP_HighNode->mp_RighNode==AP_Node) { VP_HighNode->mp_RighNode=VP_DownNode; } else { VP_HighNode->mp_LeftNode=VP_DownNode; }/* else*/ return VP_DownNode; }/* else // AI_AddState==ZNsMain::ZNsEnum::ZEAVL_INSERT_LEFT || AI_AddState==0*/ }/* else // AP_Node->mi_Balance==-1*/ }/* ZCNode* Balance(ZCNode* AP_Node,int AI_AddState)*/ private: };/* template< typename Type , typename TTypArg =const Type& , typename TTypBase =ZNsMain::ZNsIFace::ZtCAVL_BASE , typename TNodeBase =ZNsMain::ZNsIFace::ZtCAVL_NodeBase , typename TAlloc =ZNsMain::ZCAllocator , typename TSize =ZNsMain::ZTypLong , typename TCompare =ZNsMain::ZNsFunc::ZtCCompare, typename TMoveObj =ZNsMain::ZNsFunc::ZtCMoveObj > class ZtCObjAVL /////////////////////////////////////////////////////////////////////*/ namespace ZNsExam { template class ZtCExamAVL { public: static void ShowDataInNode(int AI_Data) { cout<<"* Node Data : "< VO_CObjAVL; VO_CObjAVL.AddData(10); VO_CObjAVL.AddData(20); VO_CObjAVL.AddData(30); VO_CObjAVL.AddData(40); VO_CObjAVL.AddData(9 ); cout<<"# In Order" < class ZtCExamAVL*/ }/* namespace ZNsExam*/ }/* namespace ZNsMain */ /*######################################################################################### ■ ZtCObjAVL 예제 -- 2025-08-11 20:43 #include #include "ZCppMain/ZtCObjAVL.H" using namespace std ; using namespace ZNsMain; void ShowDataInNode(int AI_Data) { cout<<"* Node Data : "< VO_CObjAVL; VO_CObjAVL.AddData(10); VO_CObjAVL.AddData(20); VO_CObjAVL.AddData(30); VO_CObjAVL.AddData(40); VO_CObjAVL.AddData(9 ); cout<<"# In Order" <, typename TTypBase =ZNsMain::ZNsIFace::ZtCAVL_BASE , typename TNodeBase =ZNsMain::ZNsIFace::ZtCAVL_NodeBase , typename TAlloc =ZNsMain::ZCAllocator , typename TSize =long , typename TMoveObj =ZNsMain::ZNsFunc::ZtCMoveObj > class ZtCParamObjAVL_Compare ////////////////////////////////////////////////////////// { public: typedef ZNsMain::ZtCObjAVL< Type, TTypArg, TTypBase, TNodeBase, TAlloc, TSize, TCompare, TMoveObj> TypeData; };/* template< typename Type , typename TTypArg =const Type& , typename TCompare =ZNsMain::ZNsFunc ::ZtCCompare, typename TTypBase =ZNsMain::ZNsIFace::ZtCAVL_BASE , typename TNodeBase =ZNsMain::ZNsIFace::ZtCAVL_NodeBase , typename TAlloc =ZNsMain::ZCAllocator , typename TSize =long , typename TMoveObj =ZNsMain::ZNsFunc::ZtCMoveObj > class ZtCParamObjAVL_Compare ////////////////////////////////////////////////////////*/ }/* namespace ZNsTmplParam*/ }/* namespace ZNsMain*/ #endif //__ZNSMAIN_ZTOBJAVL_H__ /*////////////////////////////////////////////////////////////////////////// ■ Red Black Tree : http://www.ezdoum.com/stories.php?story=02/06/26/9759347 ※ 빨강-검정 나무의 성질 (c 로 배우는 알고리즘 - 이재규 지음) 1. 각 외부 노드로 가는 경로의 검정 노드의 수는 같다. 2. 새로 삽입되는 노드는 빨강 노드이다. 3. 경로상에 연이어 두 개의 빨강 노드가 나타날 수 없다.(회전 필요) 4. 부모의 두 자식 노드가 모두 빨강 노드이면 부모는 빨강 노드로 하고 자식은 검정 노드로 바꿀 수 있다. (색상변환) 5. 루트 노드는 빨강 노드일 수 없다. 검정색으로 바뀜 6. 빨강 노드는 자식이 없든가 있으면 두 개의 검정 노드여야 한다. 7. 검정 노드는 자식이 없던가 있으면 하나의 빨강 노드나 두 개의 빨강 노드나 두개의 검정 노드를 가진다. 단 하나의 검정 노드를 자식으로 가질 수 없다. 걀걀걀... //////////////////////////////////////////////////////////////////////////*/