天天看点

POJ4082树的镜面转换--左子右兄数与树的转换(一)

一棵树的镜面映射指的是对于树中的每个结点,都将其子结点反序。例如,对左边的树,镜面映射后变成右边这棵树。

    a                             a

  / | \                         / | \

b  c  f       ===>            f  c  b

   / \                           / \

  d   e                         e   d

我们在输入输出一棵树的时候,常常会把树转换成对应的二叉树,而且对该二叉树中只有单个子结点的分支结点补充一个虚子结点“$”,形成“伪满二叉树”。

例如,对下图左边的树,得到下图右边的伪满二叉树

    a                             a

  / | \                          / \

b  c  f       ===>             b   $

   / \                         / \

  d   e                       $   c                          

                                 / \

                                d   f

                               / \

                              $   e

然后对这棵二叉树进行前序遍历,如果是内部结点则标记为0,如果是叶结点则标记为1,而且虚结点也输出。

现在我们将一棵树以“伪满二叉树”的形式输入,要求输出这棵树的镜面映射的宽度优先遍历序列。

输入

输入包含一棵树所形成的“伪满二叉树”的前序遍历。

第一行包含一个整数,表示结点的数目。

第二行包含所有结点。每个结点用两个字符表示,第一个字符表示结点的编号,第二个字符表示该结点为内部结点还是外部结点,内部结点为0,外部结点为1。结点之间用一个空格隔开。

数据保证所有结点的编号都为一个小写字母。

输出

输出包含这棵树的镜面映射的宽度优先遍历序列,只需要输出每个结点的编号,编号之间用一个空格隔开。

样例输入

9

a0 b0 $1 c0 d0 $1 e1 f1 $1

样例输出

a f c b e d

解题思路:      

这道题有以下几点注意的地方:

1.输入处理,用getchar()接收输入字符,用于滤掉换行与空格,用InputIn[]接收最终输入的字符

2.内外标识‘0’‘1’是字符形式!InputIn[]偶数位是真正的节点信息,奇数位是‘0‘或’1’

3.构建LCRS树时,将标识‘0’的节点指针存放到栈中,先插左边,再插右边,左右都满,回溯上级插右边!

4.利用BFS框架,购置一个队列,将父节点的所有子节点依次压入到队列中,镜像之后,利用栈将队列中的节点

倒序,每个非'$'key值的节点都将key值打印出来,ok大体思路如上!

#include<iostream>
#include<stdio.h>
#include<stack>
#include<queue>
using namespace std;
const int MAX = 10000;//这棵树最多有10000个节点
char InputIn[2 * MAX];//这个数组存放MAX对(节点字母,0/1)
char OutPut[MAX];//存放待输出的字符
//每一个点的数据结构
typedef struct _Node
{
  char key;
  struct _Node *lchild;
  struct _Node *rchild;
}Node;
//定义全局变量栈
stack<Node *> s;//这个栈存放所有可能成为父节点的节点的指针
queue<Node *> q;//存放镜面对称后的节点序列
stack<Node *> t;//用于逆序
Node* CreateBiTree(int n)
{
  Node* root = new Node;
  Node* father = new Node;
  root->key = InputIn[0];
  root->lchild = root->rchild = NULL;
  s.push(root);
  for (int i = 2; i < n * 2; i += 2)//偶数个i意图是将数字滤掉,这样InputIn[i]一定是字母~,步长为2
  {
    Node *temp = new Node;
    temp->key = InputIn[i];
    temp->lchild = temp->rchild = NULL;
    father = s.top();
    if (father->lchild == NULL)//当前父节点没有左节点
    {
      father->lchild = temp;
    }
    else if (father->rchild == NULL)//当前父节点有左节点,但是没有右节点
    {
      father->rchild = temp;
    }
    else//当前父节点左右子节点都有,退栈,寻找栈中右节点为空的节点
    {
      while (s.top()->rchild != NULL) { s.pop(); }
      father = s.top();//s.top()->rchild == NULL 
      father->rchild = temp;
    }
    if (InputIn[i + 1] == '0')//0说明这个点是内节点,不是叶子结点,可以成为父节点
    {
      s.push(temp);//1说明这个点是叶子结点或者没有节点占位的$
    }
  }
  return root;
}
void MirrorTrans(Node *root)
{
  q.push(root);
  Node *father;
  while (!q.empty())
  {
    father = q.front();
    q.pop();
    if (father->key != '$') { /*cout << father->key << " ";*/ printf("%c ", father->key); }
    if (father->lchild)//如果它有儿子节点
    {
      Node *temp = father->lchild;
      while (temp)
      {
        t.push(temp);//将当前父节点的所有子节点都压入栈中
        //q.push(temp);
        temp = temp->rchild;
      }
    }
    while (!t.empty())
    {
      q.push(t.top());
      t.pop();
    }
  }
}
int main()
{
  int n; char c; int i = 0;
  Node *root;
  scanf("%d", &n);
  getchar();//滤掉换行'\n'
  while ((c = getchar()) != '\n')//滤掉空格
  {
    if (c != ' ')
    {
      InputIn[i++] = c;
    }
  }
  root = CreateBiTree(n);
  MirrorTrans(root);
  return 0;
}