二叉树
二叉树:二叉树是每个节点最多有两个子树的树结构;是n(n>=0)个结点的有限集合,它或者是空树(n=0),或者是由一个根结点及两颗互不相交的、分别称为左子树和右子树的二叉树所组成。
完全二叉树
完全二叉树:除最后一层外,每一层上的结点数均达到最大值;在最后一层上只缺少右边的若干结点;
满二叉树
满二叉树:除最后一层外,每一层上的所有结点都有两个子结点;满二叉树是一种特殊的完全二叉树;
二叉排序树(二叉搜索树)
二叉搜索树是二叉树的一种,是应用非常广泛的一种二叉树,英文简称为 BST 又被称为:二叉查找树、二叉排序树
- 任意一个节点的值都大于其左子树所有节点的值
- 任意一个节点的值都小于其右子树所有节点的值
- 它的左右子树也是一棵二叉搜索树
二叉排序(搜索)树:二叉树中,每个节点都不比它左子树的任意元素小,而且不比它的右子树的任意元素大。又叫二叉搜索树。
平衡二叉树
平衡二叉树(Balanced Binary Tree)是二叉查找树的一个进化体,也是第一个引入平衡概念的二叉树。1962年,G.M. Adelson-Velsky 和 E.M. Landis发明了这棵树,所以它又叫AVL树。
平衡二叉树要求对于每一个节点来说,它的左右子树的高度之差不能超过1,如果插入或者删除一个节点使得高度之差大于1,就要进行节点之间的旋转,将二叉树重新维持在一个平衡状态。
这个方案很好的解决了二叉查找树退化成链表的问题,把插入,查找,删除的时间复杂度最好情况和最坏情况都维持在O(logN)。但是频繁旋转会使插入和删除牺牲掉O(logN)左右的时间,不过相对二叉查找树来说,时间上稳定了很多。
二叉树遍历
package com.michealkz.tree;
import com.michealkz.printer.BinaryTreeInfo;
import java.util.Comparator;
import java.util.LinkedList;
import java.util.Queue;
/**
* 二叉搜索树继承自BinaryTreeInfo 实现其中的方法以便进行打印
*
* @param <E>
*/
public class BinarySearchTree<E> implements BinaryTreeInfo {
private int size;
private Node<E> root;
private Comparator<E> comparator;
public int size() {
return size;
}
public boolean isEmpty() {
return size == 0;
}
public void clear() {
root = null;
size = 0;
}
public void add(E element) {
elementNotNullCheck(element);
// 添加第一个节点
if (root == null) {
root = new Node<E>(element, null);
size++;
return;
}
// 添加的不是第一个节点 则找到父节点
Node<E> parent = root;
Node<E> node = root;
int cmp = 0;
do {
/*
* 根据compare的返回值正负或者相等来判断是左子树还是右子树还是相等
*/
cmp = compare(element, node.element);
// 将节点保存下来作为查找下一个的父节点
parent = node;
if (cmp > 0) {
node = node.right;
} else if (cmp < 0) {
node = node.left;
} else {
// 相等
node.element = element;
return;
}
} while (node != null);
// 看看插入到父节点的哪个位置
Node<E> newNode = new Node<E>(element, parent);
if (cmp > 0) {
parent.right = newNode;
} else {
parent.left = newNode;
}
size++;
}
/*
* @return 返回值等于0,代表e1和e2相等;返回值大于0,代表e1大于e2;返回值小于于0,代表e1小于e2
*/
private int compare(E e1, E e2) {
if (comparator != null) {
return comparator.compare(e1, e2);
}
return ((Comparable<E>) e1).compareTo(e2);
}
private void elementNotNullCheck(E element) {
if (element == null) {
throw new IllegalArgumentException("element must not be null");
}
}
// 二叉树的前序遍历操作
public void preorderTraversal() {
preorderTraversal(root);
}
// 二叉树的前序遍历传入根节点进行遍历操作
private void preorderTraversal(Node<E> node) {
if (node == null) return;
System.out.print(node.element + "\t");
preorderTraversal(node.left);
preorderTraversal(node.right);
}
// 二叉树中序遍历
public void middleOrderTraversal() {
middleOrderTraversal(root);
}
// 二叉树中序遍历实现逻辑
private void middleOrderTraversal(Node<E> node) {
if (node == null) return;
middleOrderTraversal(node.left);
System.out.print(node.element + "\t");
middleOrderTraversal(node.right);
}
// 二叉树后序遍历
public void postOrderTraversal() {
postOrderTraversal(root);
}
// 二叉树后序遍历实现
private void postOrderTraversal(Node<E> node) {
if (node == null) return;
postOrderTraversal(node.left);
postOrderTraversal(node.right);
System.out.print(node.element + "\t");
}
// 二叉树层序遍历
public void levelOrderTraversal() {
levelOrderTraversal(root);
}
// 二叉树层序遍历实现逻辑
/**
* 二叉树层序遍历很重要
* 遍历思路:
* - 1.定义队列存放节点
* - 2.首先将根节点入队列
* - 3.如果队列不为空,那么将队列顶部元素出队
* - 4.输出根节点的值
* - 5.判断根节点左右节点是否为空,如果不为空,那么将左右节点入队列,只要队列不为空就一直执行while循环
* @param root
*/
private void levelOrderTraversal(Node<E> root) {
Queue<Node<E>> queue = new LinkedList<>();
queue.offer(root);
while (!queue.isEmpty()) {
Node<E> node = queue.poll();
System.out.print(node.element + "\t");
if (node.left != null) {
queue.offer(node.left);
}
if (node.right != null) {
queue.offer(node.right);
}
}
}
/**
* 下面是打印需要重写的四个方法
* 根节点
*/
@Override
public Object root() {
return root;
}
// 左树的寻找方式
@Override
public Object left(Object node) {
return ((Node<E>) node).left;
}
// 右树的寻找方式
@Override
public Object right(Object node) {
return ((Node<E>) node).right;
}
// 打印方式
@Override
public Object string(Object node) {
Node<E> myNode = (Node<E>) node;
// 获取父节点保存下来并打印
String parentString = "null";
if (myNode.parent != null) {
parentString = myNode.parent.element.toString();
}
return myNode.element;
}
public BinarySearchTree() {
this(null);
}
public BinarySearchTree(Comparator<E> comparator) {
this.comparator = comparator;
}
/**
* 二叉树的 Node节点 对象
*/
public static class Node<E> {
E element;
Node<E> left;
Node<E> right;
Node<E> parent;
public Node(E element, Node<E> parent) {
this.element = element;
this.parent = parent;
}
public boolean isLeaf() {
return left == null && right == null;
}
public boolean hasTwoChildren() {
return left != null && right != null;
}
}
}