前言
为什么要是用优先队?优先队列又是什么?
许多应用程序都系要处理有序的元素,但不应定要求它们完全有序,或者不一定要一次就将它们排序。很多时候我们回收集一些元素,然后处处理当前键值最大的元素,然后再收集更多的元素,再狐狸当前键值最大的元素……举个生活中的例子吧,就像我们用的手机一样,手机里面有很多进程,但是有一个进程的优先级特别高,那就是来电显示(不然的话,放你在打游戏的时候也不会因为来电而退出,嘿嘿)。优先队列是局部有序的,它并不将所有的元素都排成成有序的。
基本函数
- Key delmax()用来删除队列中最大的元素
- void insert(Key value)用来插入新元素
- boolean isEmpty() 用来判断队列是否为空
- int getSize() 返回 队列中的元素个数
- Key getMax() 返回队列中的最大值元素
我们用二叉堆表示法来实现优先队列,首先来介绍一下什么是二叉堆
在一个二叉树里面,如果每个结点都大于等于它的两个子结点的时候,那么那它就是堆有序的;二叉堆是一组能够用堆有序的完全二叉树(若设二叉树的深度为h,除第 h 层外,其它各层 (1~h-1) 的结点数都达到最大个数,第 h 层所有的结点都连续集中在最左边,这就是完全二叉树。)排序的元素,并在数组中按照层级存储(为了表示方便,我们不使用数组中的第一个元素)。所以根节点的地方是队列中键值最大的元素。 
 
函数具体实现(采用java语言)
堆实现的比较和交换算法
private boolean less(int i,int j) {
        return pq[i] <pq[j];
    }
    private void exch(int i,int j) {
        int temp = pq[i];
        pq[i]=pq[j];
        pq[j]=temp;
    }由下至上的堆有序化—Swim(上浮)
private void swim(int k) { // 上浮   元素最大比较次数为logN+1次 (也就是二叉树为满二叉树的时候,再往里面插入元素的时候)
        while(k>1&&less(k/2,k)) {
            exch(k/2,k);
            k=k/2;
        }
    }由上至下的堆有序化—Sink(下沉)
private void sink(int k) { 
//下沉 一共循环logN次 元素比较次数为2*logN次
        while(2*k<=N) {
            int j=2*k;
            if(j<N && less(j,j+1)) {
                j++;
            }
            if(!less(k,j)) {
                break;
            }
            exch(k,j);
            k=j;
        }
    }插入函数和删除最大元素最大函数
public void insert(int elem) {
        pq[++N]=elem;
        swim(N);
    }
    public int delMax() {
        int max=pq[1];
        exch(1, N--);//交换根节点和最后一个节点,并删除交换后的最后一     个节点 也就是之前的根节点
        //pq[N+1] = (Integer) null ;//防止对象游离  基本类型元素不可用
        sink(1);;//恢复堆得有序性
        return max;
    }基于堆的优先队全部代码
package 优先队列1;
public class PriorityQueue {//堆顶元素最大
    private int[] pq;
    private int N = 0; //存储于pq[1...N]中,pq[0]没有使用
    private boolean less(int i,int j) {
        return pq[i] <pq[j];
    }
    private void exch(int i,int j) {
        int temp = pq[i];
        pq[i]=pq[j];
        pq[j]=temp;
    }
    public PriorityQueue(int length) {
        this.pq=new int[length+1];  //下标为0的元素不用  元素从下标为1的地方开始
    }
    private void swim(int k) { 
        // 上浮   元素最大比较次数为logN+1次 (也就是二叉树为满二叉树的时候,再往里面插入元素的时候)
        while(k>1&&less(k/2,k)) {
            exch(k/2,k);
            k=k/2;
        }
    }
    private void sink(int k) { 
        //下沉   一共循环logN次   元素比较次数为2*logN次
        while(2*k<=N) {
            int j=2*k;
            if(j<N && less(j,j+1)) {
                j++;
            }
            if(!less(k,j)) {
                break;
            }
            exch(k,j);
            k=j;
        }
    }
    public int getElemSize()
    {
        return N;
    }
    public boolean isEmpty() {
        return N == 0;
    }
    public void insert(int elem) {
        pq[++N]=elem;
        swim(N);
    }
    public int delMax() {
        int max=pq[1];
        exch(1, N--);//交换根节点和最后一个节点,并删除交换后的最后一个节点 也就是之前的根节点
        //pq[N+1] = (Integer) null ;//防止对象游离  基本类型元素不可用
        sink(1);;//恢复堆得有序性
        return max;
    }
    private void display() {
        for(int i=1;i<=N;++i)
            System.out.print(pq[i] + " ");
        System.out.println();
    }
    public static void main(String[] args) {
        // TODO Auto-generated method stub
        PriorityQueue PQ = new PriorityQueue(12);
        PQ.insert(12);
        PQ.insert(15);
        PQ.insert(2);
        PQ.insert(18);
        PQ.insert(7);
        PQ.insert(7);
        System.out.println("The count of elem is "+PQ.getElemSize());
        System.out.print("All elem are :");
        PQ.display();
        System.out.println("Now,the max elem in priorityQueue is "+PQ.delMax());
        System.out.println("Now,the max elem in priorityQueue is "+PQ.delMax());
        System.out.println("Now,the max elem in priorityQueue is "+PQ.delMax());
    }
}
运行结果如下:
算法分析
- sink()方法中,一共循环logN次 元素最大比较次数为2*logN次
- swim()方法中, 元素最大比较次数为logN+1次,也就是二叉树为满二叉树的时候,再往里面插入元素的时候。
- 算法的分析 用图表表示为: 
 
 其中,
- 第一行unordered array是没有排序的数组,插入和删除还有求最大元素的算法复杂度分别为1,n,n。
- 第二行ordered array是排好序的数组,插入和删除还有求最大元素的算法复杂度分别为n,1,1。
- 第三行binary heap是二叉堆,插入和删除还有求最大元素的算法复杂度分别为log n,2*log n,1。
- 第四行d-ary heap是d叉堆(也就是每个结点有d个子结点),插入和删除还有求最大元素的算法复杂度分别为logd n,d*logd n,1
- sweet spot: d = 4 意思就是说最好的情况是当d=4的时候,算法效率比较好。
改进版的堆排序请参考
 
                   
                   
                   
                   
                             本文介绍优先队列的基本概念及其应用场景,并详细讲解了基于二叉堆实现优先队列的方法,包括插入、删除最大元素等核心操作的具体实现。
本文介绍优先队列的基本概念及其应用场景,并详细讲解了基于二叉堆实现优先队列的方法,包括插入、删除最大元素等核心操作的具体实现。
           
       
           
                 
                 
                 
                 
                 
                
               
                 
                 
                 
                 
                
               
                 
                 扫一扫
扫一扫
                     
              
             
                   1175
					1175
					
 被折叠的  条评论
		 为什么被折叠?
被折叠的  条评论
		 为什么被折叠?
		 
		  到【灌水乐园】发言
到【灌水乐园】发言                                
		 
		 
    
   
    
   
             
            


 
            