判断一颗二叉树是否是完全二叉树
方法一,采取标记的方法
非完全二叉树的三种情况
思路分析:
通过层序遍历来遍历树中的每一个非空结点
- 遍历到的每一个结点都分为四种情况
- 1.既有左孩子也有右孩子
- 操作:将左孩子和右孩子入队列
- 2.只有左孩子
- 操作:
- 1.首先判断标记是否处于激活状态,如果标记处于激活状态,直接返回 false
- 2.满足标记条件,将标记设置为激活状态
- 操作:
- 3.只有右孩子
- 操作:直接返回 false,如果没有左结点而没有右结点,肯定不是一颗完全二叉树
- 4.没有孩子结点
- 操作:激活标记
- 1.既有左孩子也有右孩子
实现代码
/**
* 判断一棵二叉树是否是完全二叉树
*
* @return 如果是返回 true,否则返回 false
*/
public boolean isCompleteTree() {
if (root == null)
return true;
return isCompleteTree(root);
}
/**
* 通过层序遍历来遍历树中的每一个非空结点
* <p>
* 每一个结点都分为四种情况
* 1.既有左孩子也有右孩子
* 操作:将左孩子和右孩子入队列
* 2.只有左孩子
* 操作:
* 1.首先判断标记是否处于激活状态,如果标记处于激活状态,直接返回 false
* 2.满足标记条件,将标记设置为激活状态
* 3.只有右孩子
* 操作:直接返回 false,如果没有左结点而没有右结点,肯定不是一颗完全二叉树
* 4.没有孩子结点
* 操作:激活标记
* <p>
* 判断一棵二叉树是否是完全二叉树的实现
*
* @param root 根节点
* @return 如果是返回 true,否则返回 false
*/
private boolean isCompleteTree(Node<T> root) {
// 申请一个队列
ArrayDeque<Node<T>> queue = new ArrayDeque<>();
// 将根节点添加进去
queue.add(root);
// 定义一个临时结点,存储的值为队列的队头结点
Node<T> head;
// 定义一个标记,标记当前访问的结点出度是否为 2 ,如果结点只有左节点而没有右结点 flag = true
boolean flag = false;
while (!queue.isEmpty()) {
// 执行出队列操作
head = queue.pop();
// 如果结点的左子树为空但右子树不为空,此时不满足完全二叉树的条件,直接返回 false
if (head.left == null && head.right != null)
return false;
// 如果标志为 true,并且当前结点的左孩子结点不为空
if (flag && head.left != null)
return false;
// 如果当前结点的出度不为 2
if (head.left == null || head.right == null)
flag = true;
// 当前结点的左孩子不为空
if (head.left != null)
queue.add(head.left);
// 当前结点的右孩子不为空
if (head.right != null)
queue.add(head.right);
}
return true;
}
- 方法二,值为 null 的结点标记法
一颗完全二叉树
一颗非完全二叉树
思路分析:
- 通过层序遍历来遍历树中的每一个结点
- 采取特殊结点值为 null 替代 null 结点,入队列的标记方法
- 每一个结点分为两种情况
- 如果当前结点不为空,直接将当前结点入队列
- 如果当前结点为空,将结点值为 null 的标记结点入队列
- 当出队列的结点的值为标记结点 null 时,终止循环
- 接着循环队列,条件为队列不为空,进行出队列操作,
- 当出现队列出的结点的值不为 null 时,返回 false
- 循环结束,返回 true,说明是一个完全二叉树
实现代码
/**
* 判断一棵树是否是一个完全二叉树
*
* @return 如果是返回 true,否则返回 false
*/
public boolean isCompleteTree2() {
if (root == null)
return true;
return isCompleteTree2(root);
}
/**
* 通过层序遍历来遍历树中的每一个结点
* <p>
* 采取特殊结点值为 null 替代 null 结点,入队列的标记方法
* <p>
* 每一个结点分为两种情况
* 1.如果当前结点不为空,直接将当前结点入队列
* 2.如果当前结点为空,将结点值为 null 的结点入队列
* <p>
* 当出队列的结点的值为标记结点 null 时,终止循环
* <p>
* 接着循环队列,条件为队列不为空,进行出队列操作,
* 当出现队列出的结点的值不为 null 时,返回 false
* 循环结束,返回 true,说明是一个完全二叉树
* <p>
* <p>
* 判断一棵二叉树树是否是一颗完全二叉树的实现方法
*
* @param root 根节点
* @return 如果是返回 true,否则返回 false
*/
private boolean isCompleteTree2(Node<T> root) {
// 定义一个泛型为 Node 类型的队列
ArrayDeque<Node<T>> queue = new ArrayDeque<>();
// 将根节点入队列
queue.offer(root);
// 定义一个结点,值为队列的头一个
Node<T> node = queue.peek();
// 当结点的值为 标记节点 null 的时候,直接退出循环
while (null != node.value) {
queue.pop();
// 如果结点的左孩子不为 null,将左孩子入队列
// 否则插入一个值为 null 的 Node 对象
queue.offer(node.left != null ? node.left : new Node<>(null));
// 如果结点的左孩子不为 null,将左孩子入队列
queue.offer(node.right != null ? node.right : new Node<>(null));
node = queue.peek();
}
while (!queue.isEmpty())
if (queue.pop().value != null)
return false;
return true;
}