二叉链表表示的森林的若干基本问题

1.层次遍历森林
思想:
层次遍历的算法用到了两个队列,第一个队列按顺序存储森林中每一棵树的根节点,第二个队列按层次的顺序存储每一棵树的所有结点,同时入队,同时出队,是一个动态的过程。循环控制依次输出每一棵树,条件是第一个队列不为空。
首先将根节点入队,同时输出根节点的值。接下来循环控制输出其他结点,条件是第二个队列不为空。临时指针p指向队列第一位的第一个孩子,再进入一个循环,如果p不为空,则输出其值并将p的兄弟赋值给p,不断重复,直到p变成空为止。在这个过程中,对于每一个p,检查其有没有孩子,如果有就将它入队,便于下一次输出它的孩子。结束之后该结点以及他的所有兄弟已经输出,将该节点出队,进入下一轮循环。
处理完一棵树后,也要把刚处理完的树的根节点出队。

上机代码

void LevelOrder(csNode *t)
{
 queue<csNode*> q1;//有序存放的是森林中每一个树的根节点 
 queue<csNode*> q2;//按照层次顺序存放每一颗树除了根节点以外的其他节点 
 csNode *p = t;
 while(p)
 {
  q1.push(p);
  p = p -> nextSibling;
 }//将每颗树的根节点入队
  
 while(q1.empty() == false)//对于每一颗单独的树 
 {
  printf("%c ",q1.front() -> data);//输出根节点 
  q2.push(q1.front());//根节点入队 
  while(q2.empty() == false)
  {
   p = q2.front() -> firstChild;//取队首元素的第一个孩子 
   while(p)
   {
    printf("%c ",p -> data);
    if(p -> firstChild)
    {
     q2.push(p);//如果这一层某个节点有孩子则把该节点入队,准备下次把他的孩子输出 
    }
    p = p -> nextSibling;//不断横向遍历输出同一层次的节点 
   }
   q2.pop();//处理完一层的节点后要出队 
  }
  q1.pop();//处理完一棵树之后要出队去以相同方式遍历下一颗树 
 }
} 

2.求森林的高度。

思想:求森林的高度采用递归的思想。如果结点不为空则递归求其左子树的高度和右子树的高度,则当前树的高度就是左子树的高度加一或右子树的高度(因为右子树是兄弟高度相对当前节点没有变化),取两者中较大的那一个。

上机代码:

int Height(csNode *t)//求森林高度的递归算法部分 
{
 int lh,rh;
 if(t)
 {
  lh = Height(t -> firstChild);//求子树的高度 
  rh = Height(t -> nextSibling);//求相邻兄弟的高度 
  if(lh + 1 > rh)//如果该节点的高度(子树的高度加上1)比相邻兄弟高 
  {
   return lh + 1;
  }
  else
  {
   return rh;
  }   
 }
 return 0; 
}

3.输出广义表表示的树。
思想:
通过观察可以得知广义表的元素的顺序刚好就是树的先序遍历的顺序而且这样的左括号,右括号的表达形式也符合入栈出栈的操作,所以用栈来实现这个算法。这个算法是根据二叉树的非递归先序遍历而改编,在二叉树非递归先序遍历算法的基础上,当入栈时候就要输出括号和当前元素的值,如果要和后面的元素进行区分的话要加上一个逗号。如果后面那个元素的值也就是当前节点的first child的值如果不为空的话那么下一次仍然还是入栈的,这个时候就要加在后面加上逗号,以表示区分。如果下一个结点不存在,那么这个时候就是出栈的操作了,这个时候后面就不需要加逗号了。

在出栈的操作代码块里面首先要取栈顶的元素的右孩子,也就是当前那个空结点的父结点的右孩子,取完之后弹栈。接下来判断这个右孩子是空的还是非空的,如果是空的话那么他接下来就要去进入到入栈的这个过程当中,那么就需要在右括号的基础上加上一个逗号,因为后面还有其他的元素要区分开来。如果这个元素还是空的话那么第二次还是在出栈的代码块里,那么就不需要在后面加逗号以区分,因为下一次输出的还是括号。
(注:关于森林的广义表表示形式,我问了我的老师,好像没有特别严格的定义,不同表示方法之间有些细微的区别,欢迎明白的小伙伴指正)

上机代码:

void ForestToLists(csNode *t)
{
 //该算法根据非递归先序遍历算法改造而来 
 stack<csNode*> s;
 csNode *p = t;
 while(p != NULL || s.empty() == false)
 {
  if(p)
  {
   if(p -> firstChild)
   {
    printf("(%c,",p -> data);
   }//如果下一个输出的符号还是左括号则需要加一个逗号 
   else
   {
    printf("(%c",p -> data);
   }//如果下一个输出的是右括号则不需要加逗号   
   s.push(p);
   p = p -> firstChild;
  }
  else
  {
   p = s.top() -> nextSibling;
   s.pop();
   if(p)//如果下一个输出的是左括号则需要加逗号   
   {
    printf("),");
   }
   else//若下次输出的仍然是右括号则无需加逗号 
   {
    printf(")");
   }
  }
 }
} 

本人的博客记录我学习计算机期间的收获,历程和遇到的问题,欢迎大家交流哦!

  • 2
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值