Files
LGram16 dd97ddec92 Restructure repository to include all source folders
Move git root from Client/ to src/ to track all source code:
- Client: Game client source (moved to Client/Client/)
- Server: Game server source
- GameTools: Development tools
- CryptoSource: Encryption utilities
- database: Database scripts
- Script: Game scripts
- rylCoder_16.02.2008_src: Legacy coder tools
- GMFont, Game: Additional resources

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-11-29 20:17:20 +09:00

504 lines
9.5 KiB
C++

#ifndef _BinTree_H_
#define _BinTree_H_
#include <assert.h>
#include <stdexcept>
#include <vector>
using namespace std;
#pragma warning(disable:4786) //STL의 쓸데없는 Warning을 없애기 위한..
typedef unsigned char byte;
/////////////////////////////////////////////////////////////////////////////
//
int Power( int x, unsigned y )
{
int result = 1;
for( unsigned i = 0; i < y; i++ )
{
result *= x;
}
return result;
}
//LOGxY에서 소수값을 떼어낸 값이 리턴된다.
int LogInt( unsigned x, unsigned y )
{
int i = 0;
while( y >= x )
{
i++;
y /= x;
}
return i;
}
/////////////////////////////////////////////////////////////////////////////
// 이진 트리 - 1차원 배열에 저장을 하므로 0 ... n 까지 순서대로 순회를 하면
// 레벨별 순회(level-order-traversal)가 됨.
// 인덱스 0은 캐쉬로 사용
template < class T >
class CBinTree
{
public:
typedef void (*SAVEFUNC)( FILE *, const T & );
typedef void (*LOADFUNC)( FILE *, T & );
public:
////////////////유틸리티 함수들/////////////////////
//리턴값 0은 에러를 의미함.
static unsigned Root() { return 1; }
static unsigned Parent( unsigned index ) { return index / 2; }
static unsigned LeftChild( unsigned index ) { return index * 2; }
static unsigned RightChild( unsigned index ) { return index * 2 + 1; }
static unsigned LevelAtIndex( unsigned index ) { return LogInt( x, index ); }
static unsigned IndexAtLevel( unsigned nLevel ) { return int( Power( 2, nLevel ) ); }
////////////////////////////////////////////////////
protected:
struct SNode
{
T data; //실제 데이터
byte isRed : 1;
byte isValid : 1;
byte isLeaf : 1;
};
protected:
typedef vector<SNode> DATACONTAINER;
DATACONTAINER m_vecTreeData;
protected:
void LoadExtraInfo( SNode & node, FILE * fp )
{
unsigned char c = 0;
fread( &c, sizeof( c ), 1, fp );
node.isRed = ( c & 0x01 ) >> 0;
node.isValid = ( c & 0x02 ) >> 1;
node.isLeaf = ( c & 0x04 ) >> 2;
}
void SaveExtraInfo( SNode & node, FILE * fp )
{
unsigned char c = 0;
c = ( node.isRed << 0 ) | ( node.isValid << 1 ) | ( node.isLeaf << 2 );
assert( ( ( c & 0x01 ) >> 0 ) == node.isRed );
assert( ( ( c & 0x02 ) >> 1 ) == node.isValid );
assert( ( ( c & 0x04 ) >> 2 ) == node.isLeaf );
fwrite( &c, sizeof( c ), 1, fp );
}
public:
///////////////////인터페이스////////////////////
CBinTree()
{
}
~CBinTree()
{
Destroy();
}
void Create()
{
Destroy();
m_vecTreeData.push_back( SNode() ); //뿌리노드 추가
for( unsigned i = 0; i < m_vecTreeData.size(); i++ ) //전부 무효(invalid) 노드로 세팅
{
m_vecTreeData[i].isValid = 0;
m_vecTreeData[i].isLeaf = 1;
}
m_vecTreeData[0].isValid = 1;
}
void Create( FILE * fp, LOADFUNC LoadData )
{
Destroy();
if( LoadData == 0 )
return;
if( fp == 0 )
return;
unsigned size = 0;
fread( &size, sizeof( unsigned ), 1, fp );
m_vecTreeData.push_back( SNode() );
for( unsigned i = 1; i < size; i++ )
{
m_vecTreeData.push_back( SNode() );
assert( m_vecTreeData.size() == ( i + 1 ) );
LoadData( fp, m_vecTreeData[i].data );
LoadExtraInfo( m_vecTreeData[i], fp );
}
}
void Destroy()
{
m_vecTreeData.clear();
}
void Save( FILE * fp, SAVEFUNC SaveData )
{
if( SaveData == 0 )
return;
if( fp == 0 )
return;
unsigned size = m_vecTreeData.size();
fwrite( &size, sizeof( unsigned ), 1, fp );
for( unsigned i = 1; i < size; i++ )
{
SaveData( fp, m_vecTreeData[i].data );
SaveExtraInfo( m_vecTreeData[i], fp );
}
}
//////////////////////////////////////////////////
T & SetData( unsigned index )
{
if( index >= m_vecTreeData.size() )
{
m_vecTreeData.resize( index + 1 );
}
m_vecTreeData[ index ].isValid = true;
m_vecTreeData[ Parent( index ) ].isLeaf = false;
return m_vecTreeData[ index ].data;
}
const T & GetData( unsigned index )
{
if( index >= m_vecTreeData.size() )
throw out_of_range( "index out of range(at CBinTree::GetData)" );
return m_vecTreeData[ index ].data;
}
//////////////////////////////////////////////////
bool IsEmpty()
{
if( m_vecTreeData.size() < 2 )
return true;
if( m_vecTreeData[1].isValid == false )
return true;
return false;
}
bool IsValid( unsigned index )
{
if( index >= m_vecTreeData.size() )
return false;
return m_vecTreeData[ index ].isValid == 1;
}
bool IsLeaf( unsigned index )
{
if( index >= m_vecTreeData.size() )
return true;
return m_vecTreeData[ index ].isLeaf == 1;
}
unsigned Capacity()
{
return m_vecTreeData.capacity();
}
unsigned Size()
{
return m_vecTreeData.size();
}
unsigned Min( unsigned index ) //index의 자식 노드들 중 최소값인 것을 리턴
{
while( LeftChild( index ) < m_vecTreeData.size() && IsValid( LeftChild( index ) ) )
index = LeftChild( index );
return index;
}
unsigned Max( unsigned index ) //index의 자식 노드들 중 최대값인 것을 리턴
{
while( RightChild( index ) < m_vecTreeData.size() && IsValid( RightChild( index ) ) )
index = RightChild( index );
return index;
}
//////////////////////////////////////////////////
class iterator_base
{
protected:
CBinTree * m_pBinTree;
unsigned m_uiCurIndex;
public:
iterator_base( CBinTree * pBinTree, unsigned index )
: m_pBinTree( pBinTree ), m_uiCurIndex( index )
{
}
T & operator*() const
{
return m_pBinTree->m_vecTreeData[m_uiCurIndex].data;
}
T * operator->() const
{
return (&**this);
}
bool operator==( iterator_base & rhs ) const
{
if( m_pBinTree == rhs.m_pBinTree && m_uiCurIndex == rhs.m_uiCurIndex )
return true;
else
return false;
}
bool operator!=( iterator_base & rhs ) const
{
return !operator==( rhs );
}
bool IsValid() const
{
if( m_pBinTree != NULL && m_uiCurIndex != 0 )
return true;
else
return false;
}
unsigned GetIndex() const
{
return m_uiCurIndex;
}
};
//////////////////////////////////////////////////
//전위순회 - 1 2 4 8 9 5 10 11 3 6 12 13 7 14 15
class iterator_preorder : public iterator_base
{
protected:
void Inc()
{
//왼쪽이 유효한 동안 왼쪽으로 간다.
//왼쪽이 무효하면 오른쪽으로 간다.
//오른쪽도 무효하면 부모노드로 돌아간다.
//부모 노드가 방문했던 노드이면 또다시 부모노드로 간다.
if( m_pBinTree->IsValid( LeftChild( m_uiCurIndex ) ) )
m_uiCurIndex = LeftChild( m_uiCurIndex );
else if( m_pBinTree->IsValid( RightChild( m_uiCurIndex ) ) )
m_uiCurIndex = RightChild( m_uiCurIndex );
else
{
unsigned tempIndex;
while( m_uiCurIndex == RightChild( tempIndex = Parent( m_uiCurIndex ) )
|| !m_pBinTree->IsValid( RightChild( tempIndex ) ) )
{
m_uiCurIndex = tempIndex;
if( m_uiCurIndex == 0 )
return;
}
m_uiCurIndex = RightChild( tempIndex );
}
}
void Dec()
{
//아직 구현 안했으므로 호출하면 바로 end가 되어서 끝나도록 해놨음.
m_uiCurIndex = 0;
}
public:
iterator_preorder( CBinTree * pBinTree, unsigned index )
: iterator_base( pBinTree, index )
{
}
iterator_preorder & operator++()
{
Inc();
return (*this);
}
iterator_preorder operator++(int)
{
iterator_preorder tmp = *this;
Inc();
return tmp;
}
iterator_preorder & operator--()
{
Dec();
return (*this);
}
iterator_preorder operator--(int)
{
iterator_preorder tmp = *this;
Dec();
return tmp;
}
};
//////////////////////////////////////////////////
//중위순회 - 8 4 9 2 10 5 11 1 12 6 13 3 14 7 15
class iterator_inorder
{
protected:
void Inc()
{
//Leftmost를 시작으로 한다.
if( m_pBinTree->IsValid( RightChild( m_uiCurIndex ) ) )
m_uiCurIndex = Min( RightChild( m_uiCurIndex ) );
else
{
unsigned tempIndex;
while( m_uiCurIndex == RightChild( tempIndex = Parent( m_uiCurIndex ) ) )
m_uiCurIndex = tempIndex;
m_uiCurIndex = tempIndex;
}
}
void Dec()
{
if( m_pBinTree->IsValid( LeftChild( m_uiCurIndex ) ) )
m_uiCurIndex = Max( LeftChild( m_uiCurIndex ) );
else
{
unsigned tempIndex;
while( m_uiCurIndex == LeftChild( tempIndex = Parent( m_uiCurIndex ) ) )
m_uiCurIndex = tempIndex;
m_uiCurIndex = tempIndex;
}
}
public:
iterator_inorder( CBinTree * pBinTree, unsigned index )
: iterator_base( pBinTree, index )
{
}
iterator_inorder & operator++()
{
Inc();
return (*this);
}
iterator_inorder operator++(int)
{
iterator_inorder tmp = *this;
Inc();
return tmp;
}
iterator_inorder & operator--()
{
Dec();
return (*this);
}
iterator_inorder operator--(int)
{
iterator_inorder tmp = *this;
Dec();
return tmp;
}
};
//////////////////////////////////////////////////
//레벨별 순회 - 0~n까지 차례대로 순회하면 됨.
class iterator_levelorder
{
public:
iterator_levelorder( CBinTree * pBinTree, unsigned index )
: iterator_base( pBinTree, index )
{
}
iterator_levelorder & operator++()
{
m_uiCurIndex++;
return (*this );
}
iterator_levelorder operator++(int)
{
iterator_levelorder tmp = *this;
m_uiCurIndex++;
return tmp;
}
iterator_levelorder & operator--()
{
m_uiCurIndex--;
return (*this);
}
iterator_levelorder operator--(int)
{
iterator_levelorder tmp = *this;
m_uiCurIndex--;
return tmp;
}
};
iterator_preorder Begin_preorder() { return iterator_preorder( this, 1 ); }
iterator_levelorder Begin_levelorder() { return iterator_levelorder( this, 1 ); }
iterator_preorder End_preorder() { return iterator_preorder( this, 0 ); }
iterator_levelorder End_levelorder() { return iterator_levelorder( this, m_TreeData.size() ); }
friend class iterator_base;
};
#endif