2484 lines
91 KiB
C++
2484 lines
91 KiB
C++
|
|
|
|
#ifndef __ZNSMAIN_ZTOBJAVL_H__
|
|
#define __ZNSMAIN_ZTOBJAVL_H__
|
|
|
|
|
|
#include "ZCppMain/ZMainAVL.H"
|
|
|
|
|
|
namespace ZNsMain
|
|
{
|
|
|
|
/*/////////////////////////////////////////////////////////////////////////////////////////
|
|
|
|
■ 이 AVL tree 는 각 노드가 트리 구조를 이루며, 동시에 이중 원형 연결리스트를 이루고 있다.
|
|
자료를 기본적으로 오름차순 정렬한다.
|
|
|
|
■ TType 자료형에는 <,>,== 연산이 가능해야 한다.
|
|
|
|
■ 어떤 클래스에 비교연산자를 정의할 때 bool operator>(const CStringHash& rhs) const 와 같
|
|
이 하면 인수에도 const, 멤버함수에도 const 를 잊지 말 것.
|
|
|
|
■ 접미어 Key 가 붙어있는 멤버 함수는 TType 보다는 크기가 작은 어떤 자료형이다. 삽입, 삭제
|
|
시에 메모리를 절약하기 위해서 사용한다. TType 자료형과 Key 자료형 사이에는 <,>,==,= 의 연
|
|
산이 가능해야 한다.
|
|
|
|
■ multi set 으로 활용하는 코드는 MainAVL.H 파일의 주석에 예시하였다. typename TNodeBase 를
|
|
std::NsInterface::CAVL_Multi_NodeBase_T<> 으로 지정하고 있다.
|
|
|
|
/////////////////////////////////////////////////////////////////////////////////////////*/
|
|
|
|
|
|
template< typename TType ,
|
|
typename TTypArg = const TType& ,
|
|
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::ZtCCompare<TTypArg, TTypArg, false>,
|
|
typename TMoveObj = ZNsMain::ZtCMoveObj<TType , TTypArg, true >
|
|
>
|
|
class ZtCObjAVL : public TTypBase ///////////////////////////////////////////////////////
|
|
{
|
|
public:
|
|
typedef TType 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; /* 상위 노드 */
|
|
|
|
TType mo_Data ;
|
|
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*/
|
|
|
|
typename ZtCRef<TypeArg>::TypeConst GetData() const
|
|
{
|
|
return mo_Data;
|
|
}/*
|
|
typename ZtCRef<TypeArg>::TypeConst GetData() const*/
|
|
|
|
|
|
bool operator==(TypeArg AR_Type) const{return mo_Data==AR_Type;}
|
|
bool operator> (TypeArg AR_Type) const{return mo_Data> AR_Type;}
|
|
bool operator< (TypeArg AR_Type) const{return mo_Data< 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_Data);
|
|
}
|
|
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_Data);
|
|
|
|
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_Data);
|
|
}/*
|
|
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_Data, 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_Data, 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_Data, 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_Data);
|
|
|
|
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 *this;}
|
|
|
|
DeleteAll(); if(rhs.mp_HeadNode==0){ return *this;}
|
|
|
|
ZCNode* VP_Temp=rhs.mp_HeadNode;
|
|
ZCNode* VP_Tail=rhs.mp_HeadNode->mp_PrevNode;
|
|
|
|
do //////
|
|
{
|
|
AddData(VP_Temp->mo_Data);
|
|
|
|
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_Data);
|
|
|
|
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_Data 을 받는 인수는
|
|
복사로 받거나 const TType& 으로 받아야 한다. */
|
|
|
|
ZNsMain::ZtCTypeData<TFunctor>::
|
|
GetObjRef(AO_Functor)(VP_Temp->mo_Data);
|
|
|
|
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_Data 을 받는 인수는
|
|
복사로 받거나 const TType& 으로 받아야 한다. */
|
|
|
|
ZNsMain::ZtCTypeData<TFunctor>::
|
|
GetObjRef(AO_Functor)(VP_Temp->mo_Data, 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_Data, 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);
|
|
|
|
#if(_CODE_NEW_)
|
|
if(TypeMoveObj::ZEUseMoveObj>0) /////////////////////
|
|
{
|
|
TypeMoveObj::Exec(mp_RootNode->mo_Data, AR_Type);
|
|
}
|
|
else ////////////////////////////////////////////////
|
|
#endif
|
|
mp_RootNode->mo_Data=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_Data=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_Data=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_Data=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_Data 를 가지는 노드를 찾는다. */
|
|
|
|
return FindData(AR_Type, mp_RootNode);
|
|
}/*
|
|
ZCNode* FindData(TTypArg AR_Type) const*/
|
|
|
|
|
|
ZCNode* FindData(TTypArg AR_Type, ZCNode* AP_StartNode) const
|
|
{
|
|
/* AP_StartNode 부터 하위 노드로 순회하면서
|
|
mo_Data 를 가지는 노드를 찾는다. */
|
|
|
|
#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_Data == AR_Type)
|
|
{
|
|
return AP_StartNode;
|
|
}
|
|
else if(AP_StartNode->mo_Data > 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_Data 과 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_Data==AR_Key) return AP_StartNode;
|
|
|
|
if(AP_StartNode->mo_Data>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_Data 과 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_Data==AR_Key) return AP_StartNode;
|
|
|
|
if(AP_StartNode->mo_Data>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_Data>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_Data>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_Data>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_Data, AR_Type);
|
|
else
|
|
#endif
|
|
VP_NewNode->mo_Data=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;
|
|
|
|
VP_NewNode->mo_Data = 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_Data, AR_Type);
|
|
else
|
|
#endif
|
|
VP_NewNode->mo_Data=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;
|
|
|
|
VP_NewNode->mo_Data= 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 TType ,
|
|
typename TTypArg = const TType& ,
|
|
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::ZtCCompare<TTypArg, TTypArg, false>,
|
|
typename TMoveObj = ZNsMain::ZtCMoveObj<TType , TTypArg, true >
|
|
>
|
|
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 TType ,
|
|
typename TTypArg =const TType& ,
|
|
typename TCompare =ZNsMain::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::ZtCMoveObj<TType, TTypArg, false>
|
|
>
|
|
class ZtCParamObjAVL_Compare //////////////////////////////////////////////////////////
|
|
{
|
|
public: typedef ZNsMain::ZtCObjAVL<
|
|
TType, TTypArg, TTypBase, TNodeBase, TAlloc, TSize, TCompare, TMoveObj> TypeData;
|
|
};/*
|
|
template< typename TType ,
|
|
typename TTypArg =const TType& ,
|
|
typename TCompare =ZNsMain::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::ZtCMoveObj<TType, 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. 검정 노드는 자식이 없던가 있으면
|
|
하나의 빨강 노드나 두 개의 빨강 노드나 두개의 검정 노드를 가진다.
|
|
단 하나의 검정 노드를 자식으로 가질 수 없다.
|
|
|
|
걀걀걀...
|
|
|
|
//////////////////////////////////////////////////////////////////////////*/
|