《恋上数据结构第1季》二叉树代码实现

二叉树(BinaryTree)

  • BinaryTree 基础

  • 遍历(先序、中序、后序、层次遍历)

    • 先序遍历: preorder()
  • 中序遍历: inorder()

  • 后序遍历: postorder()

  • 层次遍历: levelOrder()

  • 求二叉树的高度: height()

    • 递归实现
  • 迭代实现

  • 是否为完全二叉树: isComplaete()

  • 求二叉树的节点

    • 前驱节点: predecessor()
  • 后继节点: successor()

  • BinaryTreeInfo 工具

  • 二叉树完整源码

数据结构与算法笔记目录《恋上数据结构》 笔记目录

想加深 Java 基础推荐看这个Java 强化笔记目录

我们实现一个 通用二叉树(BinaryTree.java),里面包含所有二叉树类通用的代码。后面学到的 二叉搜索树AVL树红黑树 都需要继承这个 通用二叉树

这一篇是代码实现,先了解 二叉树基础知识

BinaryTree 基础

================================================================================

package com.mj.tree;

import java.util.LinkedList;

import java.util.Queue;

/**

  • 二叉树

*/

@SuppressWarnings(“unchecked”)

public class BinaryTree {

protected int size; // 元素数量

protected Node root; // 根节点

/**

  • 访问器接口 ——> 访问器抽象类

  • 增强遍历接口

*/

/*public static interface Visitor{

void visit(E element);

}*/

public static abstract class Visitor {

boolean stop;

// 如果返回true,就代表停止遍历

public abstract boolean visit(E element);

}

/**

  • 内部类,节点类

*/

public static class Node {

E element; // 元素值

Node left; // 左节点

Node right; // 右节点

Node parent; // 父节点

public Node(E element, Node parent) {

this.element = element;

this.parent = parent;

}

public boolean isLeaf() { // 是否叶子节点

return left == null && right == null;

}

public boolean hasTwoChildren() { // 是否有两个子节点

return left != null && right != null;

}

public boolean isLeftChild(){ // 判断自己是不是左子树

return parent!=null && this==parent.left;

}

public boolean isRightChild(){ // 判断自己是不是右子树

return parent!=null && this==parent.right;

}

/*

  • 返回兄弟节点

*/

public Node sibling() { // 红黑树中用到, 返回兄弟节点

if (isLeftChild()) {

return parent.right;

}

if (isRightChild()) {

return parent.left;

}

return null;

}

}

/**

  • 元素的数量

*/

public int size() {

return size;

}

/**

  • 是否为空

*/

public boolean isEmpty() {

return size == 0;

}

/**

  • 清空所有的元素

*/

public void clear() {

root = null;

size = 0;

}

/**

  • 创建节点的方法,用于给AVL树创建节点

*/

protected Node createNode(E element, Node parent){

return new Node<>(element, parent); // 默认返回一个通用节点

}

}

遍历(先序、中序、后序、层次遍历)

====================================================================================

先序遍历: preorder()


/**

  • 前序遍历(递归)

*/

public void preorder(Visitor visitor) {

if (visitor == null) return;

preorder(root, visitor);

}

public void preorder(Node node, Visitor visitor) {

if (node == null || visitor.stop) return;

// 根

visitor.stop = visitor.visit(node.element);

// 左

preorder(node.left, visitor);

// 右

preorder(node.right, visitor);

}

中序遍历: inorder()


/**

  • 中序遍历(递归)

*/

public void inorder(Visitor visitor) {

if (visitor == null) return;

inorder(root, visitor);

}

public void inorder(Node node, Visitor 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);

}

后序遍历: postorder()


/**

  • 后序遍历(递归)

*/

public void postorder(Visitor visitor) {

if (visitor == null) return;

postorder(root, visitor);

}

public void postorder(Node node, Visitor 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);

}

层次遍历: levelOrder()


/**

  • 层次遍历(队列)

*/

public void levelOrder(Visitor visitor){

if(root == null || visitor.stop) return;

Queue<Node> queue = new LinkedList<>(); // 队列

queue.offer(root);

while(!queue.isEmpty()){

Node 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);

}

}

}

求二叉树的高度: height()

====================================================================================

递归实现


/**

  • 求树的高度(递归)

*/

public int height() {

return height(root);

}

public int height(Node node) {

if (node == null) return 0;

return 1 + Math.max(height(node.left), height(node.right));

}

迭代实现


/**

  • 求树的高度高度(迭代)

*/

public int height() {

if (root == null) return 0;

// 存储每一层的元素数量, root!=null, 则首层必然有1个元素

int levelSize = 1;

int height = 0; // 树的高度

Queue<Node> queue = new LinkedList<>();

queue.offer(root);

while (!queue.isEmpty()) {

Node node = queue.poll();

levelSize–;

if (node.left != null) {

queue.offer(node.left);

}

if (node.right != null) {

queue.offer(node.right);

}

if (levelSize == 0) { // 即将要访问下一层

levelSize = queue.size(); // 下一层的元素数量

height++;

}

}

return height;

}

是否为完全二叉树: isComplaete()

==========================================================================================

/**

  • 是否是完全二叉树

*/

public boolean isComplete() {

if (root == null) return false;

Queue<Node> queue = new LinkedList<>();

queue.offer(root);

// leaf代表是否要求后面都是叶子节点

// 比如遍历到一个节点 left == null && right == null

// 或者是 left != null && right == null

// 则要求这个节点后面的节点都是叶子节点

boolean leaf = false;

while (!queue.isEmpty()) {

Node node = queue.poll();

// 要求是叶子结点,但是当前节点不是叶子结点

if (leaf && !node.isLeaf()) {

return false;

}

if (node.left != null) {

queue.offer(node.left);

} else if (node.right != null) {

// node.left == null && node.right != null

return false;

}

if (node.right != null) {

queue.offer(node.right);

} else {

// node.left == null && node.right == null

// node.left != null && node.right == null

leaf = true; // 要求后面都是叶子节点

}

}

return true;

}

求二叉树的节点

==========================================================================

前驱节点: predecessor()


在这里插入图片描述

/**

  • 前驱节点: 中序遍历时的前一个节点

  • 求前驱节点

*/

protected Node predecessor(Node node) {

if (node == null) return null;

// 前驱节点在左子树中(left.right.right.right…)

Node p = node.left;

if (p != null) {

// 左子树不为空,则找到它的最右节点

while (p.right != null) {

p = p.right;

}

return p;

}

// 能来到这里说明左子树为空, 则从父节点、祖父节点中寻找前驱节点

// 当父节点不为空, 且某节点为父节点的左子节点

// 则顺着父节点找, 直到找到【某结点为父节点或祖父节点的右子树中】时

while (node.parent != null && node.parent.left == node) {

node = node.parent;

}

// 来到这里有以下两种情况:

// node.parent == null 无前驱, 说明是根结点

// node.parent…right == node 找到【某结点为父节点或祖父节点的右子树中】

// 那么父节点就是某节点的前驱节点

return node.parent;

}

后继节点: successor()


在这里插入图片描述

/**

  • 后继节点: 中序遍历时的后一个节点

  • 求后继节点

*/

protected Node successor(Node node) {

if (node == null) return null;

// 后继节点与前驱节点正好相反

// 后继节点在右子树中(node.right.left.left…)

if (node.right != null) {

Node p = node.right;

while (p.left != null) {

p = p.left;

}

return p;

}

// 来到这里说明没有右节点, 则从父节点、祖父节点中寻找后继节点

// 当父节点不为空, 且某节点为父节点的右子节点

// 则顺着父节点找, 直到找到【某结点在父节点或祖父节点的左子树中】时

while (node.parent != null && node.parent.right == node) {

node = node.parent;

}

// 来到这里有以下两种情况:

// node.parent == null 无前驱,说明是根结点

// node.parent.left == node 找到【某结点在父节点或祖父节点的左子树中】

// 那么父节点就是某节点的后继节点

return node.parent;

}

BinaryTreeInfo 工具

====================================================================================

这是 MJ 老师自己写的一款工具,可以方便的打印二叉树,git 地址如下:https://github.com/CoderMJLee/BinaryTrees

/**

  • BinaryTreeInfo 工具,用来打印二叉树

*/

@Override

public Object root() {

return root;

}

@Override

public Object left(Object node) {

return ((Node)node).left;

}

@Override

public Object right(Object node) {

return ((Node)node).right;

}

@Override

public Object string(Object node) {

Node myNode = (Node)node;

String parentStr = “null”;

if(myNode.parent != null){

parentStr = myNode.parent.element.toString();

}

return myNode.element + “_p(” + parentStr + “)”;

}

二叉树完整源码

==========================================================================

package com.mj.tree;

import java.util.LinkedList;

import java.util.Queue;

import com.mj.printer.BinaryTreeInfo;

/**

  • 二叉树(通用)

*/

@SuppressWarnings(“unchecked”)

// 实现BinaryTreeInfo接口是为了使用打印二叉树的工具,非必须

public class BinaryTree implements BinaryTreeInfo {

protected int size; // 元素数量

protected Node root; // 根节点

/**

  • 访问器接口 ——> 访问器抽象类

  • 增强遍历接口

*/

/*public static interface Visitor{

void visit(E element);

}*/

public static abstract class Visitor {

boolean stop;

// 如果返回true,就代表停止遍历

public abstract boolean visit(E element);

}

/**

  • 内部类,节点类

*/

public static class Node {

E element; // 元素值

Node left; // 左节点

Node right; // 右节点

Node parent; // 父节点

public Node(E element, Node parent) {

this.element = element;

this.parent = parent;

}

public boolean isLeaf() { // 是否叶子节点

return left == null && right == null;

}

public boolean hasTwoChildren() { // 是否有两个子节点

return left != null && right != null;

}

public boolean isLeftChild(){ // 判断自己是不是左子树

return parent!=null && this==parent.left;

}

public boolean isRightChild(){ // 判断自己是不是右子树

return parent!=null && this==parent.right;

}

/*

  • 返回兄弟节点

*/

public Node sibling() { // 红黑树中用到, 返回兄弟节点

if (isLeftChild()) {

return parent.right;

}

if (isRightChild()) {

return parent.left;

}

return null;

}

}

/**

  • 元素的数量

*/

public int size() {

return size;

}

/**

  • 是否为空

*/

public boolean isEmpty() {

return size == 0;

}

/**

  • 清空所有的元素

*/

public void clear() {

root = null;

size = 0;

}

/**

  • 前序遍历

*/

public void preorder(Visitor visitor) {

if (visitor == null) return;

preorder(root, visitor);

}

public void preorder(Node node, Visitor visitor) {

if (node == null || visitor.stop) return;

// 根

visitor.stop = visitor.visit(node.element);

// 左

preorder(node.left, visitor);

// 右

preorder(node.right, visitor);

}

/**

  • 中序遍历

*/

public void inorder(Visitor visitor) {

if (visitor == null) return;

inorder(root, visitor);

}

public void inorder(Node node, Visitor 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);

}

/**

  • 后序遍历

*/

public void postorder(Visitor visitor) {

if (visitor == null) return;

postorder(root, visitor);

}

public void postorder(Node node, Visitor 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);

}

/**

  • 层次遍历

*/

public void levelOrder(Visitor visitor) {

if (root == null || visitor.stop) return;

Queue<Node> queue = new LinkedList<>(); // 队列

queue.offer(root);

while (!queue.isEmpty()) {

Node 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);

}

}

}

/**

  • 求树的高度(递归)

*/

public int height1() {

return height1(root);

}

public int height1(Node node) {

if (node == null) return 0;

return 1 + Math.max(height1(node.left), height1(node.right));

}

/**

  • 求树的高度高度(迭代)

*/

public int height() {

if (root == null) return 0;

int levelSize = 1; // 存储每一层的元素数量

int height = 0; // 树的高度

Queue<Node> queue = new LinkedList<>();

queue.offer(root);

while (!queue.isEmpty()) {

Node node = queue.poll();

levelSize–;

if (node.left != null) {

queue.offer(node.left);

}

if (node.right != null) {

queue.offer(node.right);

}

if (levelSize == 0) { // 即将要访问下一层

levelSize = queue.size();

height++;

}

}

return height;

}

/**

  • 是否是完全二叉树

*/

public boolean isComplete() {

if (root == null) return false;

Queue<Node> queue = new LinkedList<>();

queue.offer(root);

// leaf代表是否要求后面都是叶子节点

// 比如遍历到一个节点 left == null && right == null

// 或者是 left != null && right == null

// 则要求这个节点后面的节点都是叶子节点

boolean leaf = false;

while (!queue.isEmpty()) {

Node node = queue.poll();

// 要求是叶子结点,但是当前节点不是叶子结点

if (leaf && !node.isLeaf()) {

return false;

}

if (node.left != null) {

queue.offer(node.left);

} else if (node.right != null) {

// node.left == null && node.right != null

return false;

}

if (node.right != null) {

queue.offer(node.right);

} else {

// node.left == null && node.right == null

// node.left != null && node.right == null

leaf = true; // 要求后面都是叶子节点

}

}

return true;

}

/**

  • 前驱节点: 中序遍历时的前一个节点

  • 求前驱节点

*/

protected Node predecessor(Node node) {

if (node == null) return null;

// 前驱节点在左子树中(left.right.right.right…)

Node p = node.left;

if (p != null) {

// 左子树不为空,则找到它的最右节点

while (p.right != null) {

p = p.right;

}

return p;

}

// 能来到这里说明左子树为空, 则从父节点、祖父节点中寻找前驱节点

// 当父节点不为空, 且某节点为父节点的左子节点

// 则顺着父节点找, 直到找到【某结点为父节点或祖父节点的右子树中】时

while (node.parent != null && node.parent.left == node) {

node = node.parent;

}

// 来到这里有以下两种情况:

// node.parent == null 无前驱, 说明是根结点

// node.parent…right == node 找到【某结点为父节点或祖父节点的右子树中】

// 那么父节点就是某节点的前驱节点

return node.parent;

}

/**

  • 后继节点: 中序遍历时的后一个节点

  • 求后继节点

*/

protected Node successor(Node node) {

if (node == null) return null;

// 后继节点与前驱节点正好相反

// 后继节点在右子树中(node.right.left.left…)

if (node.right != null) {

Node p = node.right;

while (p.left != null) {

p = p.left;

}

return p;

}

// 来到这里说明没有右节点, 则从父节点、祖父节点中寻找后继节点

// 当父节点不为空, 且某节点为父节点的右子节点

// 则顺着父节点找, 直到找到【某结点在父节点或祖父节点的左子树中】时

while (node.parent != null && node.parent.right == node) {

node = node.parent;

}

// 来到这里有以下两种情况:

// node.parent == null 无前驱,说明是根结点

// node.parent.left == node 找到【某结点在父节点或祖父节点的左子树中】

// 那么父节点就是某节点的后继节点

return node.parent;

}

/**

  • 创建节点的方法,用于给AVL树创建节点

*/

protected Node createNode(E element, Node parent){

return new Node<>(element, parent); // 默认返回一个通用节点

}

/**

  • BinaryTreeInfo 工具,用来打印二叉树

*/

@Override

public Object root() {

return root;

}

@Override

public Object left(Object node) {

return ((Node) node).left;

}

@Override

public Object right(Object node) {

return ((Node) node).right;

}

@Override

public Object string(Object node) {

Node myNode = (Node) node;

String parentStr = “null”;

if (myNode.parent != null) {

parentStr = myNode.parent.element.toString();

}

return myNode.element + “_p(” + parentStr + “)”;

}

}

  • 11
    点赞
  • 13
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值