我们知道二分查找可以缩短查找的时间和复杂度,但是二分查找的要求是序列必须是有序的,所以我们引用了二分排序树
二叉排序树,又称二叉查找树、二叉搜索树、B树。
二叉树具有以下独特的性质:
若左子树不空,则左子树上所有的节点的值均小于根节点。
若右子树不空,则右子树上所有的节点的值均小于或等于根节点。
左右子树也分别为二叉排序树。
同样,上面三个规则和二叉树的定义都是递归定义:左子树所有子节点都比该节点小,右子树的所有子节点逗逼该节点大。
二叉排序树又一个非常重要的点:中序遍历二叉排序树,他的结果一定是从小到大的。不明朗的同学可以理一下二叉排序树的中序遍历。
根据二叉排序树,我们可以知道,在查找某个元素的时候
相同返回该节点,如果为空则返回空。
该元素比节点元素小,则返回左子树。
该元素比节点元素大,则返回右子树。
1)查找
同样的,这是递归的一种方式实现查找。我们也可以转换一下思想,这就是一个用树实现的二分查找。
实现过程:
public BinarySortTreeNode getRoot(){ return mRoot; } public BinarySearchTree(BinarySortTreeNode root){ this.mRoot=root; } public BinarySortTreeNode Search(int data){ return Search(mRoot,data); } public BinarySortTreeNode Search(BinarySortTreeNode node,int data){ if(node==null||node.getData()==data){ return node; } if(node.getData()>data){ return Search(node.getLeftChild(),data); } else{ return Search(node.getRightChild(),data); } }
2)插入:
插入分为两个部分
1、查找是否有整个元素,如果有,则直接返回;
2、找到合适的位置,进行插入操作
实现代码如下
public void insert(int data){ if(mRoot==null){ mRoot=new BinarySortTreeNode(data,null,null); mRoot.setData(data); return ; } searchandinsert(null,mRoot,data); } private BinarySortTreeNode searchandinsert(BinarySortTreeNode parent,BinarySortTreeNode node,int data){ if(node==null){ //destination node=new BinarySortTreeNode(data,null,null); if(parent!=null){ if(data<parent.getData()){ parent.setLeftChild(node); } else parent.setRightChild(node); } return node; } if(node.getData()==data)return node; else if(node.getData()>data) return searchandinsert(node,node.getLeftChild(),data); else return searchandinsert(node,node.getRightChild(),data); }
3)删除
删除中会考虑很多种情况,其中包括删除节点是否有左右节点、删除节点是其父节点的左节点还是右节点。 这些判断在代码中会很好的理解出啦
public BinarySortTreeNode searchParent(int data){ return searchParent(null,mRoot,data); } public BinarySortTreeNode searchParent(BinarySortTreeNode parent,BinarySortTreeNode node,int data){ if(node==null)return null; if(data==node.getData())return parent; else if(data<node.getData())return searchParent(node,node.getLeftChild(),data); else return searchParent(node,node.getRightChild(),data); } public void delete(int data){ if(mRoot==null)return ; if(mRoot.getData()==data){ mRoot=null;return; } BinarySortTreeNode parent=searchParent(data); if(parent==null)return; BinarySortTreeNode deleteNode=Search(data); if(deleteNode==null)return; //deleteNode has not any subtree if(deleteNode.getLeftChild()==null&&deleteNode.getRightChild()==null){ if(parent.getLeftChild()!=null&&parent.getLeftChild().getData()==data) parent.setLeftChild(null); else parent.setRightChild(null); deleteNode=null; } //deleteNode only has the left subtree else if(deleteNode.getLeftChild()!=null&&deleteNode.getRightChild()==null){ if(parent.getLeftChild()!=null&&parent.getLeftChild().getData()==data) parent.setLeftChild(deleteNode.getLeftChild()); else parent.setRightChild(deleteNode.getLeftChild()); deleteNode=null; } else if(deleteNode.getLeftChild()==null&&deleteNode.getRightChild()!=null){ if(parent.getLeftChild()!=null&&parent.getLeftChild().getData()==data) parent.setLeftChild(deleteNode.getRightChild()); else parent.setRightChild(deleteNode.getRightChild()); } // // else{ BinarySortTreeNode parentofInherientNode=deleteNode; BinarySortTreeNode heresNode=deleteNode.getRightChild(); if(heresNode.getLeftChild()==null) heresNode.setLeftChild(deleteNode.getLeftChild()); else{ while(heresNode.getLeftChild()!=null){ parentofInherientNode=heresNode; heresNode=heresNode.getLeftChild(); } parentofInherientNode.setLeftChild(null); heresNode.setLeftChild(deleteNode.getLeftChild()); heresNode.setRightChild(deleteNode.getRightChild()); } if(parent.getLeftChild()!=null&&parent.getLeftChild().getData()==data) parent.setLeftChild(heresNode); else parent.setRightChild(heresNode); deleteNode=null; } }
当然,以上方法的具体功能和实现根据不同的需求,可以发生改变,就像我前面说的,我们只要掌握住整个树的结构,和核心的递归思想。我们就能够使用和扩展不同的树。