堆的结构及实现

32 篇文章 0 订阅
22 篇文章 0 订阅

1.知识储备:
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
2.堆的API设计:
在这里插入图片描述
上浮算法图解:
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
下沉算法图解:
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
3代码实现:

package heap;

public class Heap<T extends Comparable<T>>{
    //存储堆中的元素,用数组实现
	private T[] items;
	//记录堆中元素的个数
	private int N;
	public Heap(int capacity) {
		// TODO Auto-generated constructor stub
		this.items=(T[]) new Comparable[capacity+1];
		this.N=0;
	}
	
	//判断堆中索引i处的元素是否小于j处的元素
	private boolean less(int i,int j){
		return items[i].compareTo(items[j])<0;
	}
	
	//交换堆中i处索引和j处索引的值
	private void exch(int i,int j){
		T item =items[i];
		 items[i]=items[j];
		 items[j]=item;
	}
	
	//往堆中插入一个元素
	public void insert(T t){
		items[++N]=t;
		swim(N); 
	}
	
	//使用上浮算法,使得索引k处的元素再堆中处于一个正确的位置
	private void swim(int k){
		//通过循环不断地比较当前节点的值与其父节点的值,如果发现父节点的值比当前节点的值小,则交换位置
		//while循环的结束条件为k>1,因为ke最小可以上浮到根节点的左子树位置,当k<=1就不用比较了
		while(k>1){
			//比较当前节点和其父节点
			//如果其父节点比当前节点的值要小
			if(less(k/2,k)){    
				//交换他们两的位置
				exch(k/2,k);   
				//变换k的值,以便继续比较
				k=k/2;
			}
			//这里要注意一个bug,k/2的值不小于k的值,那么由于k的值无法改变,程序就会陷入死循环,所以这里要设置一下,不满足条件则退出循环
			else{
				break;
			}
		}
	}
	
	//使用下沉算法,使得索引k处的元素再堆中处于一个正确的位置
	private void sink(int k){
		//通过循环不断对比,当前k节点和其左子节点2k以及其右子节点2k+1元素中的较大值进行比较,如果当前节点小,则交换位置
		//while循环的条件为2*k<=N,这样才能保证当前节点有左子节点
		while(2*k<=N){
			//获取当前节点的左右子节点中的较大值
			//记录较大值所在的索引
			int max;
			//如果当前节点存再右子节点
			if(2*k+1<=N){
				//比较左右子节点的值
				//如果左子节点小于右子节点
				if(less(2*k,2*k+1)){
					//较大值为右子节点索引
					max=2*k+1;
				}else{
					max=2*k;
				}
			}
			//如果不存在右子节点
			else{
				//较大值直接等于左子节点
				max=2*k;
			}
			//比较当前节点和较大值的节点的值
			//如果当前节点的值不小于它子节点的值,直接结束循环即可
			if(!less(k,max)){
				break;
			}
			//交换索引k处和索引max处的值
			else{
				exch(k,max);
				//变换k的值,继续比较
				k=max; 
			}
		}
	}
	
	//删除堆中的最大元素,并返回这个元素
	public T delMax(){
		T max=items[1];
		//交换索引1处元素和最大索引处元素的值,让完全二叉树最右侧的元素变为临时的根节点
		exch(1,N);
		//最大索引处的元素删除掉
		items[N]=null;
		//元素个数-1
		N-=1;
		//通过下沉调整堆,让堆重新有序
		sink(1);
		return max;
	}
	
	//提供遍历方法
	public  void traversal(){
		for(int i=1;i<items.length;i++){
			System.out.print(items[i]+"->");
		}
			System.out.println();
	}
}

4.测试案例:

package heap;

public class heapTest1 {
    public static void main(String[] args) {
		//创建堆对象
    	Heap<String> heap1 =new Heap<String>(10);
    	//往堆中插入字符串数据
    	heap1.insert("D");
    	heap1.insert("C");
    	heap1.insert("A");
    	heap1.insert("F");
    	heap1.insert("B");
    	heap1.insert("G");
    	heap1.insert("E");
    	heap1.insert("J");
    	heap1.insert("H");
    	heap1.insert("I");
    
    	//通过循环从堆中删除元素,如果程序写的没有问题,那么每次删除的元素索引为一的元素,而且是元素中值最大的
    
    	//遍历
    	heap1.traversal();
    	/*
    	String result=null;
    	while((result=heap1.delMax())!=null){
    		System.out.print(result+"->");
    	}
    	System.out.println("\n-----------------------------------------------------------------------");
    	*/
	}
}


6.测试结果
在这里插入图片描述

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值