最小索引优先队列(利用堆来实现)

本文介绍了如何利用堆数据结构设计并实现一个最小索引优先队列,包括API设计、代码实现和测试过程,展示了如何通过索引来优先获取最小值。
摘要由CSDN通过智能技术生成

1.知识储备:
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
2.API设计:
在这里插入图片描述
3.代码实现:

package PriorityQueue;

public class IndexMinPriorityQueue<T extends Comparable<T>> {
    //用来存储元素的数组
	private T[] items;
	//保存每个元素在数组items中的索引,pq数组需要堆有序
	private int[] pq;
	//保存qp的逆序,pq的值作为索引,pq的索引作为值
	private int[] qp;
	//记录堆中元素个数
	private int N;
	
	public IndexMinPriorityQueue(int capacity) {
		// TODO Auto-generated constructor stub
		this.items=(T[])new Comparable[capacity+1];
		this.pq=new int[capacity+1];
		this.qp=new int[capacity+1];
		this.N=0;
		//默认情况下,队列中没有存储任何元素,让qp中的元素都为-1
		for(int i=0;i<qp.length;i++){
			qp[i]=-1;
		}
	}
	
	//判断堆中索引i处的元素是否小于索引j处的元素
	private boolean less(int i,int j){
		return items[pq[i]].compareTo(items[pq[j]])<0;
	}
	
	//交换i和j索引处的值
	private void exch(int i,int j){
		//交换pq中的数据
	    int temp=pq[i];
	    pq[i]=pq[j];
	    pq[j]=temp;
	    //更新qp中的数据
	    qp[pq[i]]=i;
	    qp[pq[j]]=j;
	}
	
	//删除队列中最小的元素,并返回该元素关联的索引
	public int delMin(){
		//获取最小元素关联的索引
		int minIndex=pq[1];
		//交换pq中索引1处和最大索引处的内容
		 exch(1,N);
		//删除qp中对应的内容
		qp[pq[N]]=-1;
		//删除pq中最大索引处的内容
		pq[N]=-1;
		//删除items中对应的内容
		items[minIndex]=null;
		//元素个数-1
		N--;
		//对堆进行下沉调整
		sink(1);
		return minIndex;
	}
	
	//往队列中插入元素,并关联索引
	public void insert(int i,T t){
		//判断i是否已经被关联,如果已经被关联则不让插入
		if(contains(i)){
			return;
		}
		//元素个数+1
		N++;
		//把数据存储到items对应的i位置处
		items[i]=t;
		//把i存储到pq中
		pq[N]=i;
		//通过qp来记录pq中的i
		qp[i]=N;
		//通过堆上浮来完成堆的调整
		swim(N);
	}
	
	//上浮算法,使得索引k处的元素在队列中处于正确位置
	private void swim(int k){
		while(k>1){
			if(less(k,k/2)){
				exch(k,k/2);
			}
			k=k/2;
		}
	}
	
	//下沉算法,使得索引k处的元素在队列中处于正确位置
	private void sink(int k){
		while(k*2<=N){
			int min;
			if(2*k+1<=N){
				 if(less(2*k,2*k+1)){
					 min=2*k;
				 }else{
					 min=2*k+1;
				 }
			}
			else{
				min=2*k;
			}
			if(less(k,min)){
				break;
			}
			exch(k,min);
			k=min;
		}
	}
	
	//获取队列中元素个数
	public int size(){
		return N;
	}
	
	//判断队列是否为空
	public boolean isEmpty(){
		return N==0;
	}
	
	//判断k对应的元素是否存在
	public boolean contains(int k){
		return qp[k]!=-1;
	}
	
	//把与索引i关联的元素修改为t
	public void changeItem(int i,T t){
		//修改items数组中i位置的元素t
		items[i]=t;
		//找到i在pq中出现的位置
		int k=qp[i];
		//堆调整
		sink(k); 
		swim(k);
		
	}
	
	//最小元素的关联索引
	public int minIndex(){
		return pq[1];
	}
	
	//删除索引i关联的元素
	public void delete(int i){
		//找到i在pq中的索引k
		int k=qp[i];
		//交换pq中索引k和N处的值
		exch(k,N);
		//删除qp中的内容
		 qp[pq[N]]=-1;
		//删除pq中的内容
		pq[N]=-1;
		//删除items中的内容
		items[k]=null;
		//元素的数量+1
		N--; 
		//堆调整,由于无法确定元素大小
		//先上浮
		swim(k);
		//在下沉
		sink(k);
	}
}

4.测试类:

package PriorityQueue;

public class IndexMinPriorityQueueTest {
     public static void main(String[] args) {
		//创建索引最小优先队列对象
    	 IndexMinPriorityQueue<String> queue =new IndexMinPriorityQueue<String>(10);
    	 //往队列中添加元素
    	 queue.insert(0, "a");
    	 queue.insert(1, "c");
    	 queue.insert(2, "f");
    	 //测试修改
    	 queue.changeItem(2, "b");
    	 //测试删除
    	 while(!queue.isEmpty()){
    		 int index=queue.delMin();
    		 System.out.print(index+" ");
    	 }
	}
} 

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

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值