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

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


}


演示程序

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值