什么是二叉树?
二叉树是一个连通的无环图,并且每一个顶点的度不大于3。有根二叉树还要满足根结点的度不大于2。有了根结点之后,每个顶点定义了唯一的父结点,和最多2个子结点。然而,没有足够的信息来区分左结点和右结点。
接下来我们来自己实现一个二叉树
首先定义一个树的节点类
public class Node {
//数据项
public long data;
//数据项
public String sData;
//左子节点
public Node leftChild;
//右子节点
public Node rightChild;
public Node(long data,String sData) {
this.data = data;
this.sData = sData;
}
}
接下来定义一个树的类Tree
public class Tree {
//根节点
public Node root;
}
这样准备工作就完成了,接下来我们进行方法的实现
二叉树插入节点
从根节点开始查找一个相应的节点,这个节点将成为新插入节点的父节点。当父节点找到后,通过比较新节点的值与父节点的大小来决定是连接到左子节点还是右子节点
public void insert(long value,String sValue){
Node newNode = new Node(value, sValue);
Node current = root;
Node parent;
if (current == null){
root = newNode;
return;
}
while (true){
parent = current;
if (current.data > value){
current = current.leftChild;
if (current == null){
parent.leftChild = newNode;
return;
}
}else{
current = current.rightChild;
if (current == null){
parent.rightChild = newNode;
return;
}
}
}
}
查找节点
从根节点开始查找,如果查找的节点值比当前的值小,则继续查找其左子树,否则查找其右子树。
public Node find(long value){
Node current = root;
//循环遍历
while (current.data != value){
if (current.data > value){
current = current.leftChild;
}else{
current = current.rightChild;
}
if (current == null){
return null;
}
}
return current;
}
二叉树的遍历
二叉树的遍历又分三种,前序遍历,中序遍历和后序遍历
1. 前序遍历:
- 访问根节点
- 前序遍历左子树
- 前序遍历右子树
/**
* 二叉树遍历:前序遍历
* @param localNode
*/
public void frontOrder(Node localNode){
if (localNode != null){
System.out.println(localNode.data + "," + localNode.sData);
//前序遍历左子树
frontOrder(localNode.leftChild);
//前序遍历右子树
frontOrder(localNode.rightChild);
}
}
如图: ABDECF
2. 中序遍历:
- 中序遍历左子树
- 访问根节点
- 中序遍历右子树
如图: DBEAFC
/**
* 二叉树遍历:中序遍历
* @param localNode
*/
public void inOrder(Node localNode){
if (localNode != null){
inOrder(localNode.leftChild);
System.out.println(localNode.data + "," + localNode.sData);
inOrder(localNode.rightChild);
}
}
3. 后续遍历
- 后序遍历左子树
- 后序遍历右子树
- 访问根节点
/**
* 二叉树遍历:后序遍历
* @param localNode
*/
public void afterOrder(Node localNode){
if (localNode != null){
afterOrder(localNode.leftChild);
afterOrder(localNode.rightChild);
System.out.println(localNode.data + "," + localNode.sData);
}
}
删除节点
- 判断是否是叶子节点:要删除叶结点,只需要将其父节点的引用值设置为null即可
- 该节点有一个子节点:改变父节点的引用,将其直接指向要删除节点的子节点
- 该节点有两个子节点:要删除有两个子节点的节点,就需要使用它的中序后继来代替该节点
public boolean delete(long value){
//引用当前节点,从根节点开始
Node current = root;
Node parent = root;
boolean isLeftChild = true;
while (current.data != value) {
parent = current;
if (current.data > value) {
current = current.leftChild;
isLeftChild = true;
} else {
current = current.rightChild;
isLeftChild = false;
}
//查不到,返回false
if (current == null) return false;
}
//找到了该节点,但是需要判断其是否含有子节点
if (current.leftChild == null && current.rightChild == null){
if (current == root){
root = null;
}else if (isLeftChild){
parent.leftChild = null;
}else{
parent.rightChild = null;
}
}else if (current.rightChild == null){
if (current == root){
root = current.leftChild;
}else if (isLeftChild){
parent.leftChild = current.leftChild;
}else{
parent.rightChild = current.rightChild;
}
}else if (current.leftChild == null){
if (current == root){
root = current.rightChild;
}else if (isLeftChild){
parent.leftChild = current.rightChild;
}else{
parent.rightChild = current.rightChild;
}
}else{
//获取中序后继节点
Node successor = getSuccessor(current);
if (current == root){
root = successor;
}else if (isLeftChild){
parent.leftChild = successor;
}else{
parent.rightChild = successor;
}
successor.leftChild = current.leftChild;
}
return true;
}
/**
* 获取到中序后继节点
* @param delNode
* @return
*/
private Node getSuccessor(Node delNode){
Node successor = delNode;
Node successorParent = delNode;
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;
}
return successor;
}
这样,二叉树的基本操作就到这儿了