数据结构——键树之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;
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

minyuanxiani

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值