zoukankan      html  css  js  c++  java
  • 优先队列

        支持两种操作: 删除最大元素和插入元素, 这种数据结构叫做优先队列.

        当一棵二叉树的每个节点都大于等于它的两个子节点时, 它被成为堆有序.

        二叉堆是一组能够用堆有序的完全二叉树排序的元素, 并在数组中按照层级储存(不使用数组中的第一个位置).

    堆的算法

    用长度为N+1的pq[]来表示一个大小为N的堆, 为了方便,不使用pq[0], 堆元素存放在pq[1]至pq[N]中.

    在堆得有序化过程中, 有两种情况:

    1.由下至上的堆有序化(上浮)

        /*上浮*/
        private void swim(int k){
            while(k>1 && less(k/2, k)){
                exch(k/2,k);
                k = k/2;
            }
        }

     当 pq[k/2] 比 pq[k] 小时, less(k/2, k)返回真.

    2.由上至下的堆有序化(下沉)

        /*下沉*/
        private void sink(int k){
            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 class MaxPQ<Key extends Comparable<Key>> {
    
        private Key[] pq;
        private int N = 0;    
        
        private MaxPQ(int maxN){
            pq = (Key[]) new Comparable[maxN+1];   //pq[0] 不用
            
        }
        
        public boolean isEmpty(){
            return N==0;
        }
        
        public int size(){
            return N;
        }
        
        public void insert(Key v){
            pq[++N] = v;
            swim(N);
        }
        
        //删除最大元素
        public Key delMax(){
            Key max= pq[1];
            exch(1,N--);  //第一个元素和最后一个元素进行交换
            pq[N+1] = null;    //防止对象游离
            sink(1);
            return max;
        }
        
        public static void main(String[] args) {
            // TODO Auto-generated method stub
    
        }
    
    }
    View Code

    在insert()中, 我们把N+1并把新元素添加到最后面, 然后用swim()将堆有序化. 在delMax()中,我们从pq[1]得到需要返回的元素,然后交换pq[N]到pq[1], 将N-1并调用sink()使堆有序化, 同时还要将pq[N+1](因为之前减过1)设为null, 以便系统回收空间.  

    堆排序算法

        public static void HeapSort(int[] nums){
            int N = nums.length;
            /*构造最大堆*/
            for(int i=N/2; i>=1; i--){
                sink(nums, i, N);
            }
            while(N>1){
                exch(nums,1,N--);
                sink(nums,1,N);
            }
        }
        
        public static void sink(int[] nums,int k,int N){
            while(2*k<=N){
                int j = 2*k;  /*左孩子节点*/
                if(j<N && less(nums,j,j+1)) j++;
                if(!less(nums,k,j)) break;    /*k为最大节点*/
                exch(nums,j,k);    /*k与最大节点交换*/
                k = j;    
            }
        }
        
        private static boolean less(int[] nums, int i, int j) {
            return nums[i-1] < nums[j-1];
        }
    
        private static void exch(int[] nums, int i, int j) {
            int swap = nums[i-1];
            nums[i-1] = nums[j-1];
            nums[j-1] = swap;
        }    
        public static void main(String[] args) {
            // TODO Auto-generated method stub
            int[] nums= {8,6,4,5,7,1,3,2,9};
            HeapSort(nums);
            System.out.println("排序后");
            for(int i = 0; i<nums.length; i++){
                System.out.println(nums[i]);
            }
        }
    View Code

    堆排序可分为两个阶段

    1.将元素数组重新组织, 构建堆.

    我们只需要扫描前半部分数组即可, 因为数组的每个位置已经是一个子堆的根节点了.

    从右到左用sink()函数构造子堆. , 首先跳过大小为1的子堆, 最后在位置1上调用sink()方法,扫描结束 这时已经构建了一个最大堆.

    2.元素下沉排序.

    sink()方法将数组nums[1]到nums[n] 进行排序, for循环构造了堆, 然后while循环将nums[N]与nums[1]交换并维护堆的性质.

    如此重复,直到堆为空.  

    这里需要注意的是 less()方法和exch()方法索引都需要减一, 因为这里是对数组nums[0]-nums[N-1]进行排序, 而sink()方法是对nums[1]-nums[N]排序.

  • 相关阅读:
    oracle的常见问题与解决
    final、finally、finalize的区别
    java中读取程序运行时间
    数据库设计与SQL优化的建议
    Eclipse 快捷键操作和常用设置
    OO设计原则
    structs常用的Action
    java的深复制与浅复制
    python进制(十进制,八进制,十六进制)
    linux的shell基础
  • 原文地址:https://www.cnblogs.com/tanxing/p/5611410.html
Copyright © 2011-2022 走看看