一、二叉查找树的特点
1.左子树的值小于根节点值
2.又子树的值大于根节点值
二、两种方式查找
1.特定目标查找
**特定目标查找时只需要给出查找的值,判断其与根的值,如果目标值小则向左查找,如果目标值大则向右查找**
public Point Search(int num) {
temp = root; //temp为辅助指针初始设为temp = root;
while(true) {
if(num<temp.num) {
temp = temp.left;
}
if(num>temp.num) {
temp = temp.right;
}
if(num == temp.num) {
break;
}
if(temp==null) {
throw new RuntimeException("节点不存在");
}
}
return temp;
}
2.最大、最小值查找
根据二叉查找树的特性,最小值位于树的最左端,最大值位于树的最右端,即可使用循环依次向左、右查找,直到左、右节点的下一个节点为空时返回该节点。
//最大值查找方法
public Point MaxSearch() {
temp = root;
while(true) {
if(temp.right==null) {
break;
}
temp = temp.right;
}
return temp;
}
//最小值查找方法
public Point MinSearch() {
temp = root;
while(true) {
if(temp.left==null) {
break;
}
temp = temp.left;
}
return temp;
}
三、二叉搜索树的插入
二叉搜索树的插入与查找类似,都是以二叉查找树的特性进行插入,区别在于在最后一级比较后需要把新增的节点放入查找出的最后一个节点之后。
public void insert() {
temp = root;
System.out.println("请输入要插入的节点的名称、编号");
Point newPoint = new Point(in.next(), in.nextInt()); //通过手动输入增加新节点
while(true) {
if(newPoint.num<temp.num) {
if(temp.left==null) { //当条件成立时即为最后一个节点的左儿子为空
temp.left = newPoint; //将新增节点插入至最后一个节点的左儿子
break;
}
temp = temp.left;
}
if(newPoint.num>temp.num) {
if(temp.right==null) { //当条件成立时即为最后一个节点的又儿子为空
temp.right = newPoint; //将新增节点插入至最后一个节点的右儿子
break;
}
temp = temp.right;
}
if(temp.num==newPoint.num) { //如果插入节点存在则break
break;
}
}
}
四、二叉搜索树的删除
二叉搜索树在删除时需分三种不同的情况
以下图为例:
*以下三种操作均由栈实现,并且放在一个while(true)循环中
栈操作及其准备操作:
Deque<Point> deque = new LinkedList<Point>();
Deque<Point> deque1 = new LinkedList<Point>();
Point res; //res用于所有删除时的临时指针
Point temp2; //temp2、3用于删除两个儿子节点的临时指针
Point temp3;
temp = root;
while(true) {
1.删除叶节点
叶节点的删除相对简单,如删除12号节点,只需找到他的父节点,再将父节点的左指针至空即可
if(temp.num>num) {
deque.addFirst(temp);
temp = temp.left;
}
if(temp.num<num) {
deque.addFirst(temp);
temp = temp.right;
}
if(temp.num==num&&temp.left==null&&temp.right==null) {
res = deque.removeFirst();
if(res.num>temp.num) {
res.left=null;
}
else {
res.right = null;
}
break;
}
2.删除只有一个儿子的节点
在图中3号节点只有一个儿子,删除3号节点的方法是将5号节点直接接在3号节点的右儿子(4号节点)上即可
//删除只有一个儿子的节点
if((temp.num==num&&temp.left==null&&temp.right!=null)||(temp.right==null&&temp.num==num&&temp.left!=null)) {
res = deque.removeFirst();
if(res.num>temp.num) {
if(temp.left!=null) {
res.left = temp.left;
break;
}
else {
res.left = temp.right;
break;
}
}
else {
if(temp.left!=null) {
res.right = temp.left;
break;
}
else {
res.right = temp.right;
break;
}
}
}
3.删除有两个儿子的节点
如果想删除有左右儿子的节点通常有两种方法
1.将要删除节点的左子树中最大的数(一定是叶子节点,如:想删除15号节点,在15号节点的左子树中最大的数为14,最大的数总是在左子树的右儿子并且其为叶子节点)放置在要被删除的节点上。
2.将要删除节点的右子树中最小的数(左儿子的叶子节点)放置在要被删除的节点上。
代码采用第一种方式
//删除左右儿子都不空的节点
if(temp.num==num&&temp.left!=null&temp.right!=null) {
res = temp.left;
while(true) {
deque1.addFirst(res);
if(res.left==null&&res.right==null) {
break;
}
res = res.right;
}
deque1.removeFirst();
temp2 = deque.removeFirst();
temp3 = deque1.removeFirst();
temp3.right=null;
if(temp.num<temp2.num) {
temp3.right=null;
temp2.left = res;
res.left = temp.left;
res.right = temp.right;
break;
}
else {
temp3.right=null;
temp2.right = res;
res.left = temp.left;
res.right = temp.right;
break;
}
}