java实现二叉树创建删除以及递归非递归遍历demo示例
基本概念
二叉树:每个节点最多有两颗子树,即左子树和右子树,次序不可以颠倒(即先有左才能有右)
满二叉树:除最后一层无任何子节点外,每一层上的所有节点都有两个子节点二叉树。即如果一个二叉树的层数为k,且节点总数是2^k-1,则它就是满二叉树。
平衡二叉树:它是一颗空树或者它的左右两个子树的高度差的绝对值不能超过1,并且左右两个子树都是一颗平衡二叉树。平衡二叉树的常用实现方法有红黑树(非严格平衡的二叉查找树)、AVL(平衡二叉搜索树)、替罪羊树、Treap、伸展树等。
二叉树高度:顾名思义就是二叉树的层数
广度优先遍历:即是层次遍历,从上往下对每一层依次访问,在每一层中,从左往右(也可以从右往左)访问结点,访问完一层就进入下一层,直到没有结点可以访问为止。
深度优先遍历:对每一个可能的分支路径深入到不能再深入为止,而且每个结点只能访问一次。要特别注意的是,二叉树的深度优先遍历比较特殊,可以细分为前(先)序遍历、中序遍历、后序遍历。前中后序遍历主要针对的是根节点访问的具体时机,具体说明如下:
1)前(先)序遍历:对任一子树,先访问根,然后遍历其左子树,最后遍历其右子树,即 中->左->右
2)中序遍历:对任一子树,先遍历其左子树,然后访问根,最后遍历其右子树,即 左->中->右
3)后序遍历:对任一子树,先遍历其左子树,然后遍历其右子树,最后访问根,即 左->右->中
二叉树的深度优先遍历的非递归的通用做法是采用栈(先进后出),而广度优先遍历的非递归的通用做法是采用队列(先进先出)
实现代码
package com.hxf.demo.demo.tree;
import java.util.List;
/**
* <p>
* BinaryTree
* </p>
*
* @author hechengxi@iqingka.com
* @date 2020年04月16日 20:04
*/
public class BinaryTree<T extends Comparable<T>> {
/**
* 根节点
*/
private Node root;
class Node {
//节点数据
private T data;
//左子节点
private Node leftChild;
//右子节点
private Node rightChild;
// 构造方法
public Node(T data) {
this.data = data;
}
}
public Node root() {
return root;
}
/**
* 薪资
*
* @param data
* @return
*/
public boolean add(T data) {
if (exist(data)) {
return Boolean.FALSE;
}
Node node = new Node(data);
if (null == root) {
root = node;
return Boolean.TRUE;
}
//获取父节点
Node parentNode = getPrentNode(data);
//更新节点
if (parentNode.data.compareTo(data) > 0) {
parentNode.leftChild = node;
} else {
parentNode.rightChild = node;
}
//插入节点
return Boolean.TRUE;
}
/**
* 前序遍历
*
* @param treeNode
* @param qianxuNumList
*/
public void qinaxuDigui(Node treeNode, List<T> qianxuNumList) {
qianxuNumList.add(treeNode.data);
if (treeNode.leftChild != null) {
qinaxuDigui(treeNode.leftChild, qianxuNumList);
}
if (treeNode.rightChild != null) {
qinaxuDigui(treeNode.rightChild, qianxuNumList);
}
}
/**
* 中序遍历
*
* @param treeNode
* @param zhongxuNumList
*/
public void zhongxuDigui(Node treeNode, List<T> zhongxuNumList) {
if (treeNode.leftChild != null) {
zhongxuDigui(treeNode.leftChild, zhongxuNumList);
}
zhongxuNumList.add(treeNode.data);
if (treeNode.rightChild != null) {
zhongxuDigui(treeNode.rightChild, zhongxuNumList);
}
}
/**
* 后序遍历
*
* @param treeNode
* @param houxuNumList
*/
public void houxuDigui(Node treeNode, List<T> houxuNumList) {
if (treeNode.leftChild != null) {
houxuDigui(treeNode.leftChild, houxuNumList);
}
if (treeNode.rightChild != null) {
houxuDigui(treeNode.rightChild, houxuNumList);
}
houxuNumList.add(treeNode.data);
}
/**
* 获取当前节点
*
* @param data
* @return
*/
private Node getNode(T data) {
Node tempNode = root;
while (tempNode != null) {
if (tempNode.data.compareTo(data) == 0) {
return tempNode;
}
if (tempNode.data.compareTo(data) > 0) {
tempNode = tempNode.leftChild;
} else {
tempNode = tempNode.rightChild;
}
}
return null;
}
public boolean remove(T data) {
Node node = getNode(data);
if (node == null) {
return Boolean.FALSE;
}
if (root == node) {
if (node.rightChild == null && node.leftChild == null) {
root = null;
} else if (node.rightChild != null && node.leftChild == null) {
root = node.rightChild;
} else if (node.rightChild == null) {
root = node.leftChild;
} else {
root = split(data);
}
} else {
//获取父节点
Node parentNode = getPrentNode(data);
if (node.rightChild == null && node.leftChild == null) {
//如果父节点大于当前节点
if (parentNode.data.compareTo(node.data) > 0) {
parentNode.leftChild = null;
} else {
parentNode.rightChild = null;
}
} else if (node.rightChild != null && node.leftChild == null) {
// 右节点不为空
parentNode.rightChild = node.rightChild;
} else if (node.rightChild == null) {
// 左节点部位空
parentNode.leftChild = node.leftChild;
} else {
// 左右节点不为空
parentNode.leftChild = node.leftChild;
}
}
return false;
}
private Node split(T data) {
Node node = getNode(data);
//找到左节点的最大数节点
Node big = getBigNode(node.leftChild);
//将big的右节点指向node的右节点
big.rightChild = node.rightChild;
return node.leftChild;
}
public Node getBigNode(Node node) {
Node tempNode = node;
while (tempNode != null) {
if (tempNode.rightChild == null) {
return tempNode;
}
tempNode = tempNode.rightChild;
}
return null;
}
/**
* 获取父节点
*
* @param data
* @return
*/
private Node getPrentNode(T data) {
Node tempNode = root;
Node prentNode = tempNode;
while (tempNode != null) {
//跳出循环时,temp 为 null,prev记录上一个节点,即为parent
prentNode = tempNode;
//如果父节点数据大当前节点
if (prentNode.data.compareTo(data) > 0) {
tempNode = prentNode.leftChild;
} else {
tempNode = prentNode.rightChild;
}
}
return prentNode;
}
/**
* 节点是否存在
*
* @param data
* @return
*/
public boolean exist(T data) {
boolean flag = false;
//从根节点开始遍历
Node temp = root;
while (temp != null) {
if (temp.data.compareTo(data) == 0) {
flag = true;
} else if (temp.data.compareTo(data) > 0) {
temp = temp.leftChild;
} else {
temp = temp.rightChild;
}
}
return flag;
}
/**
* 创建二叉树
*
* @param list
* @return
*/
public static BinaryTree createBinaryTree(List<Integer> list) {
BinaryTree<Integer> binaryTree = new BinaryTree<Integer>();
for (Integer integer : list) {
binaryTree.add(integer);
}
return binaryTree;
}
}
测试
@Slf4j
public class TreeUtil {
public static void main(String[] args) {
List<Integer> list = Arrays.asList(13, 65, 5, 97, 25, 37, 22, 4, 28, 32);
BinaryTree binaryTree = BinaryTree.createBinaryTree(list);
log.info("binaryTree={}", binaryTree);
binaryTree.remove(13);
List<Integer> list1 = new ArrayList();
binaryTree.qinaxuDigui(binaryTree.root(), list1);
log.info("中序遍历={}", list1);
List<Integer> list2 = new ArrayList();
binaryTree.zhongxuDigui(binaryTree.root(), list2);
log.info("前序遍历={}", list2);
List<Integer> list3 = new ArrayList();
binaryTree.houxuDigui(binaryTree.root(), list3);
log.info("后序遍历={}", list3);
}
}