二叉搜索树:
- 二叉搜索树(binary serach tree,BST):对于树中的每一个结点,它的左子树中任意结点都小于该结点的值,而它的右子树中结点的值都大于该结点的值。(没有重复元素)
- 二叉搜索树的表示:可以使用链接结点的集合来表示二叉树,每个结点都包含一个数值和两个称为left和right的链接,分别引用左子结点和右子结点。
定义一个类实现结点
public class TreeNode<E> {
protected E element;
protected TreeNode<E> left;
protected TreeNode<E> right;
public TreeNode(E e) {
element = e;
}
}
- 二叉搜索树中查找一个元素:从根节点开始向下扫描,直到找到一个匹配元素,或者达到一颗空子树为至。
查找方法
public boolean search(E e) {
TreeNode<E> current = root;
while (current != null) {
if (e.compareTo(current.element) < 0) {
current = current.left;
}
else if (e.compareTo(current.element) > 0) {
current = current.right;
}
else
return false;
}
return false;
}
- 二叉搜索树中插入一个元素:在二叉搜索树中插入元素,首先需要确定在树中插入元素的位置,要确定新结点的父结点的位置。
插入方法
public boolean insert(E e) {
if (root == null)
root = createNewNode(e);
else {
TreeNode<E> parent = null;
TreeNode<E> current = root;
while (current != null) {
if (e.compareTo(current.element) < 0) {
parent = current;
current = current.left;
}
else if (e.compareTo(current.element) > 0) {
parent = current;
current = current.right;
}
else
return false;
}
if (e.compareTo(parent.element) < 0)
parent.left = createNewNode(e);
else
parent.right = createNewNode(e);
}
size++;
return true;
}
如果这棵树是空的,就使用新元素创建一个根节点,否则,寻找新元素结点的父结点的位置。为该元素创建一个新结点,然后将结点链接到它的父结点的值。判断元素大小,分别设置为左右子结点。
- 树的遍历:访问每一个结点刚好一次的过程。
BST类的实现:
Tree接口(定义为collection的子类型,从而使用collection的通用操作)
import java.util.Collection;
public interface Tree<E> extends Collection<E> {
public boolean search(E e);
public boolean insert(E e);
public boolean delete(E e);
public int getSize();
public default void inorder() {}
public default void postorder() {}
public default void preorder() {}
@Override
public default boolean isEmpty() {
return size() == 0;
}
@Override
public default int size() {
return getSize();
}
@Override
public default boolean contains(Object e) {
return search((E)e);
}
@Override
public default Object[] toArray() {
return null;
}
@Override
public default <T> T[] toArray(T[] a) {
return null;
}
@Override
public default boolean add(E e){
return insert(e);
}
@Override
public default boolean remove(Object e) {
return delete((E)e);
}
@Override
public default boolean containsAll(Collection<?> c) {
return false;
}
@Override
public default boolean addAll(Collection<? extends E> c) {
return false;
}
@Override
public default boolean removeAll(Collection<?> c) {
return false;
}
@Override
public default boolean retainAll(Collection<?> c) {
return false;
}
}
Tree接口的实现类BST
import java.util.ArrayList;
import java.util.Iterator;
public class BST<E extends Comparable<E>> implements Tree<E> {
protected TreeNode<E> root;
protected int size = 0;
public BST() {
}
public BST(E[] objects) {
for (int i = 0; i < objects.length; i++)
add(objects[i]);
}
@Override
public boolean search(E e) {
TreeNode<E> current = root;
while (current != null) {
if (e.compareTo(current.element) < 0) {
current = current.left;
}
else if (e.compareTo(current.element) > 0) {
current = current.right;
}
else
return false;
}
return false;
}
@Override
public boolean insert(E e) {
if (root == null)
root = createNewNode(e);
else {
TreeNode<E> parent = null;
TreeNode<E> current = root;
while (current != null) {
if (e.compareTo(current.element) < 0) {
parent = current;
current = current.left;
}
else if (e.compareTo(current.element) > 0) {
parent = current;
current = current.right;
}
else
return false;
}
if (e.compareTo(parent.element) < 0)
parent.left = createNewNode(e);
else
parent.right = createNewNode(e);
}
size++;
return true;
}
protected TreeNode<E> createNewNode(E e) {
return new TreeNode<>(e);
}
@Override
public void inorder() {
inorder(root);
}
protected void inorder(TreeNode<E> root) {
if (root == null) return;
inorder(root.left);
System.out.println(root.element + " ");
inorder(root.right);
}
@Override
public void postorder() {
postorder(root);
}
protected void postorder(TreeNode<E> root) {
if (root == null) return;
postorder(root.left);
System.out.println(root.element + " ");
postorder(root.right);
}
@Override
public void preorder() {
preorder(root);
}
protected void preorder(TreeNode<E> root) {
if (root == null) return;
preorder(root.left);
System.out.println(root.element + " ");
preorder(root.right);
}
@Override
public int getSize() {
return size;
}
public TreeNode<E> getRoot() {
return root;
}
public ArrayList<TreeNode<E>> path(E e) {
ArrayList<TreeNode<E>> list = new ArrayList<>();
TreeNode<E> current = root;
while (current != null) {
list.add(current);
if (e.compareTo(current.element) < 0) {
current = current.left;
}
else if (e.compareTo(current.element) > 0) {
current = current.right;
}
else
break;
}
return list;
}
@Override
public boolean delete(E e) {
TreeNode<E> parent = null;
TreeNode<E> current = root;
while (current != null) {
if (e.compareTo(current.element) < 0) {
parent = current;
current = current.left;
} else if (e.compareTo(current.element) > 0) {
parent = current;
current = current.right;
} else
break;
}
if (current == null)
return false;
if (current.left == null) {
if (parent == null){
root = current.right;
}
else {
if (e.compareTo(parent.element) < 0)
parent.left = current.right;
else
parent.right = current.right;
}
}
else {
TreeNode<E> parentOfRightMost = current;
TreeNode<E> rightMost = current.left;
while (rightMost.right != null) {
parentOfRightMost = rightMost;
rightMost = rightMost.right;
}
current.element = rightMost.element;
if (parentOfRightMost.right == rightMost)
parentOfRightMost.right = rightMost.left;
else
parentOfRightMost.left = rightMost.left;
}
size--;
return true;
}
@Override
public Iterator<E> iterator() {
return new InorderIterator();
}
private class InorderIterator implements Iterator<E> {
private ArrayList<E> list = new ArrayList<>();
private int current = 0;
public InorderIterator() {
inorder();
}
private void inorder() {
inorder(root);
}
private void inorder(TreeNode<E> root) {
if (root == null) return;
inorder(root.left);
list.add(root.element);
inorder(root.right);
}
@Override
public boolean hasNext() {
if (current < list.size())
return true;
return false;
}
@Override
public E next() {
return list.get(current++);
}
@Override
public void remove() {
if (current == 0)
throw new IllegalStateException();
delete(list.get(--current));
list.clear();
inorder();
}
}
@Override
public void clear() {
root = null;
size = 0;
}
}
- BST.java中实现了很多的Tree接口中的方法,来测试一下方法:
测试类TestBST
import java.util.ArrayList;
public class TestBST {
public static void main(String[] args) {
BST<String> tree = new BST<>();
tree.insert("qqqqqq");
tree.insert("aaaaaa");
tree.insert("zzzzzz");
tree.insert("wwwwww");
tree.insert("ssssss");
tree.insert("xxxxxx");
tree.insert("eeeeee");
tree.insert("dddddd");
System.out.print("Inorder (sorted): ");
tree.inorder();
System.out.print("\nPostorder: ");
tree.postorder();
System.out.print("\nPreorder: ");
tree.preorder();
System.out.print("\nThe number of nodes is" + tree.getSize());
System.out.print("\nIs Peter in the tree?" + tree.search("Peter"));
System.out.print("\nA path from the root to Peter is: ");
ArrayList<TreeNode<String>> path = tree.path("Peter");
for (int i = 0; path != null && i < path.size(); i++)
System.out.print(path.get(i).element + " ");
Integer[] numbers = {2, 4, 3, 1, 8, 5, 6, 7};
BST<Integer> intTree = new BST<>(numbers);
System.out.print("\nInorder (sorted): ");
intTree.inorder();
}
}
- 测试中方法正常,二叉搜索树是非常有用的数据结构,它的搜索,插入和删除操作比线性表更加高效。数组线性表和链表中,查找,插入和删除的时间复杂度
O(n)
,而二叉搜索树花费O(logn)
的平均时间。 - 以上是二叉搜索树的简单实现,欢迎交流指正。