- °³¿ä
- ±¸Çö
- ¼Ò½º
- ¿¹Á¦
- ¸µÅ©
1 °³¿ä
»çÀüÀ» ¸¸µé¾î º¸¾Æ¿ä. ±×·±µ¥ SuffixTree¶û Â÷À̰¡ ¹¹Áö?
2 ±¸Çö
////////////////////////////////////////////////////////////////////////////////
/// \file TernarySearchTree.h
/// \author excel96
/// \date 2006.7.24
///
/// http://www.octavian.org/cs/software.html ÆäÀÌÁö Âü°í
////////////////////////////////////////////////////////////////////////////////
#ifndef __TERNARYSEARCHTREE_H__
#define __TERNARYSEARCHTREE_H__
#include <vector>
template <typename T>
struct ptr_delete_policy { void operator()(T ptr) { delete ptr; } };
template <typename T>
struct array_delete_policy { void operator()(T ptr) { delete [] ptr; } };
template <typename T>
struct no_delete_policy { void operator()(T ptr) {} };
////////////////////////////////////////////////////////////////////////////////
/// \class cTernarySearchTree
/// \brief Ternary Search Tree
///
/// http://www.octavian.org/cs/software.html ÆäÀÌÁö Âü°í
////////////////////////////////////////////////////////////////////////////////
template
<
typename T,
template <typename> class DP = no_delete_policy
>
class cTernarySearchTree
{
public:
/// °¢Á¾ »ó¼ö.
enum { TST_OK, TST_ERROR, TST_NULL_KEY, TST_DUPLICATE_KEY };
/// Ⱦ´Ü Äݹé ÇÔ¼ö.
typedef void (*PFNTRAVERSE)(T* data);
/// ¸ÅÄ¡¸¦ ¹ÝȯÇϱâ À§ÇÑ Ä÷º¼Ç.
typedef std::vector<T*> MATCHES;
private:
/// Æ®¸® ±âº» ³ëµå.
class cNode
{
public:
char Value; ///< ¹®ÀÚ¿ °ª.
cNode* Left; ///< ¿ÞÂÊ ÀÚ½Ä.
cNode* Middle; ///< Áß°£ ÀÚ½Ä or ¹®ÀÚ¿°ú ÇÔ²² µé¾î¿Â Æ÷ÀÎÅÍ.
cNode* Right; ///< ¿À¸¥ÂÊ ÀÚ½Ä.
/// \brief »ý¼ºÀÚ.
cNode(char v = 0, cNode* l = NULL, cNode* m = NULL, cNode* r = NULL)
: Value(v), Left(l), Middle(m), Right(r)
{
}
};
/// ³ëµå Ç®.
class cNodeLines
{
public:
cNode* Line; ///< ³ëµåµé.
cNodeLines* Next; ///< ´ÙÀ½ Ç®.
/// \brief »ý¼ºÀÚ.
cNodeLines(size_t width, cNodeLines* next = NULL)
: Line(new cNode[width]), Next(next)
{
cNode* current = Line;
for (size_t i = 1; i < width; i++)
{
current->Middle = &Line[i];
current = current->Middle;
}
current->Middle = NULL;
}
/// \brief ¼Ò¸êÀÚ.
~cNodeLines()
{
if (Line) { delete [] Line; }
if (Next) { delete Next; }
}
};
private:
size_t m_NodeLineWidth; ///< ³ëµå°¡ ¸ðÀÚ¶ö ¶§¸¶´Ù Çѹø¿¡ ÇÒ´çÇÒ ³ëµåÀÇ °¹¼ö.
cNodeLines* m_NodeLines; ///< ³ëµå Ç®.
cNode* m_FreeList; ///< ³ëµå Ç® ¾ÈÀÇ À妽º.
cNode* m_Head[256]; ///< ·çÆ® ³ëµåµé.
public:
/// \brief »ý¼ºÀÚ.
cTernarySearchTree(size_t nodeLineWidth=16);
/// \brief ¼Ò¸êÀÚ.
virtual ~cTernarySearchTree();
public:
/// \brief »õ·Î¿î ¹®ÀÚ¿À» Áý¾î³Ö´Â´Ù.
int Insert(const char* key, T* data, bool replace = false, T** prevEntry = NULL);
/// \brief ¹®ÀÚ¿À» °Ë»öÇÑ´Ù.
T* Search(const char* key) const;
/// \brief ±ÙÁ¢ ¹®ÀÚ¿À» °Ë»öÇÑ´Ù.
void NearSearch(const char* key, int distance, MATCHES& matches) const;
/// \brief ¹®ÀÚ¿À» »èÁ¦ÇÑ´Ù.
T* Delete(const char* key);
/// \brief ¸ðµç ¾ÆÀÌÅÛ¿¡ ´ëÇØ ÁÖ¾îÁø ÇÔ¼ö¸¦ ½ÇÇàÇÑ´Ù.
void Traverse(PFNTRAVERSE callback);
private:
/// \brief ÇÁ¸® ¸®½ºÆ®ÀÇ Å©±â¸¦ Áõ°¡½ÃŲ´Ù.
void GrowNodeFreeList();
/// \brief ±ÙÁ¢ ¹®ÀÚ¿À» °Ë»öÇÑ´Ù.
void NearSearch(cNode* node, const char* key, int distance, MATCHES& matches) const;
/// \brief ¸ðµç ¾ÆÀÌÅÛ¿¡ ´ëÇØ ÁÖ¾îÁø ÇÔ¼ö¸¦ ½ÇÇàÇÑ´Ù.
void Traverse(cNode* node, PFNTRAVERSE callback);
/// \brief »èÁ¦ ÇÔ¼ö.
static void Delete(T* data);
};
////////////////////////////////////////////////////////////////////////////////
/// \brief »ý¼ºÀÚ.
/// \param nodeLineWidth Çѹø¿¡ ÇÒ´çÇÒ ³ëµåÀÇ °¹¼ö.
////////////////////////////////////////////////////////////////////////////////
template <typename T, template <typename> class DP>
cTernarySearchTree<T, DP>::cTernarySearchTree(size_t nodeLineWidth)
: m_NodeLineWidth(nodeLineWidth),
m_NodeLines(new cNodeLines(nodeLineWidth)),
m_FreeList(NULL)
{
memset(m_Head, 0, sizeof(m_Head));
m_FreeList = m_NodeLines->Line;
}
////////////////////////////////////////////////////////////////////////////////
/// \brief ¼Ò¸êÀÚ.
////////////////////////////////////////////////////////////////////////////////
template <typename T, template <typename> class DP>
cTernarySearchTree<T, DP>::~cTernarySearchTree()
{
Traverse(Delete);
if (m_NodeLines)
delete m_NodeLines;
}
////////////////////////////////////////////////////////////////////////////////
/// \brief »õ·Î¿î ¹®ÀÚ¿À» Áý¾î³Ö´Â´Ù.
/// \param key ¹®ÀÚ¿.
/// \param data ¹®ÀÚ¿°ú ÇÔ²² ÇÒ´çÇÒ µ¥ÀÌÅÍ.
/// \param replace °ãÄ¡´Â µ¥ÀÌÅͰ¡ ÀÖ´Ù¸é ±³Ã¼ÇÒ °ÍÀΰ¡ÀÇ ¿©ºÎ.
/// \param prevEntry °ãÄ¡´Â µ¥ÀÌÅͰ¡ ÀÖÀ» °æ¿ì, µ¥ÀÌÅÍ °ªÀ» Áý¾î³ÖÀ» º¯¼ö.
/// \return int Á¤»óÀûÀÎ °æ¿ì TST_OK, ¿¡·¯°¡ »ý±ä °æ¿ì¿¡´Â ´Ù¸¥ °ªÀ» ¹ÝȯÇÑ´Ù.
////////////////////////////////////////////////////////////////////////////////
template <typename T, template <typename> class DP>
int cTernarySearchTree<T, DP>::Insert(
const char* key, T* data, bool replace, T** prevEntry)
{
cNode* currentNode = NULL;
cNode* newNodeTreeBegin = NULL;
int keyIndex = 0;
bool performLoop = true;
if (key == NULL)
return TST_NULL_KEY;
if (key[0] == 0)
return TST_NULL_KEY;
if (m_Head[(unsigned char)key[0]] == NULL)
{
if (m_FreeList == NULL)
GrowNodeFreeList();
m_Head[(unsigned char)key[0]] = m_FreeList;
m_FreeList = m_FreeList->Middle;
currentNode = m_Head[(unsigned char)key[0]];
currentNode->Value = key[1];
if (key[1] == 0)
{
currentNode->Middle = (cNode*)data; // argh
return TST_OK;
}
else
performLoop = false;
}
currentNode = m_Head[(unsigned char)key[0]];
keyIndex = 1;
while (performLoop)
{
if (key[keyIndex] == currentNode->Value)
{
if (key[keyIndex] == 0)
{
if (replace)
{
if (prevEntry)
*prevEntry = (T*)currentNode->Middle;
currentNode->Middle = (cNode*)data; // argh
return TST_OK;
}
else
{
if (prevEntry)
*prevEntry = (T*)currentNode->Middle;
return TST_DUPLICATE_KEY;
}
}
else
{
if (currentNode->Middle == NULL)
{
if (m_FreeList == NULL)
GrowNodeFreeList();
currentNode->Middle = m_FreeList;
m_FreeList = m_FreeList->Middle;
newNodeTreeBegin = currentNode;
currentNode = currentNode->Middle;
currentNode->Value = key[keyIndex];
break;
}
else
{
currentNode = currentNode->Middle;
keyIndex++;
continue;
}
}
}
if ( ((currentNode->Value == 0) && (key[keyIndex] < 64)) ||
((currentNode->Value != 0) && (key[keyIndex] < currentNode->Value)) )
{
if (currentNode->Left == NULL)
{
if (m_FreeList == NULL)
GrowNodeFreeList();
currentNode->Left = m_FreeList;
m_FreeList = m_FreeList->Middle;
newNodeTreeBegin = currentNode;
currentNode = currentNode->Left;
currentNode->Value = key[keyIndex];
if (key[keyIndex] == 0)
{
currentNode->Middle = (cNode*)data; // argh
return TST_OK;
}
else
{
break;
}
}
else
{
currentNode = currentNode->Left;
continue;
}
}
else
{
if (currentNode->Right == NULL)
{
if (m_FreeList == NULL)
GrowNodeFreeList();
currentNode->Right = m_FreeList;
m_FreeList = m_FreeList->Middle;
newNodeTreeBegin = currentNode;
currentNode = currentNode->Right;
currentNode->Value = key[keyIndex];
break;
}
else
{
currentNode = currentNode->Right;
continue;
}
}
}
do
{
keyIndex++;
if (m_FreeList == NULL)
GrowNodeFreeList();
currentNode->Middle = m_FreeList;
m_FreeList = m_FreeList->Middle;
currentNode = currentNode->Middle;
currentNode->Value = key[keyIndex];
} while (key[keyIndex] != 0);
currentNode->Middle = (cNode*)data; // argh
return TST_OK;
}
////////////////////////////////////////////////////////////////////////////////
/// \brief ¹®ÀÚ¿À» °Ë»öÇÑ´Ù.
/// \param key °Ë»öÇÒ ¹®ÀÚ¿.
/// \return T* ÇØ´çÇÏ´Â µ¥ÀÌÅͰ¡ ÀÖ´Â °æ¿ì¿¡´Â ±× µ¥ÀÌÅ͸¦ ¹ÝȯÇϰí,
/// ¾ø´Â °æ¿ì¿¡´Â NULLÀ» ¹ÝȯÇÑ´Ù.
////////////////////////////////////////////////////////////////////////////////
template <typename T, template <typename> class DP>
T* cTernarySearchTree<T, DP>::Search(const char* key) const
{
if (key[0] == 0)
return NULL;
if (m_Head[(unsigned char)key[0]] == NULL)
return NULL;
cNode* currentNode = m_Head[(unsigned char)key[0]];
int keyIndex = 1;
while (currentNode != NULL)
{
if (key[keyIndex] == currentNode->Value)
{
if (currentNode->Value == 0)
return currentNode->Middle;
else
{
currentNode = currentNode->Middle;
keyIndex++;
continue;
}
}
else if (
(currentNode->Value == 0 && key[keyIndex] < 64)
||
(currentNode->Value != 0 && key[keyIndex] < currentNode->Value)
)
{
currentNode = currentNode->Left;
continue;
}
else
{
currentNode = currentNode->Right;
continue;
}
}
return NULL;
}
////////////////////////////////////////////////////////////////////////////////
/// \brief ±ÙÁ¢ ¹®ÀÚ¿À» °Ë»öÇÑ´Ù.
/// \param key ¹®ÀÚ¿.
/// \param distance Ʋ·Áµµ µÇ´Â ±ÛÀÚÀÇ °¹¼ö.
/// \param matches °á°ú¸¦ ãÀº °æ¿ì ±× °á°ú¸¦ Áý¾î³ÖÀ» Ä÷º¼Ç.
////////////////////////////////////////////////////////////////////////////////
template <typename T, template <typename> class DP>
void cTernarySearchTree<T, DP>::NearSearch(
const char* key, int distance, MATCHES& matches) const
{
NearSearch(m_Head[(unsigned char)key[0]], key + 1, distance, matches);
}
////////////////////////////////////////////////////////////////////////////////
/// \brief ±ÙÁ¢ ¹®ÀÚ¿À» °Ë»öÇÑ´Ù.
/// \param node °Ë»öÀÇ ±âÁØÀÌ µÇ´Â ³ëµå.
/// \param key ¹®ÀÚ¿.
/// \param distance Ʋ·Áµµ µÇ´Â ±ÛÀÚÀÇ °¹¼ö.
/// \param matches °á°ú¸¦ ãÀº °æ¿ì ±× °á°ú¸¦ Áý¾î³ÖÀ» Ä÷º¼Ç.
////////////////////////////////////////////////////////////////////////////////
template <typename T, template <typename> class DP>
void cTernarySearchTree<T, DP>::NearSearch(
cNode* node, const char* key, int distance, MATCHES& matches) const
{
if (!node || distance < 0) return;
if (distance > 0 || ((unsigned char)(*key)) < ((unsigned char)(node->Value)))
NearSearch(node->Left, key, distance, matches);
if (node->Value == 0)
{
if ((int)strlen(key) <= distance)
matches.push_back((T*)node->Middle);
}
else
{
NearSearch(
node->Middle,
*key ? key + 1 : key,
(*key == node->Value) ? distance : distance - 1,
matches
);
}
if (distance > 0 || ((unsigned char)(*key)) > ((unsigned char)(node->Value)))
NearSearch(node->Right, key, distance, matches);
}
////////////////////////////////////////////////////////////////////////////////
/// \brief ¹®ÀÚ¿À» »èÁ¦ÇÑ´Ù.
/// \param key »èÁ¦ÇÒ ¹®ÀÚ¿.
/// \return T* ¹®ÀÚ¿°ú ÇÔ²² µé¾î¿Ô´ø Æ÷ÀÎÅÍ.
////////////////////////////////////////////////////////////////////////////////
template <typename T, template <typename> class DP>
T* cTernarySearchTree<T, DP>::Delete(const char* key)
{
cNode* currentNode = NULL;
cNode* currentNodeParent = NULL;
cNode* lastBranch = NULL;
cNode* lastBranchParent = NULL;
cNode* nextNode = NULL;
cNode* lastBranchReplacement = NULL;
cNode* lastBranchDanglingChild = NULL;
int keyIndex = 0;
if (key[0] == 0)
return NULL;
if (m_Head[(unsigned char)key[0]] == NULL)
return NULL;
lastBranch = NULL;
lastBranchParent = NULL;
currentNode = m_Head[(unsigned char)key[0]];
currentNodeParent = NULL;
keyIndex = 1;
while (currentNode != NULL)
{
if (key[keyIndex] == currentNode->Value)
{
if (currentNode->Left != NULL || currentNode->Right != NULL)
{
lastBranch = currentNode;
lastBranchParent = currentNodeParent;
}
if (key[keyIndex] == 0)
{
break;
}
else
{
currentNodeParent = currentNode;
currentNode = currentNode->Middle;
keyIndex++;
continue;
}
}
else if (
(currentNode->Value == 0 && key[keyIndex] < 64)
||
(currentNode->Value != 0 && key[keyIndex] < currentNode->Value)
)
{
lastBranchParent = currentNode;
currentNodeParent = currentNode;
currentNode = currentNode->Left;
lastBranch = currentNode;
continue;
}
else
{
lastBranchParent = currentNode;
currentNodeParent = currentNode;
currentNode = currentNode->Right;
lastBranch = currentNode;
continue;
}
}
if (currentNode == NULL)
return NULL;
if (lastBranch == NULL)
{
nextNode = m_Head[(unsigned char)key[0]];
m_Head[(unsigned char)key[0]] = NULL;
}
else if ( (lastBranch->Left == NULL) && (lastBranch->Right == NULL) )
{
if (lastBranchParent->Left == lastBranch)
lastBranchParent->Left = NULL;
else
lastBranchParent->Right = NULL;
nextNode = lastBranch;
}
else
{
if (lastBranch->Left != NULL && lastBranch->Right != NULL)
{
lastBranchReplacement = lastBranch->Right;
lastBranchDanglingChild = lastBranch->Left;
}
else if (lastBranch->Right != NULL)
{
lastBranchReplacement = lastBranch->Right;
lastBranchDanglingChild = NULL;
}
else
{
lastBranchReplacement = lastBranch->Left;
lastBranchDanglingChild = NULL;
}
if (lastBranchParent == NULL)
{
m_Head[(unsigned char)key[0]]=lastBranchReplacement;
}
else
{
if (lastBranchParent->Left == lastBranch)
lastBranchParent->Left = lastBranchReplacement;
else if (lastBranchParent->Right == lastBranch)
lastBranchParent->Right = lastBranchReplacement;
else
lastBranchParent->Middle = lastBranchReplacement;
}
if (lastBranchDanglingChild != NULL)
{
currentNode = lastBranchReplacement;
while (currentNode->Left != NULL)
currentNode = currentNode->Left;
currentNode->Left = lastBranchDanglingChild;
}
nextNode = lastBranch;
}
do
{
currentNode = nextNode;
nextNode = currentNode->Middle;
currentNode->Left = NULL;
currentNode->Right = NULL;
currentNode->Middle = m_FreeList;
m_FreeList = currentNode;
}
while (currentNode->Value != 0);
return nextNode;
}
////////////////////////////////////////////////////////////////////////////////
/// \brief ¸ðµç ¾ÆÀÌÅÛ¿¡ ´ëÇØ ÁÖ¾îÁø ÇÔ¼ö¸¦ ½ÇÇàÇÑ´Ù.
/// \param callback ½ÇÇàÇÒ ÇÔ¼ö.
////////////////////////////////////////////////////////////////////////////////
template <typename T, template <typename> class DP>
void cTernarySearchTree<T, DP>::Traverse(PFNTRAVERSE callback)
{
for (int i=0; i<256; ++i)
Traverse(m_Head[i], callback);
}
////////////////////////////////////////////////////////////////////////////////
/// \brief ¸ðµç ¾ÆÀÌÅÛ¿¡ ´ëÇØ ÁÖ¾îÁø ÇÔ¼ö¸¦ ½ÇÇàÇÑ´Ù.
/// \param node ³ëµå.
/// \param callback ½ÇÇàÇÒ ÇÔ¼ö.
////////////////////////////////////////////////////////////////////////////////
template <typename T, template <typename> class DP>
void cTernarySearchTree<T, DP>::Traverse(cNode* node, PFNTRAVERSE callback)
{
if (!node) return;
Traverse(node->Left, callback);
if (node->Value != 0)
Traverse(node->Middle, callback);
else
callback((T*)node->Middle);
Traverse(node->Right, callback);
}
////////////////////////////////////////////////////////////////////////////////
/// \brief ÇÁ¸® ¸®½ºÆ®ÀÇ Å©±â¸¦ Áõ°¡½ÃŲ´Ù.
////////////////////////////////////////////////////////////////////////////////
template <typename T, template <typename> class DP>
void cTernarySearchTree<T, DP>::GrowNodeFreeList()
{
m_NodeLines = new cNodeLines(m_NodeLineWidth, m_NodeLines);
m_FreeList = m_NodeLines->Line;
}
////////////////////////////////////////////////////////////////////////////////
/// \brief »èÁ¦ ÇÔ¼ö.
/// \param data »èÁ¦ÇÒ °´Ã¼.
////////////////////////////////////////////////////////////////////////////////
template <typename T, template <typename> class DP>
void cTernarySearchTree<T, DP>::Delete(T* data)
{
DP<T*> doDelete;
doDelete(data);
}
#endif
2.2 ¿¹Á¦
cTernarySearchTree<std::string, ptr_delete_policy> t;
t.Insert("hello", new std::string("hello"));
t.Insert("world", new std::string("world"));
cTernarySearchTree<std::string>::MATCHES matches;
t.NearSearch("h", 4, matches);
for (size_t i=0; i<matches.size(); ++i)
{
std::string* str = matches[i];
std::cout << *str << endl;
}
3 ¸µÅ©
SeriousMoin v1 (koMoinMoin 1.0a4 Modified)