/**
* @file ptree.c
*
*
* @brief パトリシア検索木を用いた名前検索:データ型が int の場合
*
*
*
* @brief Patricia index tree for name lookup: data type = int
*
*
* @author Akinobu LEE
* @date Thu Feb 17 15:34:39 2005
*
* $Revision: 1.7 $
*
*/
/*
* Copyright (c) 1991-2012 Kawahara Lab., Kyoto University
* Copyright (c) 2000-2005 Shikano Lab., Nara Institute of Science and Technology
* Copyright (c) 2005-2012 Julius project team, Nagoya Institute of Technology
* All rights reserved
*/
#include
#include
static unsigned char mbit[] = {0x80, 0x40, 0x20, 0x10, 0x08, 0x04, 0x02, 0x01};
/**
* String bit test function.
*
* @param str [in] key string
* @param bitplace [in] bit location to test
*
* @return the content of tested bit in @a tmp_str, either 0 or 1.
*/
int
testbit(char *str, int slen, int bitplace)
{
int maskptr;
if ((maskptr = bitplace >> 3) > slen) return 0;
return(str[maskptr] & mbit[bitplace & 7]);
}
/**
* Local bit test function for search.
*
* @param str [in] key string
* @param bitplace [in] bit place to test.
* @param maxbitplace [in] maximum number of bitplace
*
* @return the content of tested bit in @a tmp_str, either 0 or 1.
*/
int
testbit_max(char *str, int bitplace, int maxbitplace)
{
if (bitplace >= maxbitplace) return 0;
return(str[bitplace >> 3] & mbit[bitplace & 7]);
}
/**
* Find in which bit the two strings differ, starting from the head.
*
* @param str1 [in] string 1
* @param str2 [in] string 2
*
* @return the bit location in which the string differs.
*/
int
where_the_bit_differ(char *str1, char *str2)
{
int p = 0;
int bitloc;
int slen1, slen2;
/* step: char, bit */
while(str1[p] == str2[p]) p++;
bitloc = p * 8;
slen1 = strlen(str1);
slen2 = strlen(str2);
while(testbit(str1, slen1, bitloc) == testbit(str2, slen2, bitloc)) bitloc++;
return(bitloc);
}
/**
* Allocate a new node.
*
* @param mroot [i/o] base pointer for block malloc
*
* @return pointer to the new node.
*/
static PATNODE *
new_node(BMALLOC_BASE **mroot)
{
PATNODE *tmp;
tmp = (PATNODE *)mybmalloc2(sizeof(PATNODE), mroot);
tmp->left0 = NULL;
tmp->right1 = NULL;
return(tmp);
}
/**
* Make a patricia tree for given string arrays.
* Recursively called by descending the scan bit.
*
* @param words [in] list of word strings
* @param data [in] integer value corresponding to each string in @a words
* @param wordsnum [in] number of above
* @param bitplace [in] current scan bit.
* @param mroot [i/o] base pointer for block malloc
*
* @return pointer to the root node index.
*/
PATNODE *
make_ptree(char **words, int *data, int wordsnum, int bitplace, BMALLOC_BASE **mroot)
{
int i,j, tmp;
char *p;
int newnum;
PATNODE *ntmp;
#if 0
printf("%d:", wordsnum);
for (i=0;ivalue.data = data[0];
return(ntmp);
}
newnum = 0;
for (i=0;i=newnum; j--) {
if (testbit(words[j], strlen(words[j]), bitplace) != 0) {
p = words[i]; words[i] = words[j]; words[j] = p;
tmp = data[i]; data[i] = data[j]; data[j] = tmp;
break;
}
}
}
}
/* create node and descend for each node */
ntmp = new_node(mroot);
ntmp->value.thres_bit = bitplace;
ntmp->right1 = make_ptree(words, data, newnum, bitplace+1, mroot);
ntmp->left0 = make_ptree(&(words[newnum]), &(data[newnum]), wordsnum-newnum, bitplace+1, mroot);
return(ntmp);
}
}
/**
* Output a tree structure in text for debug, traversing pre-order
*
* @param node [in] root index node
* @param level [in] current tree depth
*/
void
disp_ptree(PATNODE *node, int level)
{
int i;
for (i=0;ileft0 == NULL && node->right1 == NULL) {
printf("LEAF:%d\n", node->value.data);
} else {
printf("%d\n", node->value.thres_bit);
if (node->left0 != NULL) {
disp_ptree(node->left0, level+1);
}
if (node->right1 != NULL) {
disp_ptree(node->right1, level+1);
}
}
}
/**
* Recursive function to search the data in the tree
*
* @param node [in] current node.
* @param str [in] key string
* @param maxbitplace [in] maximum number of bitplace
*
* @return the found integer value.
*/
static int
ptree_search_data_r(PATNODE *node, char *str, int maxbitplace)
{
if (node->left0 == NULL && node->right1 == NULL) {
return(node->value.data);
} else {
if (testbit_max(str, node->value.thres_bit, maxbitplace) != 0) {
return(ptree_search_data_r(node->right1, str, maxbitplace));
} else {
return(ptree_search_data_r(node->left0, str, maxbitplace));
}
}
}
/**
* Search for the data whose key string matches the given string.
*
* @param str [in] search key string
* @param node [in] root node of index tree
*
* @return the exactly found integer value, or the nearest one.
*/
int
ptree_search_data(char *str, PATNODE *node)
{
if (node == NULL) {
//("Error: ptree_search_data: no node, search for \"%s\" failed\n", str);
return -1;
}
return(ptree_search_data_r(node, str, strlen(str) * 8 + 8));
}
/**
* Recursive function to replace the data in the tree
*
* @param node [in] current node.
* @param str [in] key string
* @param val [in] new value
* @param maxbitplace [in] maximum number of bitplace
*
* @return the found integer value.
*/
static int
ptree_replace_data_r(PATNODE *node, char *str, int val, int maxbitplace)
{
if (node->left0 == NULL && node->right1 == NULL) {
node->value.data = val;
return(node->value.data);
} else {
if (testbit_max(str, node->value.thres_bit, maxbitplace) != 0) {
return(ptree_replace_data_r(node->right1, str, val, maxbitplace));
} else {
return(ptree_replace_data_r(node->left0, str, val, maxbitplace));
}
}
}
/**
* Search for the data whose key string matches the given string, and
* replace its value.
*
* @param str [in] search key string
* @param val [in] value
* @param node [in] root node of index tree
*
* @return the exactly found integer value, or the nearest one.
*/
int
ptree_replace_data(char *str, int val, PATNODE *node)
{
if (node == NULL) {
//("Error: ptree_search_data: no node, search for \"%s\" failed\n", str);
return -1;
}
return(ptree_replace_data_r(node, str, val, strlen(str) * 8 + 8));
}
/*******************************************************************/
/* add 1 node to given ptree */
/**
* Make a root node of a index tree.
*
* @param data [in] the first data
* @param mroot [i/o] base pointer for block malloc
*
* @return the newly allocated root node.
*/
PATNODE *
ptree_make_root_node(int data, BMALLOC_BASE **mroot)
{
PATNODE *nnew;
/* make new leaf node for newstr */
nnew = new_node(mroot);
nnew->value.data = data;
return(nnew);
}
/**
* Insert a new node to the existing index tree.
*
* @param str [in] new key string
* @param bitloc [in] bit branch to which this node will be added
* @param data [in] new data integer value
* @param parentlink [i/o] the parent node to which this node will be added
* @param mroot [i/o] base pointer for block malloc
*/
static void
ptree_add_entry_at(char *str, int slen, int bitloc, int data, PATNODE **parentlink, BMALLOC_BASE **mroot)
{
PATNODE *node;
node = *parentlink;
if (node->value.thres_bit > bitloc ||
(node->left0 == NULL && node->right1 == NULL)) {
PATNODE *newleaf, *newbranch;
/* insert between [parent] and [node] */
newleaf = new_node(mroot);
newleaf->value.data = data;
newbranch = new_node(mroot);
newbranch->value.thres_bit = bitloc;
*parentlink = newbranch;
if (testbit(str, slen, bitloc) ==0) {
newbranch->left0 = newleaf;
newbranch->right1 = node;
} else {
newbranch->left0 = node;
newbranch->right1 = newleaf;
}
return;
} else {
if (testbit(str, slen, node->value.thres_bit) != 0) {
ptree_add_entry_at(str, slen, bitloc, data, &(node->right1), mroot);
} else {
ptree_add_entry_at(str, slen, bitloc, data, &(node->left0), mroot);
}
}
}
/**
* Insert a new node to the index tree.
*
* @param str [in] new key string
* @param data [in] new data integer value
* @param matchstr [in] the most matching data already exist in the index tree,
* as obtained by aptree_search_data()
* @param rootnode [i/o] pointer to root index node
* @param mroot [i/o] base pointer for block malloc
*/
void
ptree_add_entry(char *str, int data, char *matchstr, PATNODE **rootnode, BMALLOC_BASE **mroot)
{
int bitloc;
bitloc = where_the_bit_differ(str, matchstr);
if (*rootnode == NULL) {
*rootnode = ptree_make_root_node(data, mroot);
} else {
ptree_add_entry_at(str, strlen(str), bitloc, data, rootnode, mroot);
}
}