1.二叉搜索树的概念
二叉搜索树又称二叉排序树,它有如下性质:
1.若左子树不为空,左子树上的所有节点的key值都小于根节点。
2.若右子树不为空,右子树上的所有节点的key值都大于根节点。
3.中序遍历可以得到有序序列。
4.不存在key值相同的节点。
2.二叉搜索树的意义
我们知道链表插入,删除很方便,只需要修改指针的指向,但是查找很麻烦,需要从头节点开始遍历,相反,数组的插入,删除很麻烦,需要挪动后面所有元素,但是查找很简单,直接使用下标来索引,所以综合二者优点的二叉搜索树诞生了,BST查找快,插入,删除和操作链表一样方便。
3.二叉搜索树的创建
先按升序排好序,每次把中间的元素当作根节点,依次递归下去就能构架一颗BST,举个例子:[1,2,3,4,5,6,7,9,10,14],
数组中间元素5就是根节点。还是上图吧:
java代码如下:
private static TreeNode build(int[] num,TreeNode root0,int left,int right) //递归创建二叉排序树
{
if (left>right)
{
return null;
}
int mid=(left+right)/2;
root0=new TreeNode(num[mid]);
root0.left=build(num,root0.left,left,mid-1);
root0.right=build(num,root0.right,mid+1,right);
return root0;
}
public static TreeNode createTree(int[] num)
{
Arrays.sort(num);
TreeNode root=null;
return build(num,root,0,num.length-1);
}
4.二叉搜索树的查找
public static TreeNode search0(TreeNode root, int key) //递归实现搜索
{
if (root==null)
{
return null; //说明没有这个key
}
if (root.data==key)
{
return root;
}
if (root.data>key) //key在root的左子树
{
return search0(root.left,key);
}
return search0(root.right,key); //key在root的右子树
}
public static TreeNode search1(TreeNode root,int key) //非递归实现搜索
{
TreeNode cur;
for (cur=root;cur!=null&&cur.data!=key;)
{
cur=cur.data>key?cur.left:cur.right;
}
return cur;
}
5.二叉搜索树的插入
public static Boolean insert(TreeNode root,TreeNode node) //插入节点,递归实现
{
if (root.data==node.data)
{
return false;
}
if (root.data<node.data)
{
if (root.right==null)
{
root.right=node;
}
else
{
return insert(root.right,node);
}
}
else if (root.data>node.data)
{
if (root.left==null)
{
root.left=node;
}
else
{
return insert(root.left,node);
}
}
return true;
}
6.二叉搜索树的删除
删除节点是相当的麻烦,需要考虑边边角角。
粗略分为下面四种情况:
1.要删除的节点只有左孩子,直接把左孩子代替被删除节点
2.要删除的节点只有右孩子,直接把右孩子代替被删除节点
3.要删除的节点左右孩子均有,找到被欲删除节点的后继节点(后面会将什么是后继节点),用后继节点代替被删除节点
4.节点左右孩子都没有的情况可以归为1,2,不需要单独写代码
后继节点就是欲删除节点的右子树的最左边节点(通俗说,就是从欲删除节点的右孩子开始,中序遍历的第一个节点就是后继节点)上一张算法导论的插图(ps:从别人那里扣来的^_^):
Talk is cheap,Show code!
public static TreeNode delete(TreeNode root,int key) //删除节点
{
TreeNode parent=null;
TreeNode cur=root;
while (cur!=null&&cur.data!=key)
{
parent=cur;
cur=cur.data>key?cur.left:cur.right;
}
if (cur==null)
{
return null;
}
if (cur.left==null) //欲删除节点只有右子树
{
if (parent==null) //欲删除节点是根节点
{
return cur.right;
}
if (parent.left==cur) //欲删除节点是其父节点的左子树
{
parent.left=cur.right;
}
else //否则是其右子树
{
parent.right=cur.right;
}
}
else if (cur.right==null) //欲删除节点只有左子树
{
if (parent==null) //欲删除节点是根节点
{
return cur.left;
}
if (parent.left==cur) //欲删除节点是其父节点的左子树
{
parent.left=cur.left;
}
else //否则是其右子树
{
parent.right=cur.left;
}
}
else //欲删除节点有左右子树
{
TreeNode tmp=cur.right; //找到右子树最左边节点(右子树中序遍历第一个节点)也叫后继节点
TreeNode tmp_parent=cur; //后继节点的父节点
while (tmp.left!=null)
{
tmp_parent=tmp;
tmp=tmp.left;
}
tmp.left=cur.left;
if (tmp.right!=null) //若后继节点有右子树
{
if (tmp_parent!=cur) //排除欲删除节点刚好是其后继节点的父节点
{
tmp_parent.left=tmp.right; //后继节点右子树代替后继节点成为其父节点的左子树
tmp.right=cur.right;
}
}
if (parent==null) //欲删除节点是根节点
{
return tmp;
}
else if (parent.right==cur) //欲删除节点是其父节点的右子树
{
parent.right=tmp;
}
else //欲删除节点是其父节点的左子树
{
parent.left=tmp;
}
}
return root;
}
7.完整代码如下:
package search;
/**
* Created by 灵魂都在冒香气的神 on 2018/2/24.
*/
public class TreeNode
{
public int data;
public TreeNode left;
public TreeNode right;
public TreeNode(int num)
{
data=num;
}
public TreeNode()
{
}
}
package search;
import java.util.Arrays;
/**
* Created by 灵魂都在冒香气的神 on 2018/2/24.
* 二叉搜索树
*/
public class BinarySearch
{
public static TreeNode createTree(int[] num)
{
Arrays.sort(num);
TreeNode root=null;
return build(num,root,0,num.length-1);
}
public static TreeNode search0(TreeNode root, int key) //递归实现搜索
{
if (root==null)
{
return null; //说明没有这个key
}
if (root.data==key)
{
return root;
}
if (root.data>key) //key在root的左子树
{
return search0(root.left,key);
}
return search0(root.right,key); //key在root的右子树
}
public static TreeNode search1(TreeNode root,int key) //非递归实现搜索
{
TreeNode cur;
for (cur=root;cur!=null&&cur.data!=key;)
{
cur=cur.data>key?cur.left:cur.right;
}
return cur;
}
public static Boolean insert(TreeNode root,TreeNode node) //插入节点
{
if (root.data==node.data)
{
return false;
}
if (root.data<node.data)
{
if (root.right==null)
{
root.right=node;
}
else
{
return insert(root.right,node);
}
}
else if (root.data>node.data)
{
if (root.left==null)
{
root.left=node;
}
else
{
return insert(root.left,node);
}
}
return true;
}
public static TreeNode delete(TreeNode root,int key) //删除节点
{
TreeNode parent=null;
TreeNode cur=root;
while (cur!=null&&cur.data!=key)
{
parent=cur;
cur=cur.data>key?cur.left:cur.right;
}
if (cur==null)
{
return null;
}
if (cur.left==null) //欲删除节点只有右子树
{
if (parent==null) //欲删除节点是根节点
{
return cur.right;
}
if (parent.left==cur) //欲删除节点是其父节点的左子树
{
parent.left=cur.right;
}
else //否则是其右子树
{
parent.right=cur.right;
}
}
else if (cur.right==null) //欲删除节点只有左子树
{
if (parent==null) //欲删除节点是根节点
{
return cur.left;
}
if (parent.left==cur) //欲删除节点是其父节点的左子树
{
parent.left=cur.left;
}
else //否则是其右子树
{
parent.right=cur.left;
}
}
else //欲删除节点有左右子树
{
TreeNode tmp=cur.right; //找到右子树最左边节点(右子树中序遍历第一个节点)也叫后继节点
TreeNode tmp_parent=cur; //后继节点的父节点
while (tmp.left!=null)
{
tmp_parent=tmp;
tmp=tmp.left;
}
tmp.left=cur.left;
if (tmp.right!=null) //若后继节点有右子树
{
if (tmp_parent!=cur) //排除欲删除节点刚好是其后继节点的父节点
{
tmp_parent.left=tmp.right; //后继节点右子树代替后继节点成为其父节点的左子树
tmp.right=cur.right;
}
}
if (parent==null) //欲删除节点是根节点
{
return tmp;
}
else if (parent.right==cur) //欲删除节点是其父节点的右子树
{
parent.right=tmp;
}
else //欲删除节点是其父节点的左子树
{
parent.left=tmp;
}
}
return root;
}
private static TreeNode build(int[] num,TreeNode root0,int left,int right) //递归创建二叉排序树
{
if (left>right)
{
return null;
}
int mid=(left+right)/2;
root0=new TreeNode(num[mid]);
root0.left=build(num,root0.left,left,mid-1);
root0.right=build(num,root0.right,mid+1,right);
return root0;
}
}