树的C代码实例

术语

  1. 节点的度:一个节点含有的子树的个数称为该节点的度;
  2. 树的度:一棵树中,最大的节点的度称为树的度;
  3. 叶节点终端节点:度为零的节点;
  4. 非终端节点分支节点:度不为零的节点;
  5. 父亲节点父节点:若一个节点含有子节点,则这个节点称为其子节点的父节点;
  6. 孩子节点子节点:一个节点含有的子树的根节点称为该节点的子节点;
  7. 兄弟节点:具有相同父节点的节点互称为兄弟节点;
  8. 节点的层次:从根开始定义起,根为第1层,根的子节点为第2层,以此类推;
  9. 树的高度深度:树中节点的最大层次;
  10. 堂兄弟节点:父节点在同一层的节点互为堂兄弟;
  11. 节点的祖先:从根到该节点所经分支上的所有节点;
  12. 子孙:以某节点为根的子树中任一节点都称为该节点的子孙。
  13. 森林:由m(m>=0)棵互不相交的树的集合称为森林;

树的种类

  • 无序树:树中任意节点的子节点之间没有顺序关系,这种树称为无序树,也称为自由树
  • 有序树:树中任意节点的子节点之间有顺序关系,这种树称为有序树;
    • 二叉树:每个节点最多含有两个子树的树称为二叉树;
      • 完全二叉树:对于一颗二叉树,假设其深度为d(d>1)。除了第d层外,其它各层的节点数目均已达最大值,且第d层所有节点从左向右连续地紧密排列,这样的二叉树被称为完全二叉树;
      • 满二叉树:对于上述的完全二叉树,如果去掉其第d层的所有节点,那么剩下的部分就构成一个满二叉树(此时该满二叉树的深度为d-1);
    • 霍夫曼树带权路径最短的二叉树称为哈夫曼树或最优二叉树;
    • B树

存储

父节点表示法

存储结构
/* 树节点的定义 */
#define MAX_TREE_SIZE 100
typedef struct
{
  TElemType data;
  int parent; /* 父节点位置域 */
} PTNode;
typedef struct
{
  PTNode nodes[MAX_TREE_SIZE];
  int n; /* 节点数 */
} PTree;
基本操作

设已有链队列类型LinkQueue的定义及基本操作(参见队列)。

构造空树

清空或销毁一个树也是同样的操作

void ClearTree(PTree *T)
{ 
  T->n = 0;
}
构造树
void CreateTree(PTree *T)
{ 
  LinkQueue q;
  QElemType p,qq;
  int i=1,j,l;
  char c[MAX_TREE_SIZE]; /* 临时存放孩子节点数组 */
  InitQueue(&q); /* 初始化队列 */
  printf("请输入根节点(字符型,空格为空): ");
  scanf("%c%*c",&T->nodes[0].data); /* 根节点序号为0,%*c吃掉回车符 */
  if(T->nodes[0].data!=Nil) /* 非空树 */
  {
    T->nodes[0].parent=-1; /* 根节点无父节点 */
    qq.name=T->nodes[0].data;
    qq.num=0;
    EnQueue(&q,qq); /* 入队此节点 */
    while(i<MAX_TREE_SIZE&&!QueueEmpty(q)) /* 数组未满且队不空 */
    {
      DeQueue(&q,&qq); /* 节点加入队列 */
      printf("请按长幼顺序输入节点%c的所有孩子: ",qq.name);
      gets(c);
      l=strlen(c);
      for(j=0;j<l;j++)
      {
        T->nodes[i].data=c[j];
        T->nodes[i].parent=qq.num;
        p.name=c[j];
        p.num=i;
        EnQueue(&q,p); /* 入队此节点 */
        i++;
      }
    }
    if(i>MAX_TREE_SIZE)
    {
      printf("节点数超过数组容量\n");
      exit(OVERFLOW);
    }
    T->n=i;
  }
  else
    T->n=0;
}
判断树是否为空
Status TreeEmpty(PTree *T)
{ /* 初始条件:树T存在。操作结果:若T为空树,则返回TRUE,否则返回FALSE */
  return T->n==0;
}
获取树的深度
int TreeDepth(PTree *T)
{ /* 初始条件:树T存在。操作结果:返回T的深度 */
  int k,m,def,max=0;
  for(k=0;k<T->n;++k)
  {
    def=1; /* 初始化本节点的深度 */
    m=T->nodes[k].parent;
    while(m!=-1)
    {
      m=T->nodes[m].parent;
      def++;
    }
    if(max<def)
      max=def;
  }
  return max; /* 最大深度 */
}
获取根节点
TElemType Root(PTree *T)
{ /* 初始条件:树T存在。操作结果:返回T的根 */
  int i;
  for(i=0;i<T->n;i++)
    if(T->nodes[i].parent<0)
      return T->nodes[i].data;
  return Nil;
}
获取第i个节点的值
TElemType Value(PTree *T,int i)
{ /* 初始条件:树T存在,i是树T中节点的序号。操作结果:返回第i个节点的值 */
  if(i<T->n)
    return T->nodes[i].data;
  else
    return Nil;
}
改变节点的值
Status Assign(PTree *T,TElemType cur_e,TElemType value)
{ /* 初始条件:树T存在,cur_e是树T中节点的值。操作结果:改cur_e为value */
  int j;
  for(j=0;j<T->n;j++)
  {
    if(T->nodes[j].data==cur_e)
    {
      T->nodes[j].data=value;
      return OK;
    }
  }
  return ERROR;
}
获取节点的父节点
TElemType Parent(PTree *T,TElemType cur_e)
{ /* 初始条件:树T存在,cur_e是T中某个节点 */
  /* 操作结果:若cur_e是T的非根节点,则返回它的父节点,否则函数值为"空"*/
  int j;
  for(j=1;j<T->n;j++) /* 根节点序号为0 */
    if(T->nodes[j].data==cur_e)
      return T->nodes[T->nodes[j].parent].data;
  return Nil;
}
获取节点的最左孩子节点
TElemType LeftChild(PTree *T,TElemType cur_e)
{ /* 初始条件:树T存在,cur_e是T中某个节点 */
  /* 操作结果:若cur_e是T的非叶子节点,则返回它的最左孩子,否则返回"空"*/
  int i,j;
  for(i=0;i<T->n;i++)
    if(T->nodes[i].data==cur_e) /* 找到cur_e,其序号为i */
      break;
  for(j=i+1;j<T->n;j++) /* 根据树的构造函数,孩子的序号>其父节点的序号 */
    if(T->nodes[j].parent==i) /* 根据树的构造函数,最左孩子(长子)的序号<其它孩子的序号 */
      return T->nodes[j].data;
  return Nil;
}
获取节点的右兄弟节点
TElemType RightSibling(PTree *T,TElemType cur_e)
{ /* 初始条件:树T存在,cur_e是T中某个节点 */
  /* 操作结果:若cur_e有右(下一个)兄弟,则返回它的右兄弟,否则返回"空"*/
  int i;
  for(i=0;i<T->n;i++)
    if(T->nodes[i].data==cur_e) /* 找到cur_e,其序号为i */
      break;
  if(T->nodes[i+1].parent==T->nodes[i].parent)
  /* 根据树的构造函数,若cur_e有右兄弟的话则右兄弟紧接其后 */
    return T->nodes[i+1].data;
  return Nil;
}
输出树
void Print(PTree *T)
{ /* 输出树T。加 */
  int i;
  printf("节点个数=%d\n",T->n);
  printf(" 节点 父节点\n");
  for(i=0;i<T->n;i++)
  {
    printf("    %c",Value(T,i)); /* 节点 */
    if(T->nodes[i].parent>=0) /* 有父节点 */
      printf("    %c",Value(T,T->nodes[i].parent)); /* 父节点 */
    printf("\n");
  }
}

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值