什么是二叉排序树?
二叉排序树(Binary Search Tree)又称二叉查找树,是一种高效的数据结构。它是满足以下性质的特殊二叉树。
1.若他的左子树不空,则左子树上的所有节点值均小于根节点的值;
2.若它的右子树不为空,则右子树上所有节点的值均大于根节点的值;
3.它的左右子树都分别是二叉排序数
我们可以看出,其实二叉排序树的定义是一个递归定义。
下面我们先通过一个实例来构造一棵二叉排序树:
假设输入的数组是32,44,72,58,21,80,14,23
构造分为下面几步:
1.首先我们要将第一个点作为根节点;
2.比较下一个数和根节点的大小,如果大于根节点则找到根节点的右子树,和右子树的根比较,依次类推;
3.比较下一个数和根节点的大小,如果小于根节点则找到根节点的左子树,和左子树的根比较,依次类推;
下面我们通过图画来解释一下:
好了,图也看了,应该也挺清晰了,下面我们就来上代码把!
二叉排序数的创建:
//输入的序列,用此数列建立二叉排序树
private int[] nums= {32,21,14,65,58,44,72,80};
private TreeNode root;
//创建二叉排序树
public void create_tree() {
for(int i=0;i<nums.length;i++) {
//如果i==0证明该点是树的根节点
if(i==0) {
root=new TreeNode(nums[i],null,null);
}else {
TreeNode temp=root;
//设置成死循环,只有达到条件时跳出
while(true) {
//小于当前节点则向左走
if(temp.getData()>nums[i]) {
//找到可插入的点,结束循环
if (temp.getLchild()==null) {
temp.setLchild(new TreeNode(nums[i],null,null));
break;
}else {
temp = temp.getLchild();
}
}else {
if (temp.getRchild()==null) {
temp.setRchild(new TreeNode(nums[i],null,null));
break;
}else {
temp = temp.getRchild();
}
}
}
}
}
}
下面是查询代码,查询这棵二叉树:
//对创建好的二叉排序树进行查找操作
public boolean search(TreeNode root,int data) {
TreeNode temp=root;
while(temp!=null) {
/**
* 一样的思路大右小左
*/
if(temp.getData()==data) {
System.out.println("在二叉排序树中查找到了目标值"+data);
break;
}else if(temp.getData()>data) {
temp=temp.getLchild();
}else {
temp=temp.getRchild();
}
}
if(temp==null) {
System.out.println("查找失败!");
return false;
}else {
return true;
}
}
下面是对二叉排序数的插入操作:
//对创建好的二叉排序树进行增加节点的操作
public void insert(TreeNode root,int data) {
TreeNode temp=root;
if (search(root,data)) {
System.out.println("二叉排序数中已经存在待插入值:"+data+"无法重复插入");
return;
}
while(true) {
if(temp.getData()>data) {
if (temp.getLchild()==null) {
temp.setLchild(new TreeNode(data,null,null));
System.out.println("插入成功!");
break;
}else {
temp = temp.getLchild();
}
}else {
if (temp.getRchild()==null) {
temp.setRchild(new TreeNode(data,null,null));
System.out.println("插入成功!");
break;
}else {
temp = temp.getRchild();
}
}
}
}
关于删除,算是比较难的操作
/**
* 我们在这里删除分为四种情况:
* 1.待删除节点既有左子树又有右子树
* >处理方法:这种情况下可以有两种选择
* 1-我们可以选择待删除节点的左子树最靠近右上的节点代替待删除节点(也就是树的中序遍历左子树遍历的最后一个访问的节点)
* 2-我们可以选择待删除节点的右子树最靠近左上的节点代替待删除节点(也就是树的中序遍历右子树遍历的第一个访问的节点)
* (其实我们通过中序遍历可以看出这其实就是和待删除节点相邻的两个节点)
* 2.待删除节点只有左子树
* >处理方法
* 1-待删除节点的左孩子代替删除节点
* 3.待删除节点只有右子树
* >处理方法
* 1-待删除节点的右孩子代替删除节点
* 4.待删除节点为叶子节点
* >处理方法
* 1-直接删除当前节点
*/
下面是对二叉排序数的删除操作:
//创建删除二叉排序树节点的方法
public void delete(TreeNode root,int data) {
/**
* 我们在这里删除分为四种情况:
* 1.待删除节点既有左子树又有右子树
* >处理方法:这种情况下可以有两种选择
* 1-我们可以选择待删除节点的左子树最靠近右上的节点代替待删除节点(也就是树的中序遍历左子树遍历的最后一个访问的节点)
* 2-我们可以选择待删除节点的右子树最靠近左上的节点代替待删除节点(也就是树的中序遍历右子树遍历的第一个访问的节点)
* (其实我们通过中序遍历可以看出这其实就是和待删除节点相邻的两个节点)
* 2.待删除节点只有左子树
* >处理方法
* 1-待删除节点的左孩子代替删除节点
* 3.待删除节点只有右子树
* >处理方法
* 1-待删除节点的右孩子代替删除节点
* 4.待删除节点为叶子节点
* >处理方法
* 1-直接删除当前节点
*/
//找到待删除节点
TreeNode temp=root;
TreeNode perv=null;
TreeNode q=null;
TreeNode s=null;
//查找待删除节点和其前驱节点
while(temp!=null) {
if(temp.getData()==data) {
break;
}
//保存前驱节点
perv=temp;
if(temp.getData()>data) {
temp=temp.getLchild();
}else {
temp=temp.getRchild();
}
}
if(temp==null) {
System.out.println("删除失败,原因是当前二叉排序树中不存在待删除节点");
return;
}
if(temp.getLchild()==null) {
if(perv==null) {
root=root.getRchild();
}else if(perv.getLchild()==temp) {
perv.setLchild(temp.getRchild());
}else {
perv.setRchild(temp.getRchild());
}
}else {
q=temp;
s=temp.getLchild();
while(s.getRchild()!=null) {
q=s;
s=s.getRchild();
}
if(q==temp) {
q.setLchild(s.getLchild());
}else {
q.setRchild(s.getLchild());
}
temp.setData(s.getData());
s=null;
}
}
这基本上就包含了对二叉排序数的基本日常操作。还望采纳!