java数据结构 堆与堆排序

堆的定义:

1、堆是完全二叉树,能快速的访问的树中最大或者最小的元素。

2、他常常使用一个数组实现。

3、堆中每个节点的父节点的值,都大于或者小于这个节点的值。当堆中的父节点总是大于子节点的时候,我们称之为最大堆,反之称之为最小堆。

如下图a和b所示,他是一个最小堆与最大堆(图片摘自网络http://www.lxway.com/225509804.htm,侵权请告知)

数据结构>优先队列堆数据结构>优先队列堆

堆的索引:

堆用数组表示的话,若数组中节点的索引为i,那么

1、他的父节点的下标为(i-1)/2;

2、他的左子节点的下标为2*i+1;

3、他的右子节点的下标为左子节点的下标+1;

堆的操作----插入与删除:

堆的插入(以最小堆为例):

1、保证堆没满的前提下,把节点插入数组末尾。

2、向上筛选插入的节点,这个筛选的过程其实是节点复制的过程,直到他的父节点比他小,或者没有到根。

3、堆容量加1.

//插入节点
	public  boolean insert(Node data){
		if(currentSize==maxSize){
			return false;
			
		}
		Node node=data;
		heaparr[currentSize]=node;
		trickleUp(currentSize++);
		return true;
	}
	
	//向上筛选
	public  void trickleUp(int index){
		int parent=(index-1)>>1;
		Node bottom=heaparr[index];
		while(index>0 && bottom.data<heaparr[parent].data){
			heaparr[index]=heaparr[parent];
			index=parent;
			parent=(parent-1)>>1;
		}
		heaparr[index]=bottom;
	}



堆的删除(以最小堆为例):

堆的删除总是移去根节点,所以按照以下步骤

1、移走根。

2、将末尾的节点移动到根节点处

3、如果移除节点的父节点比他大,那么我们一直向下调节,对比移除节点的左子树和右子树,获得其中最小的节点,用最小节点和移除节点对比,如果最小节点比移除节点小,则交换节点,否则,就说明他已经在合适的位置上了。

4、堆容量减去1

//删除节点
	public static Node remove(){
		Node root=heaparr[0];
		heaparr[0]=heaparr[currentSize--];
		trickleDown(0);
		return root;
		
	}
	
	//向下调节
	public static void trickleDown(int index){
		Node top=heaparr[index];
		int largChild=0;
		//是否到达最后一层
		while(index<currentSize/2){
			int leftChild=(index<<1)+1;
			int rightChild=leftChild+1;
			if(leftChild<currentSize && heaparr[leftChild].data<heaparr[rightChild].data){
				largChild=leftChild;
			}else if(rightChild<currentSize && heaparr[leftChild].data>heaparr[rightChild].data){
				largChild=rightChild;
			}
			
			if(top.data>heaparr[largChild].data){
				heaparr[index]=heaparr[largChild];
				index=largChild;
			}else{
				break;
			}
			
		}
		heaparr[index]=top;
		
	}

现在给出堆(最小堆)的完整代码:


public class Heap {
	private  Node[] heaparr;	//用来存取节点的堆数组
	private  int maxSize;		//最大容量
	private   int currentSize;  //堆的末尾指针
	
	public Heap(int maxSize){
		this.maxSize=maxSize;
		heaparr=new Node[maxSize];
		currentSize=0;
		
	}
	
	
	//插入节点
	public  boolean insert(int data){
		if(currentSize==maxSize){
			return false;
			
		}
		Node node=new Node(data);
		heaparr[currentSize]=node;
		trickleUp(currentSize++);
		return true;
	}
	
	//向上筛选
	public  void trickleUp(int index){
		int parent=(index-1)>>1;
		Node bottom=heaparr[index];
		while(index>0 && bottom.data<heaparr[parent].data){
			heaparr[index]=heaparr[parent];
			index=parent;
			parent=(parent-1)>>1;
		}
		heaparr[index]=bottom;
	}
	
	//删除节点
	public  Node remove(){
		Node root=heaparr[0];
		heaparr[0]=heaparr[currentSize--];
		trickleDown(0);
		return root;
		
	}
	
	//向下调节
	public  void trickleDown(int index){
		Node top=heaparr[index];
		int largChild=0;
		//是否到达最后一层
		while(index<currentSize/2){
			int leftChild=(index<<1)+1;
			int rightChild=leftChild+1;
			if(leftChild<currentSize && heaparr[leftChild].data<heaparr[rightChild].data){
				largChild=leftChild;
			}else if(rightChild<currentSize && heaparr[leftChild].data>heaparr[rightChild].data){
				largChild=rightChild;
			}
			
			if(top.data>heaparr[largChild].data){
				heaparr[index]=heaparr[largChild];
				index=largChild;
			}else{
				break;
			}
			
		}
		heaparr[index]=top;
		
	}
	
	public  int getHeapTop(){
		if(currentSize<0){
			return -1;
		}
		return heaparr[0].data;
	}
	//节点结构
	private  class Node{
		public int data;
		public Node(int data){
			this.data=data;
		}
	}
	
}

堆的排序:

我们都知道根节点是最大或者最小的节点,我们普通的删除插入就可以让一组无序的数组变的有序,这里给出O(N*logN)的代码。

	//堆排序
	public void MinheapsortTodescendarray(Node[] arr){
		//边界查询
		if(arr==null || arr.length==0){
			return;
		}
		for(int i=0;i<arr.length;i++){
			insert(arr[i]);
		}
		for(int i=0;i<arr.length;i++){
			arr[i]=remove();
		}
	}


 

参考资料:

Java数据结构与算法:第12章 堆

白话经典算法系列之堆与堆排序:http://blog.csdn.net/morewindows/article/details/6709644/

百度百科: 堆与堆排序


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值