描述:
在计算机科学中,二叉树是每个结点最多有两个子树的树结构。通常子树被称作“左子树”(left subtree)和“右子树”(right subtree)。二叉树常被用于实现二叉查找树和二叉堆。
一棵深度为k,且有2^k-1个节点的二叉树,称为满二叉树。这种树的特点是每一层上的节点数都是最大节点数。而在一棵二叉树中,除最后一层外,若其余层都是满的,并且最后一层或者是满的,或者是在右边缺少连续若干节点,则此二叉树为完全二叉树。具有n个节点的完全二叉树的深度为floor(log2n)+1。深度为k的完全二叉树,至少有2k-1个节点,至多有2k-1个节点。
代码:
节点类
public class Node {
public int value;
public Node leftChild;
public Node rightChild;
public Node(int val){
value = val;
}
public void display(){
System.out.println(value);
}
}
二叉树类
public class BinaryTree {
public Node root;
// 增加
public void insert(int val) {
Node node = new Node(val);
if (root == null) {
root = node;
} else {
Node parent = root;
Node current = root;
while (true) {
if (val < current.value) {
parent = current;
current = current.leftChild;
if (current == null) {
parent.leftChild = node;
break;
}
} else if (val > current.value) {
parent = current;
current = current.rightChild;
if (current == null) {
parent.rightChild = node;
break;
}
} else {
System.out.println("出现相同值");
}
}
}
}
// 查找
public Node find(int key) {
Node current = root;
while (current.value != key) {
if (key < current.value) {
current = current.leftChild;
} else if (key > current.value) {
current = current.rightChild;
}
if (current == null) {
return null;
}
}
return current;
}
//中序遍历
//*****************递归遍历
public void inOrderTarverse() {
System.out.print("中序遍历:");
inOrderTarverse(root);
System.out.println();
}
private void inOrderTarverse(Node node) {
if( node == null )
return;
inOrderTarverse(node.leftChild);
node.display();
inOrderTarverse(node.rightChild);
}
//****************非递归遍历
public void inOrderByStack() {
System.out.print("中序非递归遍历:");
Stack<Node> stack = new Stack<Node>();
Node current = root;
while (current != null || !stack.isEmpty()) {
while (current != null) {
stack.push(current);
current = current.leftChild;
}
if (!stack.isEmpty()) {
current = stack.pop();
current.display();
current = current.rightChild;
}
}
System.out.println();
}
//先序遍历
//*************递归遍历
public void perOrderTarverse() {
System.out.print("先序递归遍历:");
perOrderTarverse(root);
System.out.println();
}
private void perOrderTarverse(Node node) {
if(node == null) {
return ;
}
node.display();
perOrderTarverse(node.leftChild);
perOrderTarverse(node.rightChild);
}
//*************非递归遍历
public void preOrderByStack(){
Node current = root;
Stack<Node> stack = new Stack<Node>();
while( current != null || ! stack.isEmpty() ){
while( current != null ){
current.display();
stack.push(current);
current = current.leftChild;
}
if( ! stack.isEmpty() ){
current = stack.pop();
current = current.rightChild;
}
}
}
//后序遍历
//*******************递归遍历
public void postOrderTanverse() {
System.out.print("后序遍历");
postOrderTanverse(root);
System.out.println();
}
private void postOrderTanverse(Node node) {
if(node == null) {
return;
}
postOrderTanverse(node.leftChild);
postOrderTanverse(node.rightChild);
node.display();
}
// 得到后继节点,即删除节点的左后代
private Node getSuccessor(Node delNode) {
Node successor = delNode;
Node successorParent = null;
Node current = delNode.rightChild;
while (current != null) {
successorParent = successor;
successor = current;
current = current.leftChild;
}
// 如果后继节点不是删除节点的右子节点时,
if (successor != delNode.rightChild) {
// 要将后继节点的右子节点指向后继结点父节点的左子节点,
successorParent.leftChild = successor.rightChild;
// 并将删除节点的右子节点指向后继结点的右子节点
successor.rightChild = delNode.rightChild;
}
// 任何情况下,都需要将删除节点的左子节点指向后继节点的左子节点
successor.leftChild = delNode.leftChild;
return successor;
}
// 删除
public boolean delete(int value) {
Node current = root; // 需要删除的节点
Node parent = null; // 需要删除的节点的父节点
boolean isLeftChild = true; // 需要删除的节点是否父节点的左子树
while (true) {
if (value == current.value) {
break;
} else if (value < current.value) {
isLeftChild = true;
parent = current;
current = current.leftChild;
} else {
isLeftChild = false;
parent = current;
current = current.rightChild;
}
// 找不到需要删除的节点,直接返回
if (current == null)
return false;
}
// 分情况考虑
// 1、需要删除的节点为叶子节点
if (current.leftChild == null && current.rightChild == null) {
// 如果该叶节点为根节点,将根节点置为null
if (current == root) {
root = null;
} else {
// 如果该叶节点是父节点的左子节点,将父节点的左子节点置为null
if (isLeftChild) {
parent.leftChild = null;
} else { // 如果该叶节点是父节点的右子节点,将父节点的右子节点置为null
parent.rightChild = null;
}
}
}
// 2、需要删除的节点有一个子节点,且该子节点为左子节点
else if (current.rightChild == null) {
// 如果该节点为根节点,将根节点的左子节点变为根节点
if (current == root) {
root = current.leftChild;
} else {
// 如果该节点是父节点的左子节点,将该节点的左子节点变为父节点的左子节点
if (isLeftChild) {
parent.leftChild = current.leftChild;
} else { // 如果该节点是父节点的右子节点,将该节点的左子节点变为父节点的右子节点
parent.rightChild = current.leftChild;
}
}
}
// 2、需要删除的节点有一个子节点,且该子节点为右子节点
else if (current.leftChild == null) {
// 如果该节点为根节点,将根节点的右子节点变为根节点
if (current == root) {
root = current.rightChild;
} else {
// 如果该节点是父节点的左子节点,将该节点的右子节点变为父节点的左子节点
if (isLeftChild) {
parent.leftChild = current.rightChild;
} else { // 如果该节点是父节点的右子节点,将该节点的右子节点变为父节点的右子节点
parent.rightChild = current.rightChild;
}
}
}
// 3、需要删除的节点有两个子节点,需要寻找该节点的后续节点替代删除节点
else {
Node successor = getSuccessor(current);
// 如果该节点为根节点,将后继节点变为根节点,并将根节点的左子节点变为后继节点的左子节点
if (current == root) {
root = successor;
} else {
// 如果该节点是父节点的左子节点,将该节点的后继节点变为父节点的左子节点
if (isLeftChild) {
parent.leftChild = successor;
} else { // 如果该节点是父节点的右子节点,将该节点的后继节点变为父节点的右子节点
parent.rightChild = successor;
}
}
}
current = null;
return true;
}
}