0.
二叉查找树是按照二叉树的结构来组织的,二叉查找树满足这样的性质:
设x为二叉查找树中的一个结点,left(x)是它的左孩子,right(x)是它的右孩子,那么left(x)<=x<=right(x).
二叉查找树是一种较为简单的数据结构。
1.二叉查找树的操作及其Java实现
注意:Java没有指针,很多修改都是通过返回值带出来的
①插入
INSERT:插入指定元素
public Node treeInsert(int value,Node root) { //传值传递,没指针,只能用返回值带出来了
if(root!=null) {
if(value <= root.value) {
root.left = treeInsert(value,root.left);
}
else {
root.right = treeInsert(value,root.right);
}
}
else {
return new Node(value);
}
return root;
}
注:初始化一棵BST就是不断向它插入结点的过程
②遍历
TRAVERSE:遍历整棵树(本文以中序遍历为例)
//中序遍历BST能得到一个有序的序列
public void middleTraverse(Node root) {
if(root.left!=null) {
middleTraverse(root.left);
}
System.out.print(root.value + " ");
if(root.right!=null) {
middleTraverse(root.right);
}
}
③查找
SEARCH:查找给定的元素
public Node search(int x,Node root) { //根据BST的性质,小的往左,大的往右
if(root == null) return null;
if(root.value == x) {
return root;
}
else if(x<root.value) {
search(x,root.left);
}
else {
search(x,root.right);
}
return null;
}
MINIMUM:查找树中最小的元素
//由BST的性质可知,最小的元素在BST最左下角
public Node minimum(Node root) {
if(root == null)
return null;
if(root.left == null)
return root;
else {
return minimum(root.left);
}
}
MAXIMUM:查找树中最大的元素
//由BST的性质可知,最大的元素在BST最右下角
public Node maximum(Node root) {
if(root == null)
return null;
if(root.right == null)
return root;
else {
return maximum(root.right);
}
}
PREDECESSOR:查找给定元素的父结点
//在前序遍历的基础上做一些改动即可
public Node predecessor(Node root,int value) {
if(root == null)
return null;
if(root.left!=null) {
if(value == root.left.value) return root;
if(value < root.left.value) {
return predecessor(root.left,value);
}
return predecessor(root.right,value);
}
if(root.right!=null) {
if(value == root.right.value) return root;
if(value < root.right.value) {
return predecessor(root.left,value);
}
return predecessor(root.right,value);
}
return null;
}
SUCCESSOR:查找给定元素的后继
//在前序遍历的基础上做一些改动即可
//分为找左孩子还是右孩子,这里写一个找左孩子的
public Node leftSuccessor(Node root,int value) {
if(root.value == value)
return root.left;
if(value <= root.left.value) {
return leftSuccessor(root.left,value);
}
return leftSuccessor(root.right,value);
}
④删除
按删除结点的特点,删除的情况分为三种:
(1)删除的结点为叶子结点
若该结点为叶子结点,修改其父结点的引用,将指向该结点的引用置为空
(2)删除的结点只有左孩子或者右孩子
若该结点只有一个孩子,修改其父结点的引用,降指向该结点的引用指向该节点的孩子
(3)删除的结点既有左孩子也有右孩子
有两种方法可以解决该问题:
方法一:为了维持BST性质,我们可以在该结点的左子树里找到最大值所在的结点(或在右子树里找最小值所在的结点),和该结点交换数据后删除。这是一个递归的过程,最后删除结点的为叶子结点或者只有一个孩子的结点。
方法二:将指向该结点的前驱指向该结点的左孩子,再将该结点的右子树一整棵插入该结点的左子树
方法一代码:
public void treeDelete(Node temp,int value) {
Node pred = predecessor(temp,value);
if(pred != null) { //不是根结点
Node node = search(value,temp); //value所在结点
if(node.left == null) {
if(pred.left == node) {
pred.left = node.right;
}
else {
pred.right = node.right;
}
}
else if(node.left!=null && node.right ==null) {
if(pred.left == node) {
pred.left = node.left;
}
else {
pred.right = node.left;
}
}
else {
Node mini = minimum(node.right);
mini.value = node.value;
treeDelete(node.right,node.value);
}
}
方法二代码:
public void delete(Node node,int value) {
//根结点无前驱,拉出来特殊处理
if(predecessor(node,value) == null) {
if(root.right==null) {
root = root.left;
}
else {
treeInsert(root.right.value,root.left); //在左子树中插入整颗右子树
Node temp = search(root.right.value,root.left);
temp.left = root.right.left;
temp.right = root.right.right;
root = root.left; //把原来的root丢进垃圾箱
}
}
else {
Node pred = predecessor(node,value);
treeInsert(node.right.value,node.left);
if(node.right == null) {
pred.left = node.left;
}
else {
treeInsert(node.right.value, node.left);
Node temp = search(root.right.value,root.left);
temp.left = node.right.left;
temp.right = node.right.right;
}
if(pred.left == node) { //要删除的结点是其前驱的左孩子
pred.left = node.left;
}
else {
pred.right = node.right;
}
}
}
//如有错误,欢迎指正