数据结构——键树之Tire树

  
    
#include " stdio.h "
#include
" stdlib.h "
#include
" string.h "
#include
" ctype.h "

#define OK 1
#define ERROR 0
typedef
int Status; // Status是函数的类型,其值是函数结果状态代码,如OK等
typedef int Boolean; // Boolean是布尔类型,其值是TRUE或false
#define N 16 // 数据元素个数
#define MAXKEYLEN 16 // 关键字的最大长度
#define STACK_INIT_SIZE 10 // 存储空间初始分配量
#define STACKINCREMENT 2 // 存储空间分配增量
#define LENGTH 27 // 结点的最大度+1(大写英文字母)
#define Nil ' ' // 定义结束符为空格
#define MAXKEYLEN 16 // 关键字的最大长度
#define EQ(a,b) (!strcmp((a),(b)))
#define LT(a,b) (strcmp((a),(b))<0)
#define LQ(a,b) (strcmp((a),(b))<=0)

struct Others // 记录的其它部分
{
int ord;
};
struct KeysType // 关键字类型
{
char ch[MAXKEYLEN]; // 关键字
int num; // 关键字长度
};
struct Record // 记录类型
{
KeysType key;
// 关键字
Others others; // 其它部分(由主程定义)
};
enum NodeKind{LEAF,BRANCH}; // 结点种类:{叶子,分支}
typedef struct TrieNode // Trie键树类型
{
NodeKind kind;
union
{
struct // 叶子结点
{
KeysType K;
Record
* infoptr;
}lf;
struct // 分支结点
{
TrieNode
* ptr[LENGTH]; // LENGTH为结点的最大度+1,在主程定义
// int num; 改
}bh;
};
// union
}TrieNode, * TrieTree;

// 对两个字符串型关键字的比较约定为如下的宏定义
Status InitDSTable(TrieTree & T)
{
// 操作结果: 构造一个空的Trie键树T
T = NULL;
return OK;
}

void DestroyDSTable(TrieTree & T)
{
// 初始条件: Trie树T存在。操作结果: 销毁Trie树T
int i;
if (T) // 非空树
{
for (i = 0 ;i < LENGTH;i ++ )
{
if (T -> kind == BRANCH && T -> bh.ptr[i]) // 第i个结点不空
{
if (T -> bh.ptr[i] -> kind == BRANCH) // 是子树
{
DestroyDSTable(T
-> bh.ptr[i]);
}
else // 是叶子
{
free(T
-> bh.ptr[i]);
T
-> bh.ptr[i] = NULL;
}
}
}
// for
free(T); // 释放根结点
T = NULL; // 空指针赋0
} // if(T)
} // DestroyDSTable

Status pr(Record
* r)
{
printf(
" (%s,%d) " ,r -> key.ch,r -> others.ord);
return OK;
}
// pr

int ord( char c)
{
c
= toupper(c);
if (c >= ' A ' && c <= ' Z ' )
return c - ' A ' + 1 ; // 英文字母返回其在字母表中的序号
else
return 0 ; // 其余字符返回0
} // ord

Record
* SearchTrie(TrieTree T,KeysType K)
{
// 在键树T中查找关键字等于K的记录
TrieTree p;
int i;

for (p = T,i = 0 ; p && p -> kind == BRANCH && i < K.num; p = p -> bh.ptr[ord(K.ch[i])], ++ i )
;
// 对K的每个字符逐个查找,*p为分支结点,ord()求字符在字母表中序号

if (p && p -> kind == LEAF && p -> lf.K.num == K.num && EQ(p -> lf.K.ch,K.ch)) // 查找成功
return p -> lf.infoptr;
else // 查找不成功
return NULL;
}
// SearchTrie

void InsertTrie(TrieTree & T,Record * r)
{
// 初始条件: Trie键树T存在,r为待插入的数据元素的指针
// 操作结果: 若T中不存在其关键字等于(*r).key.ch的数据元素,
// 则按关键字顺序插r到T中
TrieTree p,q,ap;
int i = 0 ,j;
KeysType K1,K
= r -> key;
if ( ! T) // 空树
{
T
= (TrieTree)malloc( sizeof (TrieNode)); // 新建根节点
T -> kind = BRANCH;
for (i = 0 ;i < LENGTH;i ++ ) // 初始化,指针量赋初值NULL
T -> bh.ptr[i] = NULL;
p
= T -> bh.ptr[ord(K.ch[ 0 ])] = (TrieTree)malloc( sizeof (TrieNode)); // 新建叶子节点
p -> kind = LEAF;
p
-> lf.K = K;
p
-> lf.infoptr = r;
}
// if
else // 非空树
{
for (p = T,i = 0 ; p && p -> kind == BRANCH && i < K.num; ++ i)
{
q
= p;
p
= p -> bh.ptr[ord(K.ch[i])];
}
// for
i -- ;

if (p && p -> kind == LEAF && p -> lf.K.num == K.num && EQ(p -> lf.K.ch,K.ch)) // T中存在该关键字
return ;

else // T中不存在该关键字,插入之
{
if ( ! p) // 分支空,建立叶子节点,指向关键字记录
{
p
= q -> bh.ptr[ord(K.ch[i])] = (TrieTree)malloc( sizeof (TrieNode));
p
-> kind = LEAF;
p
-> lf.K = K;
p
-> lf.infoptr = r;
}
// if
else if (p -> kind == LEAF) // 有不完全相同的叶子,
{
K1
= p -> lf.K;
do
{
ap
= q -> bh.ptr[ord(K.ch[i])] = (TrieTree)malloc( sizeof (TrieNode));
ap
-> kind = BRANCH;
for (j = 0 ;j < LENGTH;j ++ ) // 指针量赋初值NULL
ap -> bh.ptr[j] = NULL;
q
= ap;
i
++ ;
}
while ( ord(K.ch[i]) == ord(K1.ch[i]) ); // do...while
// 如果原来的记录和新插入的关键字的第i个字符还是相等的话就再新生一个分支,
// 直到不相等时,把原来的记录重新连到这个分支上,再新建一个叶子节点指向新插入的关键字

q
-> bh.ptr[ord(K1.ch[i])] = p; // 把原来的不相同的叶子挂回来,如果是空字符,就挂在0号指针下

p
= q -> bh.ptr[ord(K.ch[i])] = (TrieTree)malloc( sizeof (TrieNode));
p
-> kind = LEAF;
p
-> lf.K = K;
p
-> lf.infoptr = r;
}
// else if
} // else
} // else
} // InsertTrie

void InputD(TrieTree & t,Record r[])
{
Record
* p;
for ( int i = 0 ;i < N;i ++ )
{
r[i].key.num
= strlen(r[i].key.ch) + 1 ;
r[i].key.ch[r[i].key.num]
= Nil; // 在关键字符串最后加结束符
p = SearchTrie(t,r[i].key);
if ( ! p)
InsertTrie(t,
& r[i]);
}
// for
} // InputD

void TraverseDSTable(TrieTree T,Status( * Vi)(Record * ))
{
// 初始条件: Trie键树T存在,Vi是对记录指针操作的应用函数
// 操作结果: 按关键字的顺序输出关键字及其对应的记录
TrieTree p;
int i;
if (T)
{
for (i = 0 ;i < LENGTH;i ++ )
{
p
= T -> bh.ptr[i];
if (p && p -> kind == LEAF)
Vi(p
-> lf.infoptr);
else if (p && p -> kind == BRANCH)
TraverseDSTable(p,Vi);
}
// for
} // if
printf( " \n " );
}
// TraverseDSTable

void UserSearch(TrieTree t)
{
char s[MAXKEYLEN + 1 ];
KeysType k;
Record
* p;
printf(
" \n请输入待查找记录的关键字符串: " );
scanf(
" %s " ,s);
k.num
= strlen(s) + 1 ;
strcpy(k.ch,s);
k.ch[k.num]
= Nil; // 在关键字符串最后加结束符
p = SearchTrie(t,k);
if (p)
pr(p);
else
printf(
" 没找到 " );
printf(
" \n " );
}
// UserSearch

int main()
{
TrieTree t;
Record r[N]
= {{{ " CAI " }, 1 },{{ " CAO " }, 2 },{{ " LI " }, 3 },{{ " LAN " }, 4 },

{{
" CHA " }, 5 },{{ " CHANG " }, 6 },{{ " WEN " }, 7 },{{ " CHAO " }, 8 },

{{
" YUN " }, 9 },{{ " YANG " }, 10 },{{ " LONG " }, 11 },{{ " WANG " }, 12 },

{{
" ZHAO " }, 13 },{{ " LIU " }, 14 },{{ " WU " }, 15 },{{ " CHEN " }, 16 }};
InitDSTable(t);
InputD(t,r);
printf(
" 按关键字符串的顺序遍历Trie树(键树):\n " );
TraverseDSTable(t,pr);
UserSearch(t);
DestroyDSTable(t);
return 1 ;
}

 

你可能感兴趣的:(数据结构)