排序算法——优先队列(基于堆得优先队列)

一:数据结构 堆的概念

1.堆

    堆数据结构是一种数组对象,它可以被视为一科完全二叉树结构。它的特点是父节点的值大于(小于)两个子节点的值(分别称为大顶堆和小顶堆)。它常用于管理算法执行过程中的信息,应用场景包括堆排序优先队列等。


堆有两个很基本的操作:增加、删除。先来说说增加元素,假设有下面这样一个堆:

这时候,有一个元素1要添加进来,这时候应该怎么办呢?第一步,将元素添加到堆的最后一个位置:

第二步,将新加入的元素与其父结点的值进行比较,若新结点的值比其父结点的值要小(就像这个例子一样),那么,交换两个结点的值,重复第二步,直到形成一个小顶堆:

这样,一个新的小顶堆诞生了!

然后就是从堆中删除一个元素了,假设在这个新的小顶堆中,我们打算删除值为1的那个结点:

第一步,将这个1删掉,假设其结点上当前没有值:

第二步,比较该删除结点(当前是最上面的那个)的两个子结点,看谁的值小,交换其中较小值和这个空结点的值(假设是null),然后重复这一步,直到该空值到最小面一行:

第三步,就是将这个空的结点从视线中移除了,这样,删除的过程就告一段落了(好吧,这个堆又回到解放前了)!


优先队列是由一个基于堆的完全二叉树表示,存储于数组pq[1..N]中,pq[0]没有使用。在insert()中,我们将N加一并把新元素添加到数组最后,然后用swim上浮恢复堆得秩序。在DelMax()中,我们从pq[1]中得到需要返回的元素,然后将pq[N]移动到pq[1],将N减一并用sink()恢复堆的秩序。


代码:

package suanfa;

public class MaxPQ {
	
	static int pq[]={0,13,9,8,7,6,5,4,3,2,0};
	static int N=pq.length-2;
	
	public static void insert(int m)  //插入元素
	{
	
		pq[++N]=m;  //放在最后
		swim(N);  //上浮操作
	}
	private static void swim(int n) {
		while(n>1&&less(n/2,n))
		{
			exch(n/2,n);
			n=n/2;
		}
		
	}
	private static void sink(int n) {
		while(2*n<=N) //循环条件1
		{
			int j=2*n;
			if(j<N&&less(j,j+1)) j++; //选择子节点较大的那个
			if(less(j,n)) break;//当子节点比父节点小,跳出循环
			exch(n,j);//交换父子节点
			n=j;
		}
		
	}
	private static void delMax()
	{
		int max=pq[1];
		exch(1, N--);//交换首尾节点
		pq[N+1]=0;
		sink(1);//下沉操作
		
	}
	static boolean less(int a,int b)
	{
		return pq[a]<pq[b];
	}
	static void exch(int i,int j){
		int temp=pq[i];
		pq[i]=pq[j];
		pq[j]=temp;
	}
	static int max(int i,int j){
		if(less(i,j))
			return pq[j];
		else return pq[i];
	}
	public static void main(String[] args) {
		
		
		//MaxPQ.insert(10);
		MaxPQ.delMax();
		for(int i=1;i<N+1;i++)
		{
			System.out.print(pq[i]+",");
		}
	}
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值