标签:结束 开始 结构 基本 offer 顺序 class ima 判断
树结构基本概念:
节点、根节点、父节点、子节点、兄弟节点、子树、左子树、右子树;
空树:没有任何节点的树;
节点的度:子树的个数
树的度:所有节点度中的最大值(max)
叶子节点:度为0的节点
非叶子节点:度不为0的节点
层数:根节点在第一层,根节点的子节点在第二层,以此类推
节点的深度:从根节点到当前节点的唯一路径上的节点总数
节点的高度:从当前节点到最远叶子节点的路径上的节点总数
树的深度:所有节点深度中的最大值
树的高度:所有节点高度中的最大值
树的高度==树的深度
假如有一颗完全二叉树有768个节点,求叶子节点的个数
解:假设叶子节点个数为n0,度为1的节点个数为n1,度为2的节点个数为n2(n=2n0+n1-1).
又因为完全二叉树的n1要么为1,要么为0. n1为1时,n=2n0,n必然为偶数,则叶子节点n0 = n/2. n1为0时,n=2n0 - 1, n必然是奇数, 则叶子节点n0 = (n+1)/2。
总结:叶子节点n0 = floor((n+1)/2) = ceiling(n/2) 非叶子节点n1+n2 = floor(n/2) = ceiling((n-1)/2).
所以此题的叶子节点个数为384.
//递归实现前序遍历
public void preorder(Visitor<E> visitor) {
if (visitor == null) return;
preorder(root, visitor);
}
private void preorder(Node<E> node, Visitor<E> visitor) {
if (node == null || visitor.stop) return;
visitor.stop = visitor.visit(node.element);
preorder(node.left, visitor);
preorder(node.right, visitor);
}
/**
* 前序遍历(非递归遍历)(使用Stack实现)
* @param visitor
*/
public void preorder(Visitor<E> visitor) {
if (visitor == null || root == null) return;
Stack<Node<E>> stack = new Stack<>();
stack.push(root);//将根节点入栈
while (!stack.isEmpty()){//栈不空执行while循环
Node<E> node = stack.pop();//取出栈顶节点
//访问node节点
if (visitor.visit(node.element)) return;
//node的右子节点不为空时,右子节点入栈
if (node.right != null) stack.push(node.right);
//node的左子节点不为空时,左子节点入栈
if (node.left != null) stack.push(node.left);
}
}
//前序遍历方式二(非递归遍历)(使用Stack实现)
public void preorder2(Visitor<E> visitor) {
if (visitor == null || root == null) return;
Node<E> node = root;
Stack<Node<E>> stack = new Stack<>();
while (true){
if (node != null){
//访问node节点
if (visitor.visit(node.element)) return;
//将右子节点入栈
if (node.right != null) stack.push(node.right);
//向左走
node = node.left;
} else {
//若栈空了,便结束方法
if (stack.isEmpty()) return;
//处理右边节点
node = stack.pop();
}
}
}
//递归方式实现中序遍历
public void inorder(Visitor<E> visitor) {
if (visitor == null) return;
inorder(root, visitor);
}
private void inorder(Node<E> node, Visitor<E> visitor) {
if (node == null || visitor.stop) return;
inorder(node.left, visitor);
if (visitor.stop) return;
visitor.stop = visitor.visit(node.element);
inorder(node.right, visitor);
}
/**
* 中序遍历(非递归遍历)(使用Stack实现)
* @param visitor
*/
public void inorder(Visitor<E> visitor) {
if (visitor == null || root == null) return;
Node<E> node = root;
Stack<Node<E>> stack = new Stack<>();
while (true){
if (node != null){
stack.push(node);
//向左走
node = node.left;
} else {
//若栈空了,便结束方法
if (stack.isEmpty()) return;
node = stack.pop();
//访问node节点
if (visitor.visit(node.element)) return;
//让右节点进行中序遍历
node = node.right;
}
}
}
//递归方式实现后序遍历
public void postorder(Visitor<E> visitor) {
if (visitor == null) return;
postorder(root, visitor);
}
private void postorder(Node<E> node, Visitor<E> visitor) {
if (node == null || visitor.stop) return;
postorder(node.left, visitor);
postorder(node.right, visitor);
if (visitor.stop) return;
visitor.stop = visitor.visit(node.element);
}
/**
* 后序遍历(非递归遍历)(使用Stack实现)
* @param visitor
*/
public void postorder(Visitor<E> visitor) {
if (visitor == null || root == null) return;
//记录上一次弹出访问的节点
Node<E> prev = null;
Stack<Node<E>> stack = new Stack<>();
while (!stack.isEmpty()){
Node<E> top = stack.peek();//获取栈顶节点,但并不取出栈顶节点
//若栈顶元素为叶子节点或者栈顶元素为上一个弹出元素的子节点,则执行
if (top.isLeaf() || (prev != null && prev.parent == top)){
prev = stack.pop();
//访问节点
if (visitor.visit(prev.element))return;
} else {
if (top.right != null) stack.push(top.right);
if (top.left != null) stack.push(top.left);
}
}
}
public void levelOrder(Visitor<E> visitor) {
if (root == null || visitor == null) return;
Queue<Node<E>> queue = new LinkedList<>();
queue.offer(root);
while (!queue.isEmpty()) {
Node<E> node = queue.poll();
if (visitor.visit(node.element)) return;
if (node.left != null) {
queue.offer(node.left);
}
if (node.right != null) {
queue.offer(node.right);
}
}
}
定义:中序遍历时的前一个节点(如果说二叉搜索树,前驱节点就是前一个比它小的节点)
代码实现:
/**
* 前驱节点:中序遍历时,某节点的前一个节点
* 求前驱节点
* @param node
* @return 前驱节点
*/
private Node<E> predecessor(Node<E> node){
if (node == null) return null;
//从当前节点的左子树中寻找前驱节点(node.left.right.right...)
Node<E> p = node.left;
if(p != null){
//获取到左子树最右的节点
while (p.right != null) {
p = p.right;
}
return p;
}
//从父节点||祖父节点中寻找前驱节点(node.parent.parent...)
//终止条件:当前节点为父节点的右子树,此时的父节点就是前驱节点
while (node.parent != null && node == node.parent.left){
node = node.parent;
}
/**
* 到达此处的代码符合的条件为
* node.parent == null;
* node == node.parent.right
*/
return node.parent;
}
定义:中序遍历时的后一个节点(如果说二叉搜索树,后继节点就是后一个比它大的节点)
代码实现:
/**
* 后继节点:中序遍历时,某节点的后一个节点
* 求后继节点
* @param node
* @return 后继节点
*/
private Node<E> successor(Node<E> node){
if (node == null) return null;
//从当前节点的右子树中寻找后继节点(node.right.left.left...)
Node<E> p = node.right;
if(p != null){
//获取到右子树最左的节点
while (p.left != null) {
p = p.left;
}
return p;
}
//从父节点||祖父节点中寻找后继节点(node.parent.parent...)
//终止条件:当前节点为父节点的左子树,此时的父节点就是后继节点
while (node.parent != null && node == node.parent.right){
node = node.parent;
}
return node.parent;
}
//层序遍历二叉树(用队列)
public boolean isComplete(){
if (root == null) return false;
Queue<Node<E>> queue = new LinkedList<>();
queue.offer(root);
boolean leaf = false;//节点是否为叶子节点
while (!queue.isEmpty()){
Node<E> node = queue.poll();
//如果当前节点在应该为叶子节点时,不为叶子节点,那此二叉树不是完全二叉树
if(leaf && !node.isLeaf()) return false;
if (node.left != null){
queue.offer(node.left);
} else if (node.right != null){
//左子节点为i空,右子节点不为空,此树不为完全二叉树
return false;
}
if (node.right != null){
queue.offer(node.right);
} else {
//左子节点可能为空,可能不空,但右子节点一定为空
//此时的节点应该为叶子节点
leaf = true;
}
}
return true;
}
标签:结束 开始 结构 基本 offer 顺序 class ima 判断
原文地址:https://www.cnblogs.com/Java0120/p/12584924.html