1064. Complete Binary Search Tree (30)

 距离PAT考试还有10天,最重要的是做透每一题

(1)思路

一旦知道了完全二叉树的节点个数那么这棵树的形状就固定了

比如n=3

                                 val1

       |                       |

      val2                    val3

又知道是一颗二叉排序树,所以有性质   左子树节点树是小于根的节点,右子树节点全是大于根的节点

所以在给节点排序后便可以根据这个性质将左右子树和根节点找到然后递归的进行找到根节点

这里先算出了该树的深度规定第一层深度为1

然后算出左子树的节点数

这里的index为节点的数组中的索引,虽然是用前序遍历的各个节点,但是 我们知道完全二叉树中每个节点 i 的的左右儿子序号是2*i+1,和2*i+2

前n个必定是所有的节点,但是如果是一般二叉树则要注意节点可能不存在前n个位置

#include <cstdio>
#include <vector>
#include <algorithm>
#include <cmath>
using namespace std;

int n;
vector<int> tree;
vector<int> res;

void inord(int n,vector<int> t,int index) {
  if(n == 0) return;
  if(n == 1) {
    res[index]=t[0];
    return;
  }
  int i=1;//层数
  while((int)pow(2,i)-1 < n) i++;
  int subnum=((int)(pow(2,i))-((int)pow(2,i-1)))/2;
  //  printf("i:%d subnum:%d
",i,subnum);
  //  if(subnum == 0) do something return; 不可能存在这就是只有一个节点的情况
  //至少有2层
  int dif=((int)pow(2,i-2))-1;
  //printf("dif:%d
",dif);
  int left=0;
  if(n -((int)pow(2,i-1))+1 > subnum) {
    left=subnum+dif;
  } else {
    left=n-((int)pow(2,i-1))+1+dif;
  }
  // printf("left:%d
",left);
  int root=t[left];
  //printf("root:%d
",root);
  res[index]=root;
  vector<int> ltr;
  vector<int> rtr;
  for(int i=0;i<n;i++) {
    if(i != left) {
      if(t[i] < root) ltr.push_back(t[i]);
      else if(t[i] >= root) rtr.push_back(t[i]);
    }
  }
  //  printf("%d %d
",ltr.size(),rtr.size());
  sort(ltr.begin(),ltr.end());
  sort(rtr.begin(),rtr.end());
  inord(ltr.size(),ltr,2*index+1);
  inord(rtr.size(),rtr,2*index+2);
}

int main() {
  scanf("%d",&n);
  tree.resize(n);
  res.resize(n);
  for(int i=0;i<n;i++) {
    scanf("%d",&tree[i]);
  }
  sort(tree.begin(),tree.end());
  inord(n,tree,0);
  //  printf("%d
",res.size());
  for(int i=0;i<n;i++) {
    i==0? printf("%d",res[i]):printf(" %d",res[i]);
  }
  return 0;
}

其实根据排序二叉树的性质,一组从小到大排序的数就是其中序,所以这题就是中序转层序

只要找到根,然后递归进行就可以了

(2)也可以不找根节点

在遍历中序序列的时候,填入节点

#include <cstdio>
#include <vector>
#include <algorithm>
using namespace std;

int n;
int index=0;
vector<int> v;
vector<int> rs;

void built(int root) {
  if(root >= n) return;
  built(root*2+1);      //建立左子树
  rs[root]=v[index++]; //
  built(root*2+2);      //
}

int main() {
  scanf("%d",&n);
  v.resize(n);
  rs.resize(n);
  for(int i=0;i<n;i++) {
    scanf("%d",&v[i]);
  }
  sort(v.begin(),v.end());
  built(0);
  for(int i=0;i<n;i++) {
    i==0? printf("%d",rs[i]):printf(" %d",rs[i]);
  }
  return 0;
}

我们在来总结一下,之所以可以这样写是因为如果给各节点从零开始编号 i 节点的左右子树的根节点 为 2*i+1 和 2*i+2

在这种情况下,给出中序,前序,后序都很容易得到该树的层序

换而言之,如果不是完全二叉树,那么节点间的性质就不满足2*i+1和2*i+2的性质了此时就不能用这个方法来得到层序

原文地址:https://www.cnblogs.com/tclan126/p/8529728.html