顺序存储的插入和删除可以通过在表末端插入和删除元素同最后一个元素互换来保持高效率,但是无序造成查找的效率很低。
如果查找的数据表是有序线性表,并且是顺序存储的,查找可以折半、插值、斐波那契等查找算法来实现,但是因为有序在插入和删除操作上,就需要耗费大量时间。
二叉排序树可以使得插入和删除的效率不错,又可以比较高效率地实现查找。
二叉排序树(Binary Sort Tree),又称为二叉查找树。它或者是一棵空树,或者是具有下列性质的二叉树
1.若它的左子树不空,则左子树上所有结点的值均小于它的根结点的值;
2.若它的右子树不空,则右子树上所有结点的值均小于它的根结点的值;
3.它的左、右子树也分别为二叉排序树。
二叉排序树的查找有递归和非递归两种方法
public class BinarySortTree {
/**
* 根结点
*/
private TreeNode rootNode;
/**
* 获取rootNode
* @return
*/
public TreeNode getRootNode() {
return this.rootNode;
}
/**
* 创建二叉排序树 的第一种方法(通过insertBST创建)
* @param array
* @return
*/
public void createBinarySortTree1(int[] array) {
for (int i = 0; i <array.length; i++) {
if (!insertBST(array[i])) {
System.out.println("已存在" + array[i] + ",不再插入二叉排序树");
}
}
}
/**
* 创建二叉排序树 的第二种方法
* @param array
* @return
*/
public void createBinarySortTree2(int[] array) {
for (int i = 0; i < array.length; i++) {
if (i == 0) {
rootNode = new TreeNode(array[i]);
continue;
}
TreeNode node = rootNode;
while (true) {
if (array[i] < node.getData()) {
if (node.getLchild() == null) {
node.setLchild(new TreeNode(array[i]));
break;
} else {
node = node.getLchild();
}
} else if (array[i] == node.getData()) {
System.out.println("已存在" + array[i] + ",不再插入二叉排序树");
break;
} else {
if (node.getRchild() == null) {
node.setRchild(new TreeNode(array[i]));
break;
} else {
node = node.getRchild();
}
}
}
}
}
/**
* 中序遍历
* @param node
*/
public void inOrderTraverse(TreeNode node) {
if (node != null) {
inOrderTraverse(node.getLchild());
System.out.print(node.getData() + " ");
inOrderTraverse(node.getRchild());
}
}
/**
* 二叉排序树的查找 (递归实现)
*
* 查找可以有两种实现方法,一种是递归,一种是while 循环。
* 在插入和删除操作中也首先需要查询操作,这时使用while 循环比较好,可以知道要查询结点的双亲结点
* @param node
* @param key
* @return 返回
*/
public boolean searchBST(TreeNode node, int key) {
if (node == null) {
return false;
} else if (key == node.getData()) {
return true;
} else if (key < node.getData()) {
return searchBST(node.getLchild(), key);
} else {
return searchBST(node.getRchild(), key);
}
}
/**
* 二叉排序树的插入
* @param node
* @param key
*/
public boolean insertBST(int key) {
//相当于 search 用非递归实现 -----begin
TreeNode node = rootNode;
//查找 最后访问的 node
TreeNode searchLastNode = null;
while (node != null) {
searchLastNode = node;
if (key < node.getData()) {
node = node.getLchild();
} else if (key > node.getData()) {
node = node.getRchild();
} else {
return false;
}
}
// search ----end
TreeNode newNode = new TreeNode(key);
if (rootNode == null) {
rootNode = newNode;
} else if (key < searchLastNode.getData()) {
searchLastNode.setLchild(newNode);
} else {
searchLastNode.setRchild(newNode);
}
return true;
}
public boolean deleteBST(int key) {
//相当于 search 用非递归实现 -----begin
TreeNode node = rootNode;
//存储 其双亲结点,如果是根节点,则双亲结点为null
TreeNode parentNode = null;
while (node != null) {
if (key < node.getData()) {
parentNode = node;
node = node.getLchild();
} else if (key > node.getData()) {
parentNode = node;
node = node.getRchild();
} else {
//相等时已找到
break ;
}
}
// search ----end
//没有找到要删除的node
if (node == null) {
return false;
}
// 右子树为空 ,重接左子树
if (node.getRchild() == null) {
if (parentNode != null) {
if (parentNode.getLchild() == node)
parentNode.setLchild(node.getLchild());
else
parentNode.setRchild(node.getLchild());
} else {
rootNode = node.getLchild();
}
// 左子树为空,重接右子树
} else if (node.getLchild() == null) {
if (parentNode != null) {
if (parentNode.getLchild() == node)
parentNode.setLchild(node.getRchild());
else
parentNode.setRchild(node.getRchild());
} else {
rootNode = node.getRchild();
}
// 左右子树都不为空 ,可以将 要删除结点 按中序遍历的前驱或后继 替代 要删除结点的位置,此处取前驱
} else {
//取前驱结点 ,先转左,然后一直到最右
TreeNode replaceNode = node.getLchild();
TreeNode replaceParentNode = node;
while (replaceNode.getRchild() != null) {
replaceParentNode = replaceNode;
replaceNode = replaceNode.getRchild();
}
//获取到前驱结点极其双亲结点
//如果前驱结点的双亲结点是 要删除的结点
if (replaceParentNode == node)
replaceParentNode.setLchild(replaceNode.getLchild());
else
replaceParentNode.setRchild(replaceNode.getLchild());
node.setData(replaceNode.getData());
}
return true;
}
public static void main(String[] args) {
// int[] array = new int[15];
// System.out.print("随机数:");
// for (int i = 0; i < 15; i++) {
// array[i] = (int) (Math.random() * 100);
// System.out.print(array[i] + " ");
// }
int[] array = {4, 10, 1, 13, 3, 15, 9, 11, 8, 5, 14, 2, 6, 7, 12};
BinarySortTree binarySortTree = new BinarySortTree();
//创建二叉排序树
binarySortTree.createBinarySortTree1(array);
//中序遍历 即是 从小到大的排序
System.out.print("\n中序遍历结果:");
binarySortTree.inOrderTraverse(binarySortTree.getRootNode());
//二叉排序树的查找
boolean searchResult = binarySortTree.searchBST(binarySortTree.getRootNode(), 2);
if (searchResult)
System.out.println("\n查到");
else
System.out.println("\n查不到");
//二叉排序树的删除
binarySortTree.deleteBST(2);
binarySortTree.deleteBST(1);
binarySortTree.deleteBST(3);
binarySortTree.deleteBST(4);
binarySortTree.deleteBST(10);
binarySortTree.inOrderTraverse(binarySortTree.getRootNode());
}
}
/**
* 二叉树结点
*
*
*/
class TreeNode {
private int data;
private TreeNode lchild;
private TreeNode rchild;
public TreeNode(int data) {
this.data = data;
}
public int getData() {
return data;
}
public void setData(int data) {
this.data = data;
}
public TreeNode getLchild() {
return lchild;
}
public void setLchild(TreeNode lchild) {
this.lchild = lchild;
}
public TreeNode getRchild() {
return rchild;
}
public void setRchild(TreeNode rchild) {
this.rchild = rchild;
}
@Override
public String toString() {
return "TreeNode [data=" + data + ", lchild=" + lchild + ", rchild=" + rchild + "]";
}
}
代码所示二叉树
运行结果: