【2013微软校招面试题】输出节点数为n的二叉树的所有形态

 /*
 *  题意,求节点数为n的二叉树的所有形态,先要想个方式来唯一标示一棵二叉树
 *
 *  方法一:一个前序+一个中序,可以还原一棵唯一的二叉树,故使用【前序输出的字符串+中序输出的字符串】
 *  来唯一标示一棵二叉树。
 *
 *  方法二:【将一颗二叉树逐层遍历,若节点不为空,则记为X,为空记为O,最终得到的序列可以唯一标示一颗二叉树。】
 *
 *  建树过程采用递归,对已经建成的树的部分,每次节点逐一判断其左右儿子是否可以插入,可以的话,则插入,然后递归。
 *  直到数的大小达到n,则记录这棵树的唯一标示,然后返回!
 *
 *  output:  例如输入3,
 *  则输出结果,对应的二叉树如下所示:  
 *                  X               X                X                  X                     X
 *              X    O         X    O         O    X           O   X              X      X
 *           X   O         O   X                  X   O           O   X        O  O  O  O
 *        O   O               O   O           O   O                  O  O
 */

 

代码如下所示:

 

#include <iostream>
#include <string>
#include <map>
#include <vector>
using namespace std;

int n;   //二叉树有n个节点
map<string, int> m;

struct Node{
 Node * left;
 Node * right;
};

void PreOut(Node * head, string &s)  //先序输出,根左右
{
 s += "X";       //根
 if(head->left != NULL)   //左
  PreOut(head->left, s);
 else
  s += "O";
 if(head->right != NULL)  //右
  PreOut(head->right, s);
 else
  s += "O";
}

void MidOut(Node * head, string &s)  //中序输出,左根右
{
 if(head->left != NULL)   //左
  MidOut(head->left, s);
 else
  s += "O";
 s += "X";
 if(head->right != NULL)  //右
  MidOut(head->right, s);
 else
  s += "O";

}

//逐层遍历二叉树
void Bfs(Node * head, string &s)
{
 vector<Node *> vec;
 vec.push_back(head);
 for(int i=0; i<vec.size(); i++)
 {
  if(vec[i] != NULL)
  {
   s += "X";
   vec.push_back(vec[i]->left);  //左儿子入队,为NULL的时候也入队
   vec.push_back(vec[i]->right); //右儿子入队
  }
  else
   s += "O";
 }
}

 /*
 * head: 为整棵树的根节点
 * arr:  为二叉树节点的数组
 * now:  为当前已经建立的树的节点数
 * total:为输入n,总共的节点数
 * 建树时间复杂度: 卡特兰数复杂度  C(2*n,n)/(n+1)
 */
void BuildAllKindsTree(Node * head, Node * arr, int now, int total)
{
 if(now == total)  //成功建立一棵树
 {
  string s = "";
  //PreOut(head, s);
  //MidOut(head, s);
  Bfs(head, s);
  m[s]++;
  return;
 }

 for(int i=0; i<now; ++i) //当前建立的树已经有 now 个节点
 {
  if( arr[total - 1 - i].left == NULL ) //该节点左儿子位置可以链接个节点
  {
   arr[total - 1 - i].left = &arr[total - 1 - now];
   BuildAllKindsTree(head, arr, now+1, total);
   arr[total - 1 - i].left = NULL;  //递归回溯
  } 
  if( arr[total - 1 - i].right == NULL)  //该节点右儿子位置可以链接个节点
  {
   arr[total - 1 - i].right = &arr[total - 1 - now];
   BuildAllKindsTree(head, arr, now+1, total);
   arr[total - 1 - i].right = NULL;
  }
 }
}

void output()
{
 cout<<"*****************************************************************"<<endl;
 map<string, int>::iterator iter = m.begin();
 for(; iter != m.end(); iter++)
  cout<<iter->first<<endl;
 cout<<n<<"个节点的时候,二叉树总共有"<<m.size()<<"种情况。"<<endl;
 cout<<"*****************************************************************"<<endl;
}

int main()
{
 while(cin>>n)  
 {
  m.clear();
  Node * a = new Node[n];  //new出n个节点
  for(int i=0; i<n; i++) 
  {
   a[i].left = NULL;
   a[i].right = NULL;  
  }

  BuildAllKindsTree(&a[n-1], a, 1, n); 

  output();
  delete []a;
 }
}

 


 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值