标签:
package com.charles.algo.binarysearchtree; import com.charles.algo.binarytree.BinaryTreeNode; /** * 这个类是二叉搜索树的定义 * @author charles.wang * */ public class BinarySearchTree<V> { //根节点 private BSTreeNode<V> rootNode; public BinarySearchTree(){ rootNode = null; } /** * 返回关键字匹配的节点的值 */ public V search (int key){ //如果根节点为空,那么这个二叉搜索树为空,肯定无匹配值 if(rootNode==null) return null; //如果根节点不为空,那么从根开始比较,因为二叉搜索树都是保持了左<根<右的结构,所以很快能找到匹配值 BSTreeNode<V> currentNode = rootNode; while (currentNode!=null){ //如果当前节点的key刚好和请求的key匹配,那么则返回当前节点的值 if( key==currentNode.getKey()) return currentNode.getValue(); //如果当前的节点的key和请求的key不匹配,那么进行比较 //如果传入的key比当前节点的key小,那么匹配的值(如果有),必定在当前节点的左子搜索树中 //吧待搜节点设为当前节点的左子节点 else if ( key< currentNode.getKey()) currentNode=currentNode.getLeftChild(); //如果传入的key比当前的节点的key大,那么匹配的值(如果有),必定在当前节点的右子搜索树中 //把待搜节点设为当前节点的右子节点 else currentNode=currentNode.getRightChild(); } //如果跳出了while循环还没找到匹配的值,说明在这个搜索树中找不到,返回null return null; } /** * 插入一个节点到二叉搜索树中 * @param key * @param value */ public void insertNode( int key, V value){ //先搜索二叉搜索树是否已经有相同的节点,如果有,则不执行插入动作 if (search(key)!=null) return; BSTreeNode<V> newNode= new BSTreeNode<V> (null,null,key,value); //假设是二叉搜索树还没有任何内容,那么该赋值给根节点 if(rootNode==null){ rootNode = newNode; } //假设二叉搜索树已经存在,那么从根开始,找到适合其插入的位置 //如果判断某个位置是否是其可以插入? //方法是,从根开始标记为当前节点,如果新节点的key比当前节点的key小,那么说明插在当前节点的左子树中 //这时候,如果左节点为空,那么新节点就作为当前节点的左边节点 // 如果左节点不为空,那么比较左节点的key和新节点的key, // 如果新节点的key大于左节点的key,那么吧新节点插入到左节点和当前节点之间,退出循环 // 如果新节点的key小于左节点的key,那么吧当前节点设为当前节点的左节点。 //右节点处理与上述类似 else{ BSTreeNode<V> currentNode= rootNode; //比较新节点的key和当前节点的key while(currentNode!=null){ //插入到左子树中 if(key< currentNode.getKey()){ //当前节点的左节点为空,那么找到了合适位置 if(currentNode.getLeftChild()==null){ currentNode.setLeftChild(newNode); break; } //当前节点的左节点不为空,则比较左节点的key和新节点的key else{ //如果新节点key大于当前节点的左节点的key,则说明新节点的key刚好位于当前节点的左节点和当前节点之间 //这是一个合适的插入位置 if (key > currentNode.getLeftChild().getKey()){ newNode.setLeftChild(currentNode.getLeftChild()); currentNode.setLeftChild(newNode); break; } //如果新节点key比当前节点左节点还小,那么说明适合插入的位置位于当前节点的左搜索子树中,于是移动当前节点 //到左子节点作为新的比较的基准 else{ currentNode=currentNode.getLeftChild(); } } } //插入到右子树中 else { //如果当前节点的右节点为空,那么找到了合适的位置 if( currentNode.getRightChild()==null){ currentNode.setRightChild(newNode); } //如果当前节点的右节点不为空,那么比较右节点的key和新节点的key else{ //如果新节点的key小于当前节点的右节点的key,则说明新节点的key刚好位于当前节点和当前节点的右节点之间 //这是一个合适的插入位置 if(key < currentNode.getRightChild().getKey()){ newNode.setRightChild(currentNode.getRightChild()); currentNode.setRightChild(newNode); break; } //如果新节点的key比当前节点的右边节点还大,说明适合插入的位置位于当前节点的右搜索子树中,于是移动当前节点 //到右子节点作为新的比较的基准 else { currentNode = currentNode.getRightChild(); } } } } } } /** * 删除指定key的节点 * @param key */ public void deleteNode(int key){ //如果二叉搜索树中没有对应key的节点,那么不执行删除操作 if(search(key)==null) return; //否则,肯定有key节点,首先定位到这个节点 BSTreeNode<V> currentNode = rootNode; BSTreeNode<V> currentNodeParentNode= null; //当前节点的父亲节点 while( currentNode.getKey()!=key){ //如果要删除的节点key比当前节点的key小,那么说明要删除的节点在左子树中 if(key<currentNode.getKey()){ currentNodeParentNode=currentNode; currentNode=currentNode.getLeftChild(); } else{ currentNodeParentNode=currentNode; currentNode=currentNode.getRightChild(); } } //跳出上述while循环时候,currentNode就指向了即将要被删除的节点,currentNodeParentNode指向了被删除节点的父亲节点 //这时候删除分为若干种情况 //情况1,假设currentNode既有左子节点又有右子节点,那么删除currentNode后有一个洞, //这个洞的值必须从已有元素中取一个填充,而且这个元素必须比左子树所有节点都大,并且比右子树所有节点都小 //显然这里有2个备选方案: //一个是左子树的最大节点,它大于所有左子树节点(除去自身),并且小于当前被删节点,也就小于所有右子树节点 //另一个是右子树的最小节点。它小于所有右子树节点(除去自身),并且大于当前被删节点,也就大于所有左子树节点 //如果我们采用了左子树的最大节点,那么这种情况就转为只有左子树的情况了 if( ( currentNode.getLeftChild()!=null) && (currentNode.getRightChild()!=null) ){ //找到左子树的最大节点 BSTreeNode<V> maxNode = currentNode.getLeftChild(); //这变量存放了要找的最大节点 BSTreeNode<V> maxNodeParentNode= currentNode; //这变量存放了要找的最大节点的父节点 while(maxNode.getRightChild()!=null){ //向右移动 maxNodeParentNode=maxNode; maxNode= maxNode.getRightChild(); } //吧最大节点插入到currentNode中,从而维持了原有的结构不变 currentNode.setKey(maxNode.getKey()); currentNode.setValue(maxNode.getValue()); //删除左子树的原最大节点 maxNodeParentNode.setRightChild(null); return ; } //情况2,如果当前节点既没有左节点又没有右节点,则直接丢弃 if(( currentNode.getLeftChild()==null) && (currentNode.getRightChild()==null) ){ //如果当前节点为根节点,那么删除根节点 if(currentNode==rootNode){ rootNode=null; } //如果当前节点不为根节点,那么必定有父亲节点,这时候只要丢弃当前节点就可以了,判断是判断当前节点是父亲节点的左儿子还是右儿子 if(currentNode==currentNodeParentNode.getLeftChild()){ currentNodeParentNode.setLeftChild(null); } else currentNodeParentNode.setRightChild(null); return; } //情况3,如果当前节点只有左节点或者右节点中的1个,那么吧儿子提升上来 else { //如果只有左节点 if( currentNode.getLeftChild()!=null){ //如果当前节点为根节点,那么吧左节点提升上来当根节点 if(currentNode==rootNode){ rootNode=currentNode.getLeftChild(); } //如果当前节点不为根节点,那么必定有父节点,则判断当前节点是父亲节点的左儿子还是右儿子,并且用左节点值取代之 else if(currentNode==currentNodeParentNode.getLeftChild()){ currentNodeParentNode.setLeftChild(currentNode.getLeftChild()); } else currentNodeParentNode.setRightChild(currentNode.getLeftChild()); } //如果只有右节点 else{ //如果当前节点为根节点,那么吧右节点提升上来当根节点 if(currentNode==rootNode){ rootNode=currentNode.getRightChild(); } //如果当前节点不为根节点,那么必定有父节点,则判断当前节点是父亲节点的左儿子还是右儿子,并且用右节点值取代之 if(currentNode==currentNodeParentNode.getLeftChild()){ currentNodeParentNode.setLeftChild(currentNode.getRightChild()); } else currentNodeParentNode.setRightChild(currentNode.getRightChild()); } } } /** * 因为二叉搜索树中,左<根<右,所以我们可以用中序遍历的方法来打印出所有的节点 */ public void printAllNodes(){ midOrder(rootNode); } /** * 中序遍历某节点,它会先打印左边节点,再打印当前节点,最后打印出右边节点 * @param args */ private void midOrder(BSTreeNode currentNode){ //当前节点如果是null,则不打印出当前节点,并且退出递归 if(currentNode!=null){ midOrder(currentNode.getLeftChild()); System.out.print(currentNode.getValue()+" "); midOrder(currentNode.getRightChild()); } } }
public static void main(String[] args){ //构造一颗二叉搜索树,其中key为每个人的能力强度(假设每个人的个人能力都不同) ,value为每个人的名字 //Charles:1000 //Jack: 422 //Penny: 635 //Jude: 95 //John: 23 //Golden 768 //Bull: 79 BinarySearchTree<String> bsTree = new BinarySearchTree<String>(); bsTree.insertNode(1000, "Charles"); bsTree.insertNode(422,"Jack"); bsTree.insertNode(635, "Penny"); bsTree.insertNode(95, "Jude"); bsTree.insertNode(23, "John"); bsTree.insertNode(768, "Golden"); bsTree.insertNode(79, "Bull"); //测试二叉搜索树的搜索 System.out.println("测试在二叉搜索树中搜索."); int powerKey1 = 422; String powerValue1 = bsTree.search(powerKey1); if(powerValue1==null) System.out.println("找不到匹配强度为:"+powerKey1+"的人."); else System.out.println("强度为"+powerKey1+"的人名字叫:"+powerValue1); int powerKey2 = 420; String powerValue2 = bsTree.search(powerKey2); if(powerValue2==null) System.out.println("找不到匹配强度为:"+powerKey2+"的人."); else System.out.println("强度为"+powerKey2+"的人名字叫:"+powerValue2); System.out.println(); //测试打印出所有二叉搜索树的节点,升序 System.out.println("测试二叉搜索树中各个节点是否有序排列了"); System.out.print("所有人强度按照升序排名为:"); bsTree.printAllNodes(); System.out.println(); //测试二叉搜索树的删除,看每次删除是否还维持二叉搜索树的结构 System.out.println("删除 Jude:"); bsTree.deleteNode(95); System.out.println("删除后所有人强度升序排名为:"); bsTree.printAllNodes(); System.out.println(); System.out.println("删除 Charles:"); bsTree.deleteNode(1000); System.out.println("删除后所有人强度升序排名为:"); bsTree.printAllNodes(); }
标签:
原文地址:http://blog.csdn.net/zhushuai1221/article/details/51908766