先看一个需求
给你一个数列(7,3,10,12,5,1,9),要求能够高效的完成对数据的查询和添加
解决方案分析
- 使用数组
- 数组未排序,优点:直接在数组尾添加,速度快。缺点:查找速度慢
- 数组排序,优点:可以使用二分查找,查找速度快,缺点:为了保证数组有序,在添加新数据时,找到插入位置后,后面的数据需要整体移动,速度慢
- 使用链式存储-链表
不管链表是否有序,查找速度都慢,添加数据速度比数组快,不需要数据整体移动 - 使用二叉排序树
二叉排序树介绍
二叉排序树:BST:(Binary Sort(serach) Tree),对于二叉排序树的任何一个非叶子节点,要求左子节点的指比当前节点的指小,右子节点的值比当前节点的值大。
特别说明:如果有相同的值,可以将该节点放在左子节点或右子节点
比如针对前面的数据,对应的二叉排序树为:
二叉排序树创建和遍历
一个数组创建成对应的二叉排序树,并使用中序遍历二叉排序树,比如:数组为Array(7,3,10,12,5,1,9),创建成对应的二叉排序树为
二叉排序树的删除
二叉排序树的删除情况比较,有下面三种情况需要考虑
1.删除叶子节点(比如:2,5,9,12)
思路 :只针对删除叶子节点
-
需要先去找到要删除的节点, targetnode
-
找到targetnode的父节点 parent
-
确定targetnode是parent的左子节点 还是右子节点
-
根据前面的情况来对应删除
左子节点 parent.left=null;
右子节点parent.right=null;
2.删除只有一颗子树的节点(比如:1)
思路:
- 先找到要删除的节点targetnode
- 找到targetnode的父节点
- 确定targetnode的子节点是左子节点还是右子节点
- targetnode是parent的左子节点还是右子节点
- 如果targetnode有左子节点
- 如果targetnode是parent的左子节点parent.left=targetnode.left
- 如果targetnode是parent的右子节点parent.right=targetnode.left
- 如果targetnode有右子节点
- 如果targetnode是parent 的左子节点parent.left=targetnode.right
- 如果targetnode是parent的右子节点parent.right=targetnode.right
3.删除有两颗子树的节点(比如:7,3,10)
思路:
1.需求先去找到要删除的节点targetNode
2.找到targetnode的父节点 parent
3.从targetNode 的右子树找到最小的节点
4.用一个临时变量,将最小节点的值保存 temp=11;
5.删除该最小节点
6.targetnode.value=temp;
package cxf.xiangxiang;
public class feifeiTest {
public static void main(String[] args) {
BinarySorttree binarySorttree = new BinarySorttree();
int[] arr={7,3,10,12,5,1,9};
for (int i = 0; i < arr.length; i++) {
binarySorttree.add(new Node(arr[i]));
}
binarySorttree.add(new Node(2));
binarySorttree.midorder();
Node search = binarySorttree.search(10);
System.out.println(search);
// binarySorttree.del(2);
// binarySorttree.del(1);
// binarySorttree.del(7);
binarySorttree.del(7);
System.out.println("--------");
binarySorttree.midorder();
}
}
class BinarySorttree{
private Node root;
//删除节点
public void del(int value){
if(root==null){
return;
}else{
Node targetNode = search(value);
//如果没有找到要删除的节点直接返回
if(targetNode==null){
return;
}
//找到了 要删除的节点 并且bst只有一个根节点 就直接删除根节点
if(root.left==null && root.right==null){
root=null;
return;
}
//找节点的父节点
Node node = searchParent(value);
//如果要删除的节点是叶子节点
if(targetNode.left==null && targetNode.right==null){
if(node.right!=null && node.right.value==value){
node.right=null;
}else if (node.left!=null && node.left.value==value){
node.left=null;
}
}else if(targetNode.left!=null && targetNode.right!=null){
int i = delRightTreeMin(targetNode.right);
targetNode.value=i;
}else{//删除只有一个子树的节点
//如果删除的节点只有左子节点
if(targetNode.left!=null){
if( node.left!=null && node.left.value==value ){
node.left=targetNode.left;
}else if(node.right!=null && node.left.value==value ){
node.right=targetNode.left;
}
}else{//要删除的节点只有右子树
if(node.left!=null && node.left.value==value){
node.left=targetNode.right;
}else if(node.right!=null && node.right.value==value){
node.right=targetNode.right;
}
}
}
}
}
/**
*
* @param node 传入的节点(当前二叉排序树的根节点)
* @return 返回的以node 为根节点的二叉排序树的最小值
*/
public int delRightTreeMin(Node node){
Node target=node;
while(target.left!=null){
target=target.left;
}
//将该根节点的二叉排序树的最小值删除并返回
del(target.value);
return target.value;
}
//查找要删除的节点
public Node search(int value){
if(root==null){
return null;
}else{
return root.search(value);
}
}
//查找要删除节点的父节点
public Node searchParent(int value){
if(root==null){
return null;
}else{
return root.searchParent(value);
}
}
public void add(Node node){
if(root==null){
root=node;
}else{
root.add(node);
}
}
public void midorder(){
if(root!=null){
root.midOrder();
}else{
System.out.println("二叉排序树为空");
}
}
}
//创建node节点
class Node{
int value;
Node left;
Node right;
@Override
public String toString() {
return "Node{" +
"value=" + value +
'}';
}
public Node(int value){
this.value=value;
}
/**
*
* @param value 要删除的节点的值
* @return 如果找到就返回,如果找不到就返回null
*/
public Node search(int value){
if(value==this.value){
return this;
}else if (value <this.value){
if(this.left==null){
return null;
}
return this.left.search(value);
}else{
if(this.right==null){
return null;
}
return this.right.search(value);
}
}
//查找要删除节点的父节点
public Node searchParent(int value){
//如果当前节点就是要查找的节点的父节点就直接返回
if((this.left!=null && this.left.value==value) || (this.right!=null && this.right.value==value)){
return this;
}else{
//如果值小于当前值就向左去寻找
if(this.left!=null && value<this.value){
return this.left.searchParent(value);
}else if(this.right!=null && value>=this.value){
return this.right.searchParent(value);
}else{
return null;//没有找到父节点 同样的根节点的父节点也是null
}
}
}
//add方法往二叉排序树中添加节点
public void add(Node node){
if(node==null){
return;
}
//判断传入节点的值,和当前节点值的关系
if(node.value<this.value){
if(this.left==null){
this.left=node;
}else{
this.left.add(node);
}
}else{
if(this.right==null){
this.right=node;
}else{
this.right.add(node);
}
}
}
//中序遍历
public void midOrder(){
if(this.left!=null){
this.left.midOrder();
}
System.out.println(this);
if(this.right!=null){
this.right.midOrder();
}
}
}