Files
RepoMain/ZCppMain/ZtCObjAVL.H
sauron f7636ecc5d commit 2025-08-16 34:34
git add ZCppMain/ZMainHead.H
git add ZCppMain/ZtCArray.H
git add ZCppMain/ZtCObjList.H
git add ZCppMain/ZMainAVL.H
git add ZCppMain/ZMainHeadEx.H
git add ZCppMain/ZMainXhtml.H
git add ZCppMain/ZtCLoadDataBlock.H
git add ZCppMain/ZtCMainChars.H
git add ZCppMain/ZtCObjAVL.H
git add ZCppMain/ZtCStringEx.H
git add ZCppMain/ZtCTreeData.H
2025-08-16 23:35:44 +09:00

2484 lines
92 KiB
C++

#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 <TTypArg> ,
typename TNodeBase =ZNsMain::ZNsIFace::ZtCAVL_NodeBase<TTypArg> ,
typename TAlloc =ZNsMain::ZCAllocator ,
typename TSize =ZNsMain::ZTypLong ,
typename TCompare =ZNsMain::ZNsFunc::ZtCCompare<TTypArg, TTypArg, false>,
typename TMoveObj =ZNsMain::ZNsFunc::ZtCMoveObj<TTypArg, TTypArg, false>
>
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<ZCNode*>(this);
/* 이 함수는 뒤에 const keyword 가 붙어 있는데 이것 때문에 this pointer 는 상수
포인터로 간주된다. 윗줄에서 이 this 포인터를 비상수 포인터로 먼저 형변환하였다.
ZCNode* VP_TmpNode=const_cast<ZCNode*>this;
라 하면 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<typename TFunctor> static void IterInOrder (ZCNode* AP_Node, TFunctor AO_Functor)
{
if(AP_Node!=0)
{
ZCNode::template IterInOrder<TFunctor>(AP_Node->mp_LeftNode, AO_Functor);
{
ZNsMain::ZtCTypeData<TFunctor>::GetObjRef(AO_Functor)(AP_Node->mo_Type);
}
ZCNode::template IterInOrder<TFunctor>(AP_Node->mp_RighNode, AO_Functor);
}/*
if(AP_Node!=0)*/
}/*
template<typename TFunctor> static void IterInOrder (ZCNode* AP_Node, TFunctor AO_Functor) */
template<typename TFunctor> static void IterPreOrder(ZCNode* AP_Node, TFunctor AO_Functor)
{
if(AP_Node!=0)
{
ZNsMain::ZtCTypeData<TFunctor>::GetObjRef(AO_Functor)(AP_Node->mo_Type);
ZCNode::template IterPreOrder<TFunctor>(AP_Node->mp_LeftNode, AO_Functor);
ZCNode::template IterPreOrder<TFunctor>(AP_Node->mp_RighNode, AO_Functor);
}/*
if(AP_Node!=0)*/
}/*
template<typename TFunctor> static void IterPreOrder(ZCNode* AP_Node,TFunctor AO_Functor) */
template<typename TFunctor> static void IterPostOrder(ZCNode* AP_Node, TFunctor AO_Functor)
{
if(AP_Node!=0)
{
ZCNode::template IterPostOrder<TFunctor>(AP_Node->mp_LeftNode, AO_Functor);
ZCNode::template IterPostOrder<TFunctor>(AP_Node->mp_RighNode, AO_Functor);
ZNsMain::ZtCTypeData<TFunctor>::GetObjRef(AO_Functor)(AP_Node->mo_Type);
}/*
if(AP_Node!=0)*/
}/*
template<typename TFunctor> static void IterPostOrder(ZCNode* AP_Node, TFunctor AO_Functor) */
template<typename TFunctor, typename THelpObj> static void IterInOrder
(ZCNode* AP_Node, TFunctor AO_Functor, THelpObj AR_HelpObj)
/*####################################################################*/
{
if(AP_Node!=0)
{
ZCNode::template IterInOrder<TFunctor, THelpObj>
(AP_Node->mp_LeftNode, AO_Functor, AR_HelpObj);
{
ZNsMain::ZtCTypeData<TFunctor>::
GetObjRef(AO_Functor)(AP_Node->mo_Type, AR_HelpObj);
}
ZCNode::template IterInOrder<TFunctor, THelpObj>
(AP_Node->mp_RighNode, AO_Functor, AR_HelpObj);
}/*
if(AP_Node!=0)*/
}/*
template<typename TFunctor, typename THelpObj> static void IterInOrder
(ZCNode* AP_Node, TFunctor AO_Functor, THelpObj AR_HelpObj)
######################################################################*/
template<typename TFunctor, typename THelpObj> static void IterPreOrder
(ZCNode* AP_Node, TFunctor AO_Functor, THelpObj AR_HelpObj)
/*####################################################################*/
{
if(AP_Node!=0)
{
ZNsMain::ZtCTypeData<TFunctor>::
GetObjRef(AO_Functor)(AP_Node->mo_Type, AR_HelpObj);
ZCNode::template IterPreOrder
<TFunctor, THelpObj>(AP_Node->mp_LeftNode, AO_Functor, AR_HelpObj);
ZCNode::template IterPreOrder
<TFunctor, THelpObj>(AP_Node->mp_RighNode, AO_Functor, AR_HelpObj);
}/*
if(AP_Node!=0)*/
}/*
template<typename TFunctor, typename THelpObj> static void IterPreOrder
(ZCNode* AP_Node, TFunctor AO_Functor, THelpObj AR_HelpObj)
######################################################################*/
template<typename TFunctor, typename THelpObj> static void IterPostOrder
(ZCNode* AP_Node, TFunctor AO_Functor, THelpObj AR_HelpObj)
/*####################################################################*/
{
if(AP_Node!=0)
{
ZCNode::template IterPostOrder<TFunctor, THelpObj>
( AP_Node->mp_LeftNode, AO_Functor, AR_HelpObj );
ZCNode::template IterPostOrder<TFunctor, THelpObj>
( AP_Node->mp_RighNode, AO_Functor, AR_HelpObj );
ZNsMain::ZtCTypeData<TFunctor>::
GetObjRef(AO_Functor)(AP_Node->mo_Type, AR_HelpObj);
}/*
if(AP_Node!=0)*/
}/*
template<typename TFunctor, typename THelpObj> 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<<std::endl<<"File : "<<__FILE__<<std::endl<<"Line : "<<__LINE__<<std::endl;
fileout<<" Error In ZCNode* ZtCObjAVL::CutEmptyNode(ZCNode* AP_CutNode)"<<std::endl;
fileout<<" One Of Sub Node Pointer Of Parameter Node Must Be NULL"<<std::endl;
fileout<<std::endl;
::exit(0);
}/*
if(AP_CutNode->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<<std::endl<<"File : "<<__FILE__<<std::endl<<"Line : "<<__LINE__<<std::endl;
fileout<<"Error In ZCNode* CutNode(ZCNode* AP_CutNode)"<<std::endl;
fileout<<" Parameter Pointer is not VALID"<<std::endl;
fileout.close();
}/*
if(FindNode(AP_CutNode)==0)*/
#endif //_DEBUG
/* AVL TREE 상태를 조종한다.
AP_CutNode->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<<std::endl<<"File : "<<__FILE__<<std::endl<<"Line : "<<__LINE__<<std::endl;
fileout<<"Error In 'ZCNode* GetNodePtr(TypeSize AL_Index)' : Parameter is bad index("<<AL_Index<<")"<<std::endl;
fileout.close();
::exit(1);
}/*
if(AL_Index<1 || AL_Index>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<ZCNode*>(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<<std::endl<<"File : "<<__FILE__<<std::endl<<"Line : "<<__LINE__<<std::endl;
fileout<<"Error In 'const ZCNode* GetNodePtr(TypeSize AL_Index) const' : Parameter is bad index("<<AL_Index<<")"<<std::endl;
fileout.close();
::exit(1);
}/*
if(AL_Index<1 || AL_Index>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<<std::endl<<"File : "<<__FILE__<<std::endl<<"Line : "<<__LINE__<<std::endl;
fileout<<"Error In void ZtCObjAVL::DeleteNode(ZCNode* AP_DelNode)"<<std::endl;
fileout<<" Parameter node pointer dosn't belong to this object"<<std::endl;
fileout.close();
::exit(0);
}/*
if(FindNode(AP_DelNode)==0)*/
#endif //_DEBUG
delete CutNode(AP_DelNode);
}/*
void DeleteNode(ZCNode* AP_DelNode)*/
void DeleteAll()
{
if(mp_HeadNode!=0)
{
ZCNode* VP_NodeCut =mp_HeadNode;
ZCNode* VP_NodeNext=mp_HeadNode;
__for0(TypeSize, i, ml_NodeSize)
{
VP_NodeNext=VP_NodeNext->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<typename TFunctor> 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<TFunctor>::
GetObjRef(AO_Functor)(VP_Temp->mo_Type);
if(VP_Temp==VP_Tail) return; VP_Temp=VP_Temp->mp_NextNode;
}
while(true);
}/*
template<typename TFunctor> void IterNode(TFunctor AO_Functor) const */
template<typename TFunctor, typename TypeHelp>
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<TFunctor>::
GetObjRef(AO_Functor)(VP_Temp->mo_Type, AO_HelpType) ;
if(VP_Temp==VP_Tail) return; VP_Temp=VP_Temp->mp_NextNode;
}
while(true);
}/*
template<typename TFunctor, typename TypeHelp>
void IterNode(TFunctor AO_Functor, TypeHelp AO_HelpType) const */
template<typename TFunctor, typename TypeHelp>
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<TFunctor>::
GetObjRef(AO_Functor)(VP_Temp->mo_Type, AR_HelpType) ;
if(VP_Temp==VP_Tail) return; VP_Temp=VP_Temp->mp_NextNode;
}
while(true);
}/*
template<typename TFunctor, typename TypeHelp>
void IterNodeRef(TFunctor AO_Functor, TypeHelp& AR_HelpType) const */
template<typename TFunctor> void IterInOrder (TFunctor AO_Functor) const{
ZCNode::template IterInOrder <TFunctor>(mp_RootNode, AO_Functor);}
template<typename TFunctor> void IterPreOrder (TFunctor AO_Functor) const{
ZCNode::template IterPreOrder <TFunctor>(mp_RootNode, AO_Functor);}
template<typename TFunctor> void IterPostOrder(TFunctor AO_Functor) const{
ZCNode::template IterPostOrder<TFunctor>(mp_RootNode, AO_Functor);}
template<typename TFunctor, typename THelpObj> void IterInOrder (TFunctor AO_Functor, THelpObj AR_HelpObj) const{
ZCNode::template IterInOrder <TFunctor, THelpObj>(mp_RootNode, AO_Functor, AR_HelpObj);}
template<typename TFunctor, typename THelpObj> void IterPreOrder (TFunctor AO_Functor, THelpObj AR_HelpObj) const{
ZCNode::template IterPreOrder <TFunctor, THelpObj>(mp_RootNode, AO_Functor, AR_HelpObj);}
template<typename TFunctor, typename THelpObj> void IterPostOrder(TFunctor AO_Functor, THelpObj AR_HelpObj) const{
ZCNode::template IterPostOrder<TFunctor, THelpObj>(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<typename TKey> 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<TKey>(*mp_RootNode, AR_Key, RR(VP_CNode));
return VP_CNode; /*////////////////////////////*/
}/*
else // mp_RootNode==0*/
}/*
template<typename TKey> 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<typename TKey> ZCNode* UpdateKey(TKey AR_Key, TKey AR_NewKey)
{
/* AR_Key 값을 가지고 있는 노드를 찾아내어 AR_NewKey 로 업데이트한다.
AR_Key 값을 가지고 있는 노드를 찾아내어 잘라낸 다음, AR_NewKey 로
업데이트하고 다시 삽입한다. */
ZCNode* VP_FindNode=FindKey<TKey>(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<typename TKey> 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<ZCNode*>
( 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<<std::endl<<"File : "<<__FILE__<<std::endl<<"Line : "<<__LINE__<<std::endl;
fileout<<"Error IN 'ZCNode* ZtCObjAVL::FindData(TTypArg AR_Type,ZCNode* AP_StartNode)'"<<std::endl;
fileout<<" Parameter Node Pointer is not valid"<<std::endl;
fileout.close();
::exit(1);
}/*
if(AP_StartNode!=0 && FindNode(AP_StartNode)==0)*/
#endif // _DEBUG
while(AP_StartNode!=0)
{
if(AP_StartNode->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<typename TKey> bool DeleteKey(TKey AR_Key)
{
/*////////////////////////////////////////////////
■ cf) bool DeleteData(TTypArg AR_Type)
AR_Key 가 AR_Type 보다 작은 크기의 object 라면
아래 FindKey() 함수에서 성능향상이 있는 것이다.
////////////////////////////////////////////////*/
ZCNode* VP_FindNode=FindKey<TKey>(AR_Key);
if(VP_FindNode)
{
DeleteNode(VP_FindNode); return true;
}/*
if(VP_FindNode)*/
return false;
}/*
template<typename TKey> bool DeleteKey(TKey AR_Key) */
template<typename TKey> 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<<std::endl<<"File : "<<__FILE__<<std::endl<<"Line : "<<__LINE__<<std::endl;
fileout<<"Error IN 'template<typename TKey> const ZCNode* ZtCObjAVL::FindKey(TKey AR_Key,ZCNode* AP_StartNode) const'"<<std::endl;
fileout<<" Parameter Node Pointer is not valid"<<std::endl;
fileout.close();
::exit(1);
}/*
if(AP_StartNode!=0 && FindNode(AP_StartNode)==0)*/
#endif //_DEBUG
while(AP_StartNode!=0)
{
if(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<typename TKey> const ZCNode*
FindKey(TKey AR_Key, ZCNode* AP_StartNode) const */
template<typename TKey> 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<<std::endl<<"File : "<<__FILE__<<std::endl<<"Line : "<<__LINE__<<std::endl;
fileout<<"Error IN 'template<typename TKey> ZCNode* ZtCObjAVL::FindKey(TKey AR_Key,ZCNode* AP_StartNode)'"<<std::endl;
fileout<<" Parameter Node Pointer is not valid"<<std::endl;
fileout.close();
::exit(1);
}/*
if(AP_StartNode!=0 && FindNode(AP_StartNode)==0)*/
#endif // _DEBUG
while(AP_StartNode!=0)
{
if(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<typename TKey> ZCNode*
FindKey(TKey AR_Key, ZCNode* AP_StartNode) */
template<typename TKey> const ZCNode* FindKey(TKey AR_Key) const
{
return FindKey<TKey>(AR_Key, mp_RootNode);
}/*
template<typename TKey> const ZCNode* FindKey(TKey AR_Key) const */
template<typename TKey> ZCNode* FindKey(TKey AR_Key)
{
return FindKey<TKey>(AR_Key,mp_RootNode);
}/*
template<typename TKey> 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<<std::endl<<"File : "<<__FILE__<<std::endl<<"Line : "<<__LINE__<<std::endl;
fileout<<std::endl<<"void DEBUG_WriteNodeStatus()"<<std::endl<<std::endl;
fileout<<"mp_RootNode Ptr : "<<mp_RootNode<<std::endl;
ZCNode* VP_LoopNode=mp_RootNode;
DEBUG_PreOrder(mp_RootNode, fileout, DEBUG_EachNode);
fileout.close();
}/*
void DEBUG_WriteNodeStatus()*/
#endif //_DEBUG
/*public :*/
private:
int AddData(ZCNode& AR_Node, TTypArg AR_Type)
{
using ZNsMain::ZNsEnum::ZECompareResult_Equal;
#if(_CODE_NEW_)
int VI_CompareResultCode =
(
TypeCompare::ZEUseCompareObj>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<typename TNode> void TTypBase
<TTypArg>::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_CompareResultCode<ZECompareResult_Equal :
AR_Node.GetData() <AR_Type
);
//////////////////////
#if(_CODE_OLD_)
if(AR_Node.GetData()<AR_Type)
#else
if(CB_IsLess)
#endif
{
if(AR_Node.mp_RighNode==0)
{
ZCNode* VP_Temp=JoinAfter(&AR_Node, AR_Type);
AR_Node.mp_RighNode =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_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<typename TKey>
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_CompareResultCode<ZECompareResult_Equal :
AR_Node.GetData() <AR_Key
);
//////////////////////
#if(_CODE_OLD_)
if(AR_Node.GetData()<AR_Key)
#else
if(CB_IsLess)
#endif
{
if(AR_Node.mp_RighNode==0)
{
APR_CNode=JoinAfterKey(&AR_Node, AR_Key);
AR_Node.mp_RighNode=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_RIGHT;
//else
}
else /* AR_Node.mp_RighNode!=0 */
{
int VI_AddState = AddKey<TKey>
(*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<TKey>
(*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<typename TKey>
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_CompareResultCode<ZECompareResult_Equal :
AR_Node.GetData() <AR_AddNode.GetData()
);
//////////////////////
#if(_CODE_OLD_)
if(AR_Node.GetData()<AR_AddNode.GetData())
#else
if(CB_IsLess)
#endif
{
if(AR_Node.mp_RighNode==0)
{
(void)JoinAfter(&AR_Node, &AR_AddNode);
AR_Node. mp_RighNode=&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_RIGHT;
//else
}
else /* AR_Node.mp_RighNode!=0 */
{
int VI_AddState = AddNode(*AR_Node.mp_RighNode, 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_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)
{
(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<<std::endl<<"File : "<<__FILE__<<std::endl<<"Line : "<<__LINE__<<std::endl;
fileout<<"Error In 'inline ZCNode* JoinBefore(ZCNode* AP_StdNode,ZCNode* AP_Insert)' : Parameter is not valid"<<std::endl;
fileout.close();
exit(1);
}/*
if(FindNode(AP_StdNode)==0 || FindNode(AP_Insert)!=0)*/
#endif // _DEBUG
(AP_StdNode->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<typename TKey>
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<typename TKey>
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<<std::endl<<"File : "<<__FILE__<<std::endl<<"Line : "<<__LINE__<<std::endl;
fileout<<"Error In 'inline ZCNode* JoinAfter(ZCNode* AP_StdNode,ZCNode* AP_Insert)' : Parameter is not valid"<<std::endl;
fileout.close();
::exit(1);
}/*
if(FindNode(AP_StdNode)==0 || FindNode(AP_Insert)!=0)*/
#endif //_DEBUG
(AP_StdNode->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<typename TKey>
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<typename TKey>
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<<std::endl;
}/*
static void DEBUG_EachNode(ZCNode& AR_Node, std::fstream& fileout)*/
static void DEBUG_PreOrder( ZCNode* AP_Node,
std::fstream& fileout,
void pf_DEBUG_EachNode(ZCNode&, std::fstream&)
/*/////////////////////*/ )
{
if(AP_Node!=0)
{
pf_DEBUG_EachNode(*AP_Node, fileout);
DEBUG_PreOrder(AP_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 <TTypArg> ,
typename TNodeBase =ZNsMain::ZNsIFace::ZtCAVL_NodeBase<TTypArg> ,
typename TAlloc =ZNsMain::ZCAllocator ,
typename TSize =ZNsMain::ZTypLong ,
typename TCompare =ZNsMain::ZNsFunc::ZtCCompare<TTypArg, TTypArg, false>,
typename TMoveObj =ZNsMain::ZNsFunc::ZtCMoveObj<TTypArg, TTypArg, false>
>
class ZtCObjAVL /////////////////////////////////////////////////////////////////////*/
}/*
namespace ZNsMain */
/*#########################################################################################
■ ZtCObjAVL 예제 -- 2025-08-11 20:43
#include <iostream>
#include "ZCppMain/ZtCObjAVL.H"
using namespace std ;
using namespace ZNsMain;
void ShowDataInNode(int AI_Data)
{
cout<<"* Node Data : "<<AI_Data<<endl;
}
int main()
{
ZtCObjAVL<int, int> 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" <<endl; VO_CObjAVL.IterInOrder (&ShowDataInNode);
cout<<"# Post Order"<<endl; VO_CObjAVL.IterPostOrder(&ShowDataInNode);
cout<<"# Pre Order" <<endl; VO_CObjAVL.IterPreOrder (&ShowDataInNode);
return 0;
}
#########################################################################################*/
namespace ZNsMain
{
using ZNsMain::ZtCObjAVL;
namespace ZNsTmplParam
{
template< typename Type ,
typename TTypArg =const Type& ,
typename TCompare =ZNsMain::ZNsFunc ::ZtCCompare<TTypArg, TTypArg, true>,
typename TTypBase =ZNsMain::ZNsIFace::ZtCAVL_BASE <TTypArg> ,
typename TNodeBase =ZNsMain::ZNsIFace::ZtCAVL_NodeBase<TTypArg> ,
typename TAlloc =ZNsMain::ZCAllocator ,
typename TSize =long ,
typename TMoveObj =ZNsMain::ZNsFunc::ZtCMoveObj<TTypArg, TTypArg, false>
>
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<TTypArg, TTypArg, true>,
typename TTypBase =ZNsMain::ZNsIFace::ZtCAVL_BASE <TTypArg> ,
typename TNodeBase =ZNsMain::ZNsIFace::ZtCAVL_NodeBase<TTypArg> ,
typename TAlloc =ZNsMain::ZCAllocator ,
typename TSize =long ,
typename TMoveObj =ZNsMain::ZNsFunc::ZtCMoveObj<TTypArg, TTypArg, false>
>
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. 검정 노드는 자식이 없던가 있으면
하나의 빨강 노드나 두 개의 빨강 노드나 두개의 검정 노드를 가진다.
단 하나의 검정 노드를 자식으로 가질 수 없다.
걀걀걀...
//////////////////////////////////////////////////////////////////////////*/