【算法】堆,最大堆(大顶堆)及最小堆(小顶堆)的实现【2】---软件截图及算法代码

来源:互联网 发布:sina股票数据接口 编辑:程序博客网 时间:2024/06/05 18:20

ok,先上截图:


下面将演示堆的插入操作


【插入关键字18,17,15,19】


【插入关键字16,12,21】


【插入关键字27】


【插入关键字13】


【插入关键字11】




插入操作都大同小异。



然后进行删除操作:

【删除关键字11】


【删除关键字16】


【删除关键字13】


【删除关键字17】


【删除关键字21】



ok,我们输入数组进去,然后构建一个最小堆:





构建完毕后,我们逐个逐个数读取,形成排序完毕的数组(都从根节点开始读,每读一个根节点就删除一个根节点,调整树形结构,直到空):



下面就是核心代码了:


package heap;public class TreeNode {public TreeNode parent=null;public TreeNode leftChild=null;public TreeNode rightChild=null;public float key=0.0f;public TreeNode rightBrother=null;public TreeNode leftBrother=null;}



package heap;import java.util.ArrayList;import org.apache.velocity.runtime.directive.Break;/** * 最小堆的实现。--- * 作者:码农下的天桥。 * 这个是实现最小堆的核心方法, * 也是实现堆排序(从小到大)的核心操作类, * 它里面有一个TreeNode作为节点的模型类,各位同学在 * 看完我摘抄的相关文章及勘误后肯定明白是怎么回事。 * 至于最大堆------------聪明如你们肯定可以举一反三实现出来的。 *  * */public class MinTopHeap {private TreeNode _rootNode=null;private ArrayList<Float> _arrContainer=new ArrayList<Float>();public void setRootNode(TreeNode rootNode){_rootNode=rootNode;}public TreeNode getRootNode(){return _rootNode;}public boolean insert(float key) {/** * 假如当前节点为null,那么可以判断是第一次插入关键字,直接插入。 * */if(_rootNode==null){_rootNode=new TreeNode();_rootNode.key=key;_arrContainer.add(key);return true;}/** * 假如当前为root根节点,并且没有子节点,那么就插入到根节点的左孩子 * */if(_rootNode!=null&&_rootNode.leftChild==null&&_rootNode.rightChild==null){TreeNode cNode=new TreeNode();cNode.key=key;cNode.parent=_rootNode;_rootNode.leftChild=cNode;recursion_adjustment_after_insert(cNode);return true;}/** * 假如当前为root节点,并且有左子节点,没有右子节点,那么直接添加右子节点。 * */if(_rootNode!=null&&_rootNode.leftChild!=null&&_rootNode.rightChild==null){TreeNode cNode=new TreeNode();cNode.key=key;cNode.parent=_rootNode;_rootNode.rightChild=cNode;_rootNode.leftChild.rightBrother=cNode;cNode.leftBrother=_rootNode.leftChild;recursion_adjustment_after_insert(cNode);return true;}/** * 假如这些都不是,那么就判断该树形是不是已经满了,满了的话,直接在最左边添加一个左子节点, * 否则,找出最后的那一个叶子节点,然后判断并添加一个节点。 * */TreeNode cNode=getSuitableNode();String t1="";System.out.print(t1);if(cNode==null){return false;}TreeNode realNode=new TreeNode();realNode.key=key;if(cNode.leftChild==null){cNode.leftChild=realNode;realNode.parent=cNode;//--请注意,需要检查是否有左边的靠近这边的兄弟,有的话需要修改指针。if(cNode.parent!=null){TreeNode leftAncle=cNode.leftBrother;if(leftAncle!=null){leftAncle.rightChild.rightBrother=realNode;realNode.leftBrother=leftAncle.rightChild;}}recursion_adjustment_after_insert(realNode);return true;}else if(cNode.rightChild==null){cNode.rightChild=realNode;realNode.parent=cNode;cNode.leftChild.rightBrother=realNode;realNode.leftBrother=cNode.leftChild;recursion_adjustment_after_insert(realNode);return true;}// TODO Auto-generated method stubreturn false;}private TreeNode ___suitableNode=null;public boolean delete(float key){TreeNode lastNode=getLastNode();if(lastNode==null){return false;}if(_rootNode==null){return false;}TreeNode deletedNode=getNode(key);if(deletedNode==null){return false;}TreeNode lastParent=lastNode.parent;if(lastParent!=null){boolean isLeft=true;if(lastParent.rightChild!=null&&lastParent.rightChild.key==lastNode.key){isLeft=false;}if(isLeft==true){lastParent.leftChild=null;if(lastParent.leftBrother!=null){lastParent.leftBrother.rightChild.rightBrother=null;}}else{lastParent.rightChild=null;lastParent.leftChild.rightBrother=null;}/** * 注意,假如删除的节点没有左右子节点,并且它与最后的真实删除的节点并非同一个,那么就必须上浮调整各个节点的位置了。 * */if(deletedNode.leftChild==null&&deletedNode.rightChild==null&&deletedNode.key!=lastNode.key){deletedNode.key=lastNode.key;     recursion_adjustment_after_insert(deletedNode);return true;}/** * 假如需要删除的节点跟最后节点是一样的,那么我们可以认为这个节点就是最后的节点。那么直接删除就好了。 * */else if(deletedNode.key==lastNode.key){return true;}else{deletedNode.key=lastNode.key;recursion_adjustment_after_deletion(deletedNode);return true;}}else{_rootNode=new TreeNode();return true;}}private TreeNode getSuitableNode(){if(_rootNode==null){return null;}if(_rootNode.leftChild==null){return _rootNode;}/** * 查看最左侧节点。 * */TreeNode preNode=null;TreeNode cNode=_rootNode;int theHeight=1;while(cNode.leftChild!=null){theHeight++;cNode=cNode.leftChild;}int lvMaxNodes=(int)Math.pow(2.0, (double)(theHeight-1));int lvRealNodes=1;TreeNode lvLastNode=cNode;while (lvLastNode.rightBrother!=null) {lvRealNodes++;lvLastNode=lvLastNode.rightBrother;}//判断当前节点所在层数的节点数量是否已经满了。if(lvRealNodes<lvMaxNodes){boolean isLeft=true;TreeNode parentNode=lvLastNode.parent;if(parentNode.rightChild!=null&&parentNode.rightChild.key==lvLastNode.key){isLeft=false;}else if(parentNode.leftChild!=null&&parentNode.leftChild.key==lvLastNode.key){isLeft=true;}if(isLeft==true){return parentNode;}else{if(parentNode.rightBrother==null){return cNode;}else{return parentNode.rightBrother;}}}else{return cNode;}}public boolean pop() {// TODO Auto-generated method stubreturn false;}public boolean containsKey(float key) {// TODO Auto-generated method stub___containsKey=false;recursion_search_key(_rootNode, key);return ___containsKey;}private boolean ___containsKey=false;private void recursion_search_key(TreeNode node,float key){if(node==null){return;}if(node.key==key){___containsKey=true;return;}recursion_search_key(node.leftChild, key);recursion_search_key(node.rightChild, key);}private TreeNode ___searchNode=null;public TreeNode getNode(float key){___searchNode=null;recursion_search_node(_rootNode, key);return ___searchNode;}private void recursion_search_node(TreeNode currentNode,float key){if(currentNode==null){return;}if(currentNode.key==key){___searchNode=currentNode;return;}else{recursion_search_node(currentNode.leftChild, key);recursion_search_node(currentNode.rightChild, key);}}/** * 请注意,simpleinsert这个方法只是单纯将关键字插入到二叉树里面, * 每次查完它都不会主动调整使其成为一个最小堆,为什么要有这个方法呢? * 因为每个需要排序的数组往往有多个数字,假如每次插入都调整那么就很麻烦了, * 倒不如插入以后,一次性调整。 *  * */private boolean simpleInsert(float key){/** * 假如当前节点为null,那么可以判断是第一次插入关键字,直接插入。 * */if(_rootNode==null){_rootNode=new TreeNode();_rootNode.key=key;_arrContainer.add(key);return true;}/** * 假如当前为root根节点,并且没有子节点,那么就插入到根节点的左孩子 * */if(_rootNode!=null&&_rootNode.leftChild==null&&_rootNode.rightChild==null){TreeNode cNode=new TreeNode();cNode.key=key;cNode.parent=_rootNode;_rootNode.leftChild=cNode;//recursion_adjustment_after_insert(cNode);return true;}/** * 假如当前为root节点,并且有左子节点,没有右子节点,那么直接添加右子节点。 * */if(_rootNode!=null&&_rootNode.leftChild!=null&&_rootNode.rightChild==null){TreeNode cNode=new TreeNode();cNode.key=key;cNode.parent=_rootNode;_rootNode.rightChild=cNode;_rootNode.leftChild.rightBrother=cNode;cNode.leftBrother=_rootNode.leftChild;//recursion_adjustment_after_insert(cNode);return true;}/** * 假如这些都不是,那么就判断该树形是不是已经满了,满了的话,直接在最左边添加一个左子节点, * 否则,找出最后的那一个叶子节点,然后判断并添加一个节点。 * */TreeNode cNode=getSuitableNode();String t1="";System.out.print(t1);if(cNode==null){return false;}TreeNode realNode=new TreeNode();realNode.key=key;if(cNode.leftChild==null){cNode.leftChild=realNode;realNode.parent=cNode;//--请注意,需要检查是否有左边的靠近这边的兄弟,有的话需要修改指针。if(cNode.parent!=null){TreeNode leftAncle=cNode.leftBrother;if(leftAncle!=null){leftAncle.rightChild.rightBrother=realNode;realNode.leftBrother=leftAncle.rightChild;}}recursion_adjustment_after_insert(realNode);return true;}else if(cNode.rightChild==null){cNode.rightChild=realNode;realNode.parent=cNode;cNode.leftChild.rightBrother=realNode;realNode.leftBrother=cNode.leftChild;//recursion_adjustment_after_insert(realNode);return true;}// TODO Auto-generated method stubreturn false;}private void recursion_adjustment_after_insert(TreeNode _node){if(_node==null){return;}TreeNode parentNode=_node.parent;if(parentNode==null){return;}if(_node.key<parentNode.key){float tmp1=parentNode.key;parentNode.key=_node.key;_node.key=tmp1;recursion_adjustment_after_insert(parentNode);return;}else{return;}}private void recursion_adjustment_in_inition(TreeNode currentNode){if(currentNode==null){return;}if(currentNode.leftChild==null){return;}TreeNode leftChild=currentNode.leftChild;TreeNode rightChild=currentNode.rightChild;float tmpKey=currentNode.key;if(leftChild!=null&&rightChild!=null){if(leftChild.key<currentNode.key&&rightChild.key<currentNode.key){if(leftChild.key<=rightChild.key){currentNode.key=leftChild.key;leftChild.key=tmpKey;recursion_adjustment_in_inition(leftChild);return;}else{currentNode.key=rightChild.key;rightChild.key=tmpKey;recursion_adjustment_in_inition(rightChild);return;}}else if(leftChild.key<currentNode.key&&rightChild.key>=currentNode.key){currentNode.key=leftChild.key;leftChild.key=tmpKey;recursion_adjustment_in_inition(leftChild);return;}else if(leftChild.key>=currentNode.key&&rightChild.key<currentNode.key){currentNode.key=rightChild.key;rightChild.key=tmpKey;recursion_adjustment_in_inition(rightChild);return;}else{return;}}else if(leftChild!=null&&rightChild==null){if(leftChild.key<currentNode.key){currentNode.key=leftChild.key;leftChild.key=tmpKey;recursion_adjustment_in_inition(leftChild);return;}else{return;}}else{return;}}/** * 当前节点被删除后,下沉过程调整。 * */private void recursion_adjustment_after_deletion(TreeNode currentNode){if(currentNode==null){return;}float ftmp=currentNode.key;if(currentNode.leftChild==null&¤tNode.rightChild==null){return;}if(currentNode.leftChild!=null&¤tNode.rightChild!=null){if(currentNode.leftChild.key<currentNode.key&¤tNode.rightChild.key<currentNode.key){if(currentNode.leftChild.key<=currentNode.rightChild.key){currentNode.key=currentNode.leftChild.key;currentNode.leftChild.key=ftmp;recursion_adjustment_after_deletion(currentNode.leftChild);return;}else{currentNode.key=currentNode.rightChild.key;currentNode.rightChild.key=ftmp;recursion_adjustment_after_deletion(currentNode.rightChild);return;}}else if(currentNode.leftChild.key<currentNode.key){currentNode.key=currentNode.leftChild.key;currentNode.leftChild.key=ftmp;recursion_adjustment_after_deletion(currentNode.leftChild);return;}else if(currentNode.rightChild.key<currentNode.key){currentNode.key=currentNode.rightChild.key;currentNode.rightChild.key=ftmp;recursion_adjustment_after_deletion(currentNode.rightChild);return;}else{return;}}else if(currentNode.leftChild!=null&¤tNode.rightChild==null){ if(currentNode.leftChild.key<currentNode.key){currentNode.key=currentNode.leftChild.key;currentNode.leftChild.key=ftmp;recursion_adjustment_after_deletion(currentNode.leftChild);return;} return;}else{return;}}private TreeNode getLastNode(){if(_rootNode==null){return null;}TreeNode cNode=_rootNode;while(cNode.leftChild!=null){cNode=cNode.leftChild;}TreeNode lvLastNode=cNode;while(lvLastNode.rightBrother!=null){lvLastNode=lvLastNode.rightBrother;}return lvLastNode;}/** * 根据index来获得节点,请注意,index从零开始。 * */public TreeNode getTreeNodeByIndex(int loc){if(_rootNode==null){return null;}if(loc<=-1){return null;}int cindex=0;if(loc==0){return _rootNode;}else{int theHeight=1;TreeNode leftNode=_rootNode;while(leftNode.leftChild!=null){leftNode=leftNode.leftChild;theHeight++;}int cHeight=1;TreeNode resultNode=null;TreeNode lvFirstNode=_rootNode;TreeNode tmpRightNode=null;for(cindex=0;cindex<=loc;cindex++){if(cHeight>theHeight){break;}    if(lvFirstNode==null){    break;    }            if(loc==0){    return _rootNode;    }        tmpRightNode=lvFirstNode;        while(tmpRightNode!=null){    if(cindex==loc){    return tmpRightNode;    }    tmpRightNode=tmpRightNode.rightBrother;    if(tmpRightNode==null){    break;    }    else{    cindex++;    }        }lvFirstNode=lvFirstNode.leftChild;        cHeight++;}return resultNode;}}public void fromArray_origin(float[] arr){_rootNode=null;if(arr==null){return;}else{for(float f1:arr){simpleInsert(f1);}}int theLength=arr.length;int middle_loc=(int)Math.floor((double)((double)theLength/2.0))-1;if(theLength<=1){return ;}//--循环进行上浮调整。}/** * 将原始数组构建成为完全二叉树,再调整成为最小堆,然后 * 返回堆的根节点。 * 请注意查看我摘抄的图文教程,主要就是从最后一个不为叶子节点的节点开始, * 通过比较进行下沉,直到根节点结束。 * 当然,假如您的节点数据里面没有leftBrother之类的指针你会发现按照排位寻找节点是如此麻烦。 * */public TreeNode fromArray(float[] arr){_rootNode=null;if(arr==null){return null;}else{for(float f1:arr){simpleInsert(f1);}}int theLength=arr.length;int middle_loc=(int)Math.floor((double)((double)theLength/2.0))-1;System.out.println("最下面的非叶子节点:【"+middle_loc+"】");if(theLength<=1){return _rootNode;}//--循环进行上浮调整。for(int i=middle_loc;i>=0;i--){TreeNode cNode=getTreeNodeByIndex(i);recursion_adjustment_in_inition(cNode);}return _rootNode;}/** * 通过根节点来逐个读取数字,然后组成从小到大的数组。 * */public ArrayList<Float> toArray(){if(_rootNode==null){return null;}ArrayList<Float> _arr=new ArrayList<Float>();while(_rootNode!=null){_arr.add(_rootNode.key);deleteNode(_rootNode);}return _arr;}public boolean deleteNode(TreeNode currentNode){TreeNode lastNode=getLastNode();TreeNode deletedNode=currentNode;if(deletedNode==null){return false;}/** * 假如只有一个根节点,没有子节点的话,那么就直接删除 * */ if(currentNode!=null&¤tNode.parent==null&¤tNode.leftChild==null&¤tNode.rightChild==null){ _rootNode=null; currentNode=null; return true; }TreeNode lastParent=lastNode.parent;if(lastParent!=null){boolean isLeft=true;if(lastParent.rightChild!=null&&lastParent.rightChild.key==lastNode.key){isLeft=false;}if(isLeft==true){lastParent.leftChild=null;if(lastParent.leftBrother!=null){lastParent.leftBrother.rightChild.rightBrother=null;}}else{lastParent.rightChild=null;lastParent.leftChild.rightBrother=null;}/** * 注意,假如删除的节点没有左右子节点,并且它与最后的真实删除的节点并非同一个,那么就必须上浮调整各个节点的位置了。 * */if(deletedNode.leftChild==null&&deletedNode.rightChild==null&&deletedNode.key!=lastNode.key){deletedNode.key=lastNode.key;     recursion_adjustment_after_insert(deletedNode);return true;}/*** 假如需要删除的节点跟最后节点是一样的,那么我们可以认为这个节点就是最后的节点。那么直接删除就好了。* */else if(deletedNode.key==lastNode.key){return true;}else{deletedNode.key=lastNode.key;recursion_adjustment_after_deletion(deletedNode);return true;}}else{_rootNode=new TreeNode();return true;}}}


演示程序

原创粉丝点击