您的位置:首页 > 其它

L3-010. 是否完全二叉搜索树

2017-03-20 13:01 351 查看
将一系列给定数字顺序插入一个初始为空的二叉搜索树(定义为左子树键值大,右子树键值小),你需要判断最后的树是否一棵完全二叉树,并且给出其层序遍历的结果。

输入格式:

输入第一行给出一个不超过20的正整数N;第二行给出N个互不相同的正整数,其间以空格分隔。

输出格式:

将输入的N个正整数顺序插入一个初始为空的二叉搜索树。在第一行中输出结果树的层序遍历结果,数字间以1个空格分隔,行的首尾不得有多余空格。第二行输出“YES”,如果该树是完全二叉树;否则输出“NO”。
输入样例1:
9
38 45 42 24 58 30 67 12 51

输出样例1:
38 45 24 58 42 30 12 67 51
YES

输入样例2:
8
38 24 12 45 58 67 42 51

输出样例2:
38 45 24 58 42 12 67 51
NO

首先理解依据题意需要搞清楚几个理论,二叉树:一般c定义结构体,java定义类,里面分别都是数据data,左右孩子left,right;二叉搜索树:在二叉树的基础上,满足定义右子树键值大,左子树键值小; 注:(题目中给出的定义为左子树键值大,右子树键值小,但不影响,下述会讲到)完全二叉树:首先满足所有节点要嘛是叶节点,要嘛是左右孩子不为空的节点,并且最下面一层的结点都集中在该层最左边的若干位置的二叉树;
引论百度百科:完全二叉树概念

理解了上述几个概念,我们就可以做题了,首先建树方法与课上老师分享的博客相同方法,写好insert()方法,将数据一个一个插入即可构建出二叉搜索树。
根据题目的输出格式,首先我们需要解决层序输出,根据层序输出即从根节点开始一层一层输出,例如下图的二叉搜索树



其层序输出即为 12 8 14 10 。可以发现使用队列来处理会简易得多,即使把根节点入队列,当队列不为空的时候一直重复操作:弹出队列首元素,输出data,当此时的节点的左不为空时入队列,右不为空时入队列。根据这个顺序很自然的就输出了层序输出。
注:(由于题目所说的定义是左子树键值大,右子树键值小,所以我们在这时候处理左右孩子入队时,先把右孩子入队,再把左孩子入队即可。又或者直接在insert()插入方法里,将大值放在左孩子,小值放在右孩子也可)。

接着我们需要判断我们构建的二叉树是不是完全二叉树,根据上述完全二叉树的概念,建树必须是左右孩子不为空的节点,并且最下面一层的结点都集中在该层最左边的若干位置的二叉树,所以我们在建树的时候,或者在层序输出的时候对我们所构建的二叉搜索树编号,根据编号就可以判断出是不是完全二叉搜索树了。如下图



我们在层序遍历的时候对root节点id设为1,因此左右孩子的id必然为2跟3.
由队列遍历到 root.left节点的时候,也就是数据8所在的节点,因此其左右孩子的节点为4跟5,因为左孩子是空的,所以我们只需要入队右孩子即可
再遍历到 root.right节点,也就是数据14所在的节点时,因其左右孩子都为空,所以不用处理
最后遍历到数据10这个节点时,他的id为5,而我们建树所输入的数据只有4个,判断出id>n,所以其不是完全二叉搜索树。
而我们这时候可根据需求,我们的节点还需要一个id数据,所以在定义节点类或节点结构体的时候只需要加上id定义即可,比如java的节点类我们可以如下述定义
class Binarynode {
int data; //数据
int id; //我们需要使用到的id
Binarynode left, right; //同类型的左右孩子
}

而左右孩子的id可根据此时我们节点的id来定。
比如数据8的节点我们看成节点p,此时p.id=2,其左节点的id,即p.left.id=p.id*2;
其右节点的id,即p.right.id=p.id*2+1;

我们再举一个完全二叉树的例子看看是否符合,如下图:



当输入8个数据构建二叉搜索树,即n=8时,我们依据上面的规则来定义id,可发现id刚好定义到8,因此我们可根据这个方法来判断是不是完全二叉搜索树。
注:(在上阶段的各个树概念的理解很重要,最初对完全二叉树理解不完全,所以在判断完全二叉树上走了很多弯路,提交的时候有一组数据没有通过,所 以大家应理解清楚概念后再入手做题最佳)

以下是AC的代码

import java.util.*;

public class Main {

public static void main(String[] args) {
Scanner cin = new Scanner(System.in);

SearchTree tree = new SearchTree();

int n = cin.nextInt();
for (int i = 0; i < n; i++) {
tree.insert(cin.nextInt());
}

String cengxv = tree.cengxv(n);
System.out.println(cengxv.substring(0, cengxv.length() - 1)); //层序输出

if (tree.flag) { //输出是否完全二叉搜索树
System.out.println("NO");
} else {
System.out.println("YES");
}
}
}

class SearchTree {
Binarynode root;
boolean flag; //用来标记是不是完全二叉搜索树

public SearchTree() {
this.root = null;
flag = false;
}

public String cengxv(int n) { //层序遍历,以及对id的判断
String str = "";
Queue<Binarynode> q = new LinkedList<Binarynode>();
this.root.id = 1;
if (this.root != null) {
q.add(this.root);
}
while (!q.isEmpty()) {
Binarynode t = q.poll();
if (t.id > n) { //id比n大,即不是完全二叉搜索树
flag = true;
}
str += t.data + " ";
if (t.right != null) {
t.right.id = t.id * 2;
q.add(t.right);
}
if (t.left != null) {
t.left.id = t.id * 2 + 1;
q.add(t.left);
}

}
return str;
}

public void insert(int t) {
insert(this.root, t);
}

public void insert(Binarynode p, int t) { //插入方法
if (this.root == null) {
this.root = new Binarynode(t);
} else if (p.data < t) {
if (p.right == null) {
p.right = new Binarynode(t);
} else {
insert(p.right, t);
}
} else {
if (p.left == null) {
p.left = new Binarynode(t);
} else {
insert(p.left, t);
}
}
}
}

class Binarynode {
int data;
int id;
Binarynode left, right;

public Binarynode(int data, Binarynode left, Binarynode right) {
super();
this.data = data;
this.left = left;
this.right = right;
}

public Binarynode(int data) {
this(data, null, null);
}
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: