二叉树

来源:互联网 发布:html5.js 下载 编辑:程序博客网 时间:2024/06/12 19:48

在这个二叉树中,

前序遍历的结果:2, 7, 2, 6, 5, 11, 5, 9, 4

后序遍历的结果:2, 5, 11, 6, 7, 4, 9, 5, 2

中序遍历的结果:2, 7, 5, 6, 11, 2, 5, 4, 9


以上的递归算法使用与树的高度成比例的栈空间。如果我们在每个结点中存储指向父结点的指针,那样可以使用迭代算法,只使用常数空间实现所有这些遍历。然而,指向父结点的指针占用更多的空间。这只在需要指向父节点的指针或栈空间有限时才使用。例如, 这是一个中序遍历的迭代算法:

visit(root)

    prev    := null

    current := root

    next    := null

   

    while current != null

        if prev == current.parent

            prev := current

            next := current.left

        if next == null or prev == current.left

            print current.value

            prev := current

            next := current.right

        if next == null or prev == current.right

            prev := current

            next := current.parent

        current := next

用二叉树表示下述表达式:a+b*(c-d)-e/f

先序遍历的序列是:-+a*b-cd/ef

中序遍历的序列是:a+b*c-d-e/f

后序遍历的序列是:abcd-*+ef/-

[编辑] 深度优先遍历

在深度优先顺序中,我们希望从根结点访问最远的结点。和图的深度优先搜索不同的是,不需记住访问过的每一个结点,因为树中不会有环。前序,中序和后序遍历都是深度优先遍历的特例。参见深度优先搜索

[编辑] 广度优先遍历

和深度优先遍历不同,广度优先遍历会先访问离根节点最近的节点。参见广度优先搜索 二叉树的广度优先遍历又称按层次遍历。算法借助队列实现。

[编辑] n叉树转换为二叉树

一般有序树和二叉树之间有一一映射关系,能进行相互转换。

n叉树转换为二叉树的方法:二叉树中结点x的左子结点为n叉树中结点x的左子结点;二叉树中结点x的右子结点为n叉树中结点x的第一个右边的同级结点y

例如,在左边的树中,A6个子结点{B,C,D,E,F,G}。它能被转换成右边的二叉树。

将一棵树转换为二叉树的方法:

在兄弟之间加一连线;

对每个结点,除了其左孩子外,去除其与其余孩子之间的联系;

以树的根结点为轴心,将整树顺时针转45度。

[编辑] 存储结构与基本操作

树的二叉链表表示法(孩子兄弟表示法)是树和二叉树转换的媒介。

[编辑] 树的二叉链表存储表示

/* 树的二叉链表(孩子兄弟)存储表示 */

typedef struct CSNode

{

  TElemType data;

  struct CSNode *firstchild,*nextsibling;

}CSNode,*CSTree;

[编辑] 树的二叉链表存储的基本操作

/* 树的二叉链表(孩子兄弟)存储的基本操作(17) */

#define ClearTree DestroyTree /* 二者操作相同 */

#include"func6-2.c" /* 包括PreOrderTraverse() */

void InitTree(CSTree *T)

{ /* 操作结果:构造空树T */

  *T=NULL;

}

void DestroyTree(CSTree *T)

{ /* 初始条件:树T存在。操作结果:销毁树T */

  if(*T)

  {

    if((*T)->firstchild) /* T有长子 */

      DestroyTree(&(*T)->firstchild); /* 销毁T的长子为根结点的子树 */

    if((*T)->nextsibling) /* T有下一个兄弟 */

      DestroyTree(&(*T)->nextsibling); /* 销毁T的下一个兄弟为根结点的子树 */

    free(*T); /* 释放根结点 */

    *T=NULL;

  }

}

typedef CSTree QElemType; /* 定义队列元素类型 */

#include"c3-2.h" /* 定义LinkQueue类型(链队列) */

#include"bo3-2.c" /* LinkQueue类型的基本操作 */

void CreateTree(CSTree *T)

{ /* 构造树T */

  char c[20]; /* 临时存放孩子结点(设不超过20)的值 */

  CSTree p,p1;

  LinkQueue q;

  int i,l;

  InitQueue(&q);

  printf("请输入根结点(字符型,空格为空): ");

  scanf("%c%*c",&c[0]);

  if(c[0]!=Nil) /* 非空树 */

  {

    *T=(CSTree)malloc(sizeof(CSNode)); /* 建立根结点 */

    (*T)->data=c[0];

    (*T)->nextsibling=NULL;

    EnQueue(&q,*T); /* 入队根结点的指针 */

    while(!QueueEmpty(q)) /* 队不空 */

    {

      DeQueue(&q,&p); /* 出队一个结点的指针 */

      printf("请按长幼顺序输入结点%c的所有孩子: ",p->data);

      gets(c);

      l=strlen(c);

      if(l>0) /* 有孩子 */

      {

        p1=p->firstchild=(CSTree)malloc(sizeof(CSNode)); /* 建立长子结点 */

        p1->data=c[0];

        for(i=1;i<l;i++)

        {

          p1->nextsibling=(CSTree)malloc(sizeof(CSNode)); /* 建立下一个兄弟结点 */

          EnQueue(&q,p1); /* 入队上一个结点 */

          p1=p1->nextsibling;

          p1->data=c[i];

        }

        p1->nextsibling=NULL;

        EnQueue(&q,p1); /* 入队最后一个结点 */

      }

      else

        p->firstchild=NULL; /* 长子指针为空 */

    }

  }

  else

    *T=NULL; /* 空树 */

}

Status TreeEmpty(CSTree T)

{ /* 初始条件:树T存在。操作结果:若T为空树,则返回TURE,否则返回FALSE */

  if(T) /* T不空 */

    return FALSE;

  else

    return TRUE;

}

int TreeDepth(CSTree T)

{ /* 初始条件:树T存在。操作结果:返回T的深度 */

  CSTree p;

  int depth,max=0;

  if(!T) /* 树空 */

    return 0;

  if(!T->firstchild) /* 树无长子 */

    return 1;

  for(p=T->firstchild;p;p=p->nextsibling)

  { /* 求子树深度的最大值 */

    depth=TreeDepth(p);

    if(depth>max)

      max=depth;

  }

  return max+1; /* 树的深度=子树深度最大值+1 */

}

TElemType Value(CSTree p)

{ /* 返回p所指结点的值 */

  return p->data;

}

TElemType Root(CSTree T)

{ /* 初始条件:树T存在。操作结果:返回T的根 */

  if(T)

    return Value(T);

  else

    return Nil;

}

 CSTree Point(CSTree T,TElemType s)

 { /* 返回二叉链表(孩子兄弟)T中指向元素值为s的结点的指针。另加 */

   LinkQueue q;

   QElemType a;

   if(T) /* 非空树 */

   {

     InitQueue(&q); /* 初始化队列 */

     EnQueue(&q,T); /* 根结点入队 */

     while(!QueueEmpty(q)) /* 队不空 */

     {

       DeQueue(&q,&a); /* 出队,队列元素赋给a */

       if(a->data==s)

         return a;

       if(a->firstchild) /* 有长子 */

         EnQueue(&q,a->firstchild); /* 入队长子 */

       if(a->nextsibling) /* 有下一个兄弟 */

         EnQueue(&q,a->nextsibling); /* 入队下一个兄弟 */

     }

   }

   return NULL;

 }

Status Assign(CSTree *T,TElemType cur_e,TElemType value)

{ /* 初始条件:树T存在,cur_e是树T中结点的值。操作结果:改cur_evalue */

  CSTree p;

  if(*T) /* 非空树 */

  {

    p=Point(*T,cur_e); /* pcur_e的指针 */

    if(p) /* 找到cur_e */

    {

      p->data=value; /* 赋新值 */

      return OK;

    }

  }

  return ERROR; /* 树空或没找到 */

}

 TElemType Parent(CSTree T,TElemType cur_e)

 { /* 初始条件:树T存在,cur_eT中某个结点 */

   /* 操作结果:若cur_eT的非根结点,则返回它的双亲,否则函数值为”*/

   CSTree p,t;

   LinkQueue q;

   InitQueue(&q);

   if(T) /* 树非空 */

   {

     if(Value(T)==cur_e) /* 根结点值为cur_e */

       return Nil;

     EnQueue(&q,T); /* 根结点入队 */

     while(!QueueEmpty(q))

     {

       DeQueue(&q,&p);

       if(p->firstchild) /* p有长子 */

       {

         if(p->firstchild->data==cur_e) /* 长子为cur_e */

           return Value(p); /* 返回双亲 */

         t=p; /* 双亲指针赋给t */

         p=p->firstchild; /* p指向长子 */

         EnQueue(&q,p); /* 入队长子 */

         while(p->nextsibling) /* 有下一个兄弟 */

         {

           p=p->nextsibling; /* p指向下一个兄弟 */

           if(Value(p)==cur_e) /* 下一个兄弟为cur_e */

             return Value(t); /* 返回双亲 */

           EnQueue(&q,p); /* 入队下一个兄弟 */

         }

       }

     }

   }

   return Nil; /* 树空或没找到cur_e */

 }

TElemType LeftChild(CSTree T,TElemType cur_e)

{ /* 初始条件:树T存在,cur_eT中某个结点 */

  /* 操作结果:若cur_eT的非叶子结点,则返回它的最左孩子,否则返回”*/

  CSTree f;

  f=Point(T,cur_e); /* f指向结点cur_e */

  if(f&&f->firstchild) /* 找到结点cur_e且结点cur_e有长子 */

    return f->firstchild->data;

  else

    return Nil;

}

TElemType RightSibling(CSTree T,TElemType cur_e)

{ /* 初始条件:树T存在,cur_eT中某个结点 */

  /* 操作结果:若cur_e有右兄弟,则返回它的右兄弟,否则返回”*/

  CSTree f;

  f=Point(T,cur_e); /* f指向结点cur_e */

  if(f&&f->nextsibling) /* 找到结点cur_e且结点cur_e有右兄弟 */

    return f->nextsibling->data;

  else

    return Nil; /* 树空 */

}

Status InsertChild(CSTree *T,CSTree p,int i,CSTree c)

{ /* 初始条件:树T存在,p指向T中某个结点,1≤i≤p所指结点的度+1,非空树cT不相交 */

  /* 操作结果:插入cTp结点的第i棵子树 */

  /* 因为p所指结点的地址不会改变,故p不需是引用类型 */

  int j;

  if(*T) /* T不空 */

  {

    if(i==1) /* 插入cp的长子 */

    {

      c->nextsibling=p->firstchild; /* p的原长子现是c的下一个兄弟(c本无兄弟) */

      p->firstchild=c;

    }

    else /* 找插入点 */

    {

      p=p->firstchild; /* 指向p的长子 */

      j=2;

      while(p&&i>j)

      {

        p=p->nextsibling;

        j++;

      }

      if(j==i) /* 找到插入位置 */

      {

        c->nextsibling=p->nextsibling;

        p->nextsibling=c;

      }

      else /* p原有孩子数小于i-1 */

        return ERROR;

    }

    return OK;

  }

  else /* T */

    return ERROR;

}

Status DeleteChild(CSTree *T,CSTree p,int i)

{ /* 初始条件:树T存在,p指向T中某个结点,1≤i≤p所指结点的度 */

  /* 操作结果:删除Tp所指结点的第i棵子树 */

  /* 因为p所指结点的地址不会改变,故p不需是引用类型 */

  CSTree b;

  int j;

  if(*T) /* T不空 */

  {

    if(i==1) /* 删除长子 */

    {

      b=p->firstchild;

      p->firstchild=b->nextsibling; /* p的原次子现是长子 */

      b->nextsibling=NULL;

      DestroyTree(&b);

    }

    else /* 删除非长子 */

    {

      p=p->firstchild; /* p指向长子 */

      j=2;

      while(p&&i>j)

      {

        p=p->nextsibling;

        j++;

      }

      if(j==i) /* 找到第i棵子树 */

      {

        b=p->nextsibling;

        p->nextsibling=b->nextsibling;

        b->nextsibling=NULL;

        DestroyTree(&b);

      }

      else /* p原有孩子数小于i */

        return ERROR;

    }

    return OK;

  }

  else

    return ERROR;

}

void PostOrderTraverse(CSTree T,void(*Visit)(TElemType))

{ /* 后根遍历孩子兄弟二叉链表结构的树T */

  CSTree p;

  if(T)

  {

    if(T->firstchild) /* 有长子 */

    {

      PostOrderTraverse(T->firstchild,Visit); /* 后根遍历长子子树 */

      p=T->firstchild->nextsibling; /* p指向长子的下一个兄弟 */

      while(p)

      {

        PostOrderTraverse(p,Visit); /* 后根遍历下一个兄弟子树 */

        p=p->nextsibling; /* p指向再下一个兄弟 */

      }

    }

    Visit(Value(T)); /* 最后访问根结点 */

  }

}

void LevelOrderTraverse(CSTree T,void(*Visit)(TElemType))

{ /* 层序遍历孩子兄弟二叉链表结构的树T */

  CSTree p;

  LinkQueue q;

  InitQueue(&q);

  if(T)

  {

    Visit(Value(T)); /* 先访问根结点 */

    EnQueue(&q,T); /* 入队根结点的指针 */

    while(!QueueEmpty(q)) /* 队不空 */

    {

      DeQueue(&q,&p); /* 出队一个结点的指针 */

      if(p->firstchild) /* 有长子 */

      {

        p=p->firstchild;

        Visit(Value(p)); /* 访问长子结点 */

        EnQueue(&q,p); /* 入队长子结点的指针 */

        while(p->nextsibling) /* 有下一个兄弟 */

        {

          p=p->nextsibling;

          Visit(Value(p)); /* 访问下一个兄弟 */

          EnQueue(&q,p); /* 入队兄弟结点的指针 */

        }

      }

    }

  }

}

[编辑] 线索二叉树 (threaded binary tree)

线索二叉树(保留遍历时结点在任一序列的前驱和后继的信息):若结点有左子树,则其lchild域指示其左孩子,否则令lchild域指示其前驱;若结点有右子树,则其rchild域指示其右孩子,否则令rchild指示其后继。还需在结点结构中增加两个标志域LTagRTagLTag=0时,lchild域指示结点的左孩子,LTag=1时,lchild域指示结点的前驱;RTag=0时,rchild域指示结点的右孩子,RTag=1时,rchild域指示结点的后继。以这种结点结构构成的二叉链表作为二叉树的存储结构,叫做线索链表,其中指向结点前驱和后继的指针叫做线索,加上线索的二叉树称为线索二叉树。对二叉树以某种次序遍历使其变为线索二叉树的过程叫做线索化。若对二叉树进行中序遍历,则所得的线索二叉树称为中序线索二叉树,线索链表称为为中序线索链表。线索二叉树是一种物理结构。

在中序线索树找结点后继的规律是:若其右标志为1,则右链为线索,指示其后继,否则遍历其右子树时访问的第一个结点(右子树最左下的结点)为其后继;找结点前驱的规律是:若其左标志为1,则左链为线索,指示其前驱,否则遍历左子树时最后访问的一个结点(左子树中最右下的结点)为其前驱。在后序线索树中找到结点的后继分三种情况:

若结点是二叉树的根,则其后继为空;

若结点是其双亲的右孩子,或是其双亲的左孩子且其双亲没有右子树,则其后继即为双亲结点;

若结点是其双亲的左孩子,且其双亲有右子树,则其后继为双亲右子树上按后序遍历列出的第一个结点。

[编辑] 二叉线索存储表示

[编辑] 存储结构

二叉树的二叉线索存储表示:在线索链表上添加一个头结点,并令其lchild域的指针指向二叉树的根结点,其rchild域的指针指向中序遍历时访问的最后一个结点。令二叉树中序序列中的第一个结点的lchild域指针和最后一个结点的rchild域的指针均指向头结点,这样就建立了一个双向线索链表

/* 二叉树的二叉线索存储表示 */

typedef enum{Link,Thread}PointerTag; /* Link(0):指针,Thread(1):线索 */

typedef struct BiThrNode

{

  TElemType data;

  struct BiThrNode *lchild,*rchild; /* 左右孩子指针 */

  PointerTag LTag,RTag; /* 左右标志 */

}BiThrNode,*BiThrTree;

[编辑] 基本操作

/* 二叉树的二叉线索存储的基本操作 */

void CreateBiThrTree(BiThrTree *T)

{ /* 按先序输入线索二叉树中结点的值,构造线索二叉树T0(整型)/空格(字符型)表示空结点 */

  TElemType ch;

  scanf(form,&ch);

  if(ch==Nil)

    *T=NULL;

  else

  {

    *T=(BiThrTree)malloc(sizeof(BiThrNode)); /* 生成根结点(先序) */

    if(!*T)

      exit(OVERFLOW);

    (*T)->data=ch; /* 给根结点赋植 */

    CreateBiThrTree(&(*T)->lchild); /* 递归构造左子树 */

    if((*T)->lchild) /* 有左孩子 */

      (*T)->LTag=Link; /* 给左标志赋值(指针) */

    CreateBiThrTree(&(*T)->rchild); /* 递归构造右子树 */

    if((*T)->rchild) /* 有右孩子 */

      (*T)->RTag=Link; /* 给右标志赋值(指针) */

  }

}

BiThrTree pre; /* 全局变量,始终指向刚刚访问过的结点 */

void InThreading(BiThrTree p)

{ /* 通过中序遍历进行中序线索化,线索化之后pre指向最后一个结点。算法6.7 */

  if(p) /* 线索二叉树不空 */

  {

    InThreading(p->lchild); /* 递归左子树线索化 */

    if(!p->lchild) /* 没有左孩子 */

    {

      p->LTag=Thread; /* 左标志为线索(前驱) */

      p->lchild=pre; /* 左孩子指针指向前驱 */

    }

    if(!pre->rchild) /* 前驱没有右孩子 */

    {

      pre->RTag=Thread; /* 前驱的右标志为线索(后继) */

      pre->rchild=p; /* 前驱右孩子指针指向其后继(当前结点p) */

    }

    pre=p; /* 保持pre指向p的前驱 */

    InThreading(p->rchild); /* 递归右子树线索化 */

  }

}

void InOrderThreading(BiThrTree *Thrt,BiThrTree T)

{ /* 中序遍历二叉树T,并将其中序线索化,Thrt指向头结点。算法6.6 */

  *Thrt=(BiThrTree)malloc(sizeof(BiThrNode));

  if(!*Thrt) /* 生成头结点不成功 */

    exit(OVERFLOW);

  (*Thrt)->LTag=Link; /* 建头结点,左标志为指针 */

  (*Thrt)->RTag=Thread; /* 右标志为线索 */

  (*Thrt)->rchild=*Thrt; /* 右指针回指 */

  if(!T) /* 若二叉树空,则左指针回指 */

    (*Thrt)->lchild=*Thrt;

  else

  {

    (*Thrt)->lchild=T; /* 头结点的左指针指向根结点 */

    pre=*Thrt; /* pre(前驱)的初值指向头结点 */

    InThreading(T); /* 中序遍历进行中序线索化,pre指向中序遍历的最后一个结点 */

    pre->rchild=*Thrt; /* 最后一个结点的右指针指向头结点 */

    pre->RTag=Thread; /* 最后一个结点的右标志为线索 */

    (*Thrt)->rchild=pre; /* 头结点的右指针指向中序遍历的最后一个结点 */

  }

}

void InOrderTraverse_Thr(BiThrTree T,void(*Visit)(TElemType))

{ /* 中序遍历线索二叉树T(头结点)的非递归算法。算法6.5 */

  BiThrTree p;

  p=T->lchild; /* p指向根结点 */

  while(p!=T)

  { /* 空树或遍历结束时,p==T */

    while(p->LTag==Link) /* 由根结点一直找到二叉树的最左结点 */

      p=p->lchild;

    Visit(p->data); /* 访问此结点 */

    while(p->RTag==Thread&&p->rchild!=T) /* p->rchild是线索(后继),且不是遍历的最后一个结点 */

    {

      p=p->rchild;

      Visit(p->data); /* 访问后继结点 */

    }

    p=p->rchild; /* p->rchild不是线索(是右孩子)p指向右孩子,返回循环,*/

  }              /* 找这棵子树中序遍历的第1个结点 */

}

void PreThreading(BiThrTree p)

{ /* PreOrderThreading()调用的递归函数 */

  if(!pre->rchild) /* p的前驱没有右孩子 */

  {

    pre->rchild=p; /* p前驱的后继指向p */

    pre->RTag=Thread; /* pre的右孩子为线索 */

  }

  if(!p->lchild) /* p没有左孩子 */

  {

    p->LTag=Thread; /* p的左孩子为线索 */

    p->lchild=pre; /* p的左孩子指向前驱 */

  }

  pre=p; /* 移动前驱 */

  if(p->LTag==Link) /* p有左孩子 */

    PreThreading(p->lchild); /* p的左孩子递归调用preThreading() */

  if(p->RTag==Link) /* p有右孩子 */

    PreThreading(p->rchild); /* p的右孩子递归调用preThreading() */

}

void PreOrderThreading(BiThrTree *Thrt,BiThrTree T)

{ /* 先序线索化二叉树T,头结点的右指针指向先序遍历的最后1个结点 */

  *Thrt=(BiThrTree)malloc(sizeof(BiThrNode));

  if(!*Thrt) /* 生成头结点 */

    exit(OVERFLOW);

  (*Thrt)->LTag=Link; /* 头结点的左指针为孩子 */

  (*Thrt)->RTag=Thread; /* 头结点的右指针为线索 */

  (*Thrt)->rchild=*Thrt; /* 头结点的右指针指向自身 */

  if(!T) /* 空树 */

    (*Thrt)->lchild=*Thrt; /* 头结点的左指针也指向自身 */

  else

  { /* 非空树 */

    (*Thrt)->lchild=T; /* 头结点的左指针指向根结点 */

    pre=*Thrt; /* 前驱为头结点 */

    PreThreading(T); /* 从头结点开始先序递归线索化 */

    pre->rchild=*Thrt; /* 最后一个结点的后继指向头结点 */

    pre->RTag=Thread;

    (*Thrt)->rchild=pre; /* 头结点的后继指向最后一个结点 */

  }

}

void PreOrderTraverse_Thr(BiThrTree T,void(*Visit)(TElemType))

{ /* 先序遍历线索二叉树T(头结点)的非递归算法 */

  BiThrTree p=T->lchild; /* p指向根结点 */

  while(p!=T) /* p没指向头结点(遍历的最后1个结点的后继指向头结点) */

  {

    Visit(p->data); /* 访问根结点 */

    if(p->LTag==Link) /* p有左孩子 */

      p=p->lchild; /* p指向左孩子(后继) */

    else /* p无左孩子 */

      p=p->rchild; /* p指向右孩子或后继 */

  }

}

void PostThreading(BiThrTree p)

{ /* PostOrderThreading()调用的递归函数 */

  if(p) /* p不空 */

  {

    PostThreading(p->lchild); /* p的左孩子递归调用PostThreading() */

    PostThreading(p->rchild); /* p的右孩子递归调用PostThreading() */

    if(!p->lchild) /* p没有左孩子 */

    {

      p->LTag=Thread; /* p的左孩子为线索 */

      p->lchild=pre; /* p的左孩子指向前驱 */

    }

    if(!pre->rchild) /* p的前驱没有右孩子 */

    {

      pre->RTag=Thread; /* p前驱的右孩子为线索 */

      pre->rchild=p; /* p前驱的后继指向p */

    }

    pre=p; /* 移动前驱 */

  }

}

void PostOrderThreading(BiThrTree *Thrt,BiThrTree T)

{ /* 后序递归线索化二叉树 */

  *Thrt=(BiThrTree)malloc(sizeof(BiThrNode));

  if(!*Thrt) /* 生成头结点 */

    exit(OVERFLOW);

  (*Thrt)->LTag=Link; /* 头结点的左指针为孩子 */

  (*Thrt)->RTag=Thread; /* 头结点的右指针为线索 */

  if(!T) /* 空树 */

    (*Thrt)->lchild=(*Thrt)->rchild=*Thrt; /* 头结点的左右指针指向自身 */

  else

  { /* 非空树 */

    (*Thrt)->lchild=(*Thrt)->rchild=T; /* 头结点的左右指针指向根结点(最后一个结点) */

    pre=*Thrt; /* 前驱为头结点 */

    PostThreading(T); /* 从头结点开始后序递归线索化 */

    if(pre->RTag!=Link) /* 最后一个结点没有右孩子 */

    {

      pre->rchild=*Thrt; /* 最后一个结点的后继指向头结点 */

      pre->RTag=Thread;

    }

  }

}

void DestroyBiTree(BiThrTree *T)

{ /* DestroyBiThrTree调用的递归函数,T指向根结点 */

  if(*T) /* 非空树 */

  {

    if((*T)->LTag==0) /* 有左孩子 */

      DestroyBiTree(&(*T)->lchild); /* 销毁左孩子子树 */

    if((*T)->RTag==0) /* 有右孩子 */

      DestroyBiTree(&(*T)->rchild); /* 销毁右孩子子树 */

    free(*T); /* 释放根结点 */

    T=NULL; /* 空指针赋0 */

  }

}

void DestroyBiThrTree(BiThrTree *Thrt)

{ /* 初始条件:线索二叉树Thrt存在。操作结果:销毁线索二叉树Thrt */

  if(*Thrt) /* 头结点存在 */

  {

    if((*Thrt)->lchild) /* 根结点存在 */

      DestroyBiTree(&(*Thrt)->lchild); /* 递归销毁头结点lchild所指二叉树 */

    free(*Thrt); /* 释放头结点 */

    *Thrt=NULL; /* 线索二叉树Thrt指针赋0 */

  }

}