优点:快速的查找数据项、插入数据项和删除数据项。
基本概念
路径:顺着链接节点的边从一个节点到另一个节点,所经过的节点顺序排列称为路径。
根:树最上面的节点称为根节点,一棵树只有一个根,而且从根到任何节点有且只有一条路径。
父节点:每个节点都有一条边向上链接到另一个节点,这个节点就称为下面那个节点的父节点。
子节点:每个节点都有一条边,向下链接到另一个节点,下面的节点就是该节点的子节点。
叶子节点:没有子节点的节点称为叶子节点。
子树:每个节点都可以作为一个子树的根,它和它所有的子节点,子节点的子节点组合在一起就是一个子树。
访问:访问一个节点是为了在这个节点上执行一些操作,如查看节点的数据项。但是如果仅仅是经过一个节点,不认为是访问了这个节点。
层:一个节点的层数是指从根开始到这个节点有多少代。
分类
- 二叉树:树的每个节点最多只能有两个子节点的树,称为二叉树。
二叉树的操作:
插入节点
从根节点开始查找,查找到一个相应的节点,这个节点将成为先插入的节点的父节点,当父节点找到后,通过判断新节点的值和父节点的值的大小来判断该节点是作为其父节点的左子节点还是右子节点(小:作为左子节点。大:作为右子节点)。
查找操作
从根节点开始查找,如果查找的节点值比当前节点的值小,则继续查找其左子树,否则查找其右子树。
遍历树:根据一个特定的顺序访问树的每一个节点。根据顺序的不同分为前序,中序,后序遍历三种。
前序遍历:
(1)访问根节点
(2)前序遍历左子树
(3)前序遍历右子树
中序遍历:数据从小到大排序
(1)中序遍历左子树
(2)访问根节点
(3)中序遍历右子树
中序遍历打印出来每个节点的数据就是一个从小到大的有序数组。
后序遍历:
(1)后序遍历左子树
(2)后序遍历右子树
(3)访问根节点
Java代码实现二叉树
- 创建节点类
/**
* 二叉树节点
*
*
*
*/
public class Node {
// 二叉树数节点中数据项可以是多个,数据项类型可以是任意类型。
// 数据项
public long data;
// 数据项
public String sData;
// 左子节点
public Node leftChild;
// 右子节点
public Node rightChild;
/**
* 构造方法
*
* @param data
*/
public Node(long data) {
this.data = data;
}
}
- 创建二叉树类
/**
* 二叉树
*
*
*/
public class Tree {
// 根节点
private Node root;
/**
* 插入节点
*
* @param value
*/
public void insert(long value) {
Node newNode = new Node(value);
// 引用当前节点
Node current = root;
// 引用父节点
Node parent;
// 如果root为null,也就是第一插入的时候
if (root == null) {
root = newNode;
return;
} else {
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;
}
}
}
}
}
/**
* 查找节点
* @param value
*/
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;
}
/**
* 删除节点
* @param value
* @return
*/
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;
}
// 如果差找不到
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.leftChild;
}
}
} 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 deNode
* @return
*/
public Node getSuccessor(Node deNode) {
Node successor = deNode;
Node successorParent = deNode;
Node current = deNode.rightChild;
while (current != null) {
successorParent = successor;
successor = current;
current = current.leftChild;
}
if (successor != deNode.rightChild) {
successorParent.leftChild = successor.rightChild;
successor.rightChild = deNode.rightChild;
}
return successor;
}
/**
* 前序遍历
*
* @param localNode
* 当前要遍历的开始节点
*/
public void frontOrder(Node localNode) {
if (localNode != null) {
// 访问根节点
System.out.println(localNode.data);
// 前序遍历左子树
frontOrder(localNode.leftChild);
// 前序遍历右子树
frontOrder(localNode.rightChild);
}
}
/**
* 中序遍历
*
* @param localNode
*/
public void inOrder(Node localNode) {
if (localNode != null) {
// 中序遍历左子树
inOrder(localNode.leftChild);
// 访问根节点
System.out.println(localNode.data);
// 中序遍历右子树
inOrder(localNode.rightChild);
}
}
/**
* 中序遍历
*
* @param localNode
*/
public void afterOrder(Node localNode) {
if (localNode != null) {
// 后序遍历左子树
afterOrder(localNode.leftChild);
// 后序遍历右子树
afterOrder(localNode.rightChild);
// 访问根节点
System.out.println(localNode.data);
}
}
}