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 stub
return 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 stub
return 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 stub
return 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;
}
}
}