Java数据结构:有序优先队列

在使用排序算法,除了使用快速排序解决问题,有时还可以用到优先队列,在《算法》这本书里,弄明白了优先队列,以及代码在此记录

优先队列定义

优先队列可以解决操作系统中cpu处理优先级进程的问题:
例如:小明在做菜在这是小明当前最高级别的进程,但是突然老妈喊他出来帮忙,处理老妈的进程就变为了比做菜更高一级的进程,那么这个时候就用到优先队列数据结构处理这样的一个变化。

优先队列来自于堆:
Java数据结构:有序优先队列_第1张图片

堆的特点

  1. 一棵完全二叉树(拥有完全二叉树的特点)
  2. 父节点总是大/小 于孩子节点(所以有大/小根堆)
  3. 根节点是最大/小值

堆有两个操作十分消耗时间分别是:

插入值:

插入的值根据完全二叉树性质,只能插入到第一个非叶子结点的孩子节点,插入完成后的节点可能不满足堆的要求(父节点值大于孩子节点)导致堆乱序,这个时将孩子节点值和父节点值进行交换,直到满足要求这个过程称为上浮(swim)

private void swim(int k ){
    //数组二叉树的性质,孩子结点下标/2就是父亲结点
    //孩子节点比父亲结点大就上浮
    while (k > 1 && compare(pq,k/2,k)){
        swap(pq,k/2,k);
        k = k/2;
     }
 }

删除最大/最小值

Java数据结构:有序优先队列_第2张图片

删除最大/小值,这个时候堆的根节点被删除,整个堆都会散架,为了维持堆的结构完整又兼顾删除这个值,将根的值和最后一个节点值进行调换,将堆的最后一个元素抹掉就行heap[size--] = null(这里null只要是抹掉就行,因为堆的size会-1)这个时候只有头结点值不符合堆性质,就需要下沉(sink)

 private void sink(int k ){
     //当前下标k的元素开始下沉
     while (2*k <= size){
         //孩子节点
         int j = 2*k;
         //左右孩子对比,尽量交换到大的节点
         if (j < size && compare(pq,j,j+1)) j++;
         //父节点不再小于孩子节点则退出
         if (! compare(pq,k,j)) break;
         swap(pq,j,k);
         k = j ;
     }
 }

一个优先队列(默认大根堆)的实现

public class MaxPQ {
    //数组构建堆
    private int[] pq ;
    //堆的大小
    private int size = 0;
    public  MaxPQ(int[] array){
        //初始化堆内存空间
        pq = new int[1000];
        //堆是从 1开始的
        pq[0] = array[0];
        //传入的数组进行堆构建
        for (int i = 1  ; i <= array.length ; i++){
            insert(array[i-1]);
        }


    }
    public boolean isEmpty(){
        return size == 0;
    }
    public int getSize(){
        return size;
    }
    public void insert(int val){
        //新元素必须为第一个非叶子结点的孩子
        //同时堆的大小增加
        pq[++size] = val;
        //元素开始上浮
        swim(size);
    }
    public int delMax(){
        int max = pq[1];
        swap(pq,1,size--);
        pq[size+1] = 0;
        sink(1);
//        for (int i = 1 ; i <= size ; i++){
//            System.out.print(pq[i]+" ");
//        }
        return max;
    }
    private void swap(int[] array, int a, int b) {
        int tem = array[a];
        array[a] = array[b];
        array[b] = tem;
    }
    /**
     * function annotation:
     * 从下往上的堆有序化 (heapify)
     */
    private void swim(int k ){
        //数组二叉树的性质,孩子结点下标/2就是父亲结点
        //孩子节点比父亲结点大就上浮
        while (k > 1 && pq[k/2] < pq[k]){
            swap(pq,k/2,k);
            k = k/2;
        }
    }
    /**
     * function annotation:
     * 从上往下的堆有序化
     */
    private void sink(int k ){
        //当前下标k的元素开始下沉
        while (2*k <= size){
            //孩子节点
            int j = 2*k;
            //左右孩子对比,尽量交换到大的节点
            if (j < size && pq[j]<pq[j+1]) j++;
            //父节点不再小于孩子节点则退出
            if (! (pq[k] < pq[j])) break;
            swap(pq,j,k);
            k = j ;
        }
    }
//测试
//    public static void main(String[] args) {
//        int[] nums = new int[]{34,6,12,990,22,45,5};
//        MaxPQ maxPQ = new MaxPQ(nums);
//        LinkedList stack = new LinkedList<>();
//        for (int i = 0 ; i < nums.length ; i++){
//            stack.push(maxPQ.delMax());
//        }
//        System.out.println(stack);
//    }
}

结尾:这个代码有个缺点就是没有完成书本《算法》里面提到的在插入和删除的时候控制堆的空间大小这里默认开启了pq = new int[1000]明显是很笨的做法浪费空间

你可能感兴趣的:(java,数据结构,算法)