数据结构和算法分析 优先队列

也可以使用普通的数组来实现优先队列,当然push复杂度为O(1),pop复杂度为O(N)。

也可以使用二叉查找树来实现,如果使用平衡树,那么插入和查找的复杂度就是所使用的平衡树的复杂度。

一般使用堆来实现优先队列。

堆:

  • 堆是一棵完全二叉树(complete binary tree)。
  • 由于完全二叉树的规律性,它可以用一个数组来实现而不需要指针。排除数组中位置0,在数组中任一位置i上的元素,其左儿子在位置2i上,右儿子在左儿子后的单元(2i+1)上。它的父亲节点在位置i/2上。
  • 在一个堆中,对于每一个节点X,都小于它子节点的值。

堆的基本操作操作

插入操作:在堆的下一个空闲位置放入插入元素,然后将它不断上浮到合适的位置为止。时间复杂度:O(LogN)。

删除最小元:将堆顶的元素移除,然后将最后一个元素移动到堆顶,然后将堆顶元素不断下沉到合适的位置。时间复杂度:O(LogN)。

构建堆:将堆的元素的所有非叶子节点下沉到合适的位置(从最后一个非叶子结点开始,到根节点结束)。时间复杂度是O(N),而不是O(NlogN)。

代码:

  1. package com.zjf;
  2.  
  3. import java.util.Arrays;
  4. import java.util.List;
  5.  
  6. public class PriorityHeap<E extends Comparable<? super E>> {
  7.  
  8.    public static void main(String[] args) {
  9.       // TODO Auto-generated method stub
  10.       PriorityHeap<Integer> heap = new PriorityHeap<Integer>();
  11.       heap.push(5);
  12.       heap.push(3);
  13.       heap.push(8);
  14.       heap.push(1);
  15.       heap.push(7);
  16.       heap.push(6);
  17.       System.out.println(heap);
  18.       System.out.println(heap.pop());
  19.       System.out.println(heap);
  20.       Integer[] ia = {2,5,4,9,7,3,6,8};
  21.       PriorityHeap<Integer> heap1 = new PriorityHeap<Integer>(ia);
  22.       System.out.println(heap1);
  23.    }
  24.  
  25.    // 简单实现 就写死了 不再考虑扩展
  26.    private int currentSize = 0;
  27.    private Comparable[] arr = new Comparable[1024];
  28.  
  29.    public void push(E e) {
  30.       // 注意数组0下标的位置 不存储内容:为了满足n和2n+1的关系
  31.       // 插入到最后一个位置
  32.       arr[currentSize + 1] = e;
  33.       int i = currentSize + 1;
  34.       // 将刚才插入到最后一个位置的节点慢慢上浮到合适的位置
  35.       while (i > 1) {
  36.          if (arr[i].compareTo(arr[i / 2]) < 0) {
  37.             // 交换上浮
  38.             swap(i, i / 2);
  39.          }
  40.          i = i / 2;
  41.       }
  42.       // 操作成功后currentSize++
  43.       currentSize++;
  44.    }
  45.  
  46.    public PriorityHeap(E[] es) {
  47.       // 将传入数组的内容一字排开放入堆中
  48.       for (int i = 0; i < es.length; i++) {
  49.          arr[i + 1] = es[i];
  50.       }
  51.       currentSize = es.length;
  52.       // 构建堆
  53.       buildHeap();
  54.    }
  55.  
  56.    public PriorityHeap() {
  57.  
  58.    }
  59.  
  60.    // 构建堆:将乱序的数组 构建成满足堆序要求的堆结构
  61.    public void buildHeap() {
  62.       // 从currentSize的一半开始 往上 逐个下沉到合适的位置
  63.       //currentSize/2是最后一个有子节点的位置 再往后就是叶子结点了
  64.       for(int i = currentSize/2; i >=1;i--)
  65.       {
  66.          down(i);
  67.       }
  68.    }
  69.  
  70.    public E pop() {
  71.       if (currentSize == 0) {
  72.          return null;
  73.       }
  74.       E first = (E) arr[1];
  75.       // 第一个元素空了下来 将最后一个元素移到这个位置 然后下沉到合适的位置
  76.       arr[1] = arr[currentSize];
  77.       // 下沉第一个元素
  78.       down(1);
  79.       // 成功后currentSize--
  80.       currentSize--;
  81.       return first;
  82.    }
  83.  
  84.    // 下沉
  85.    private void down(int i) {
  86.       int child = i * 2;
  87.       // 没有子节点 跳出循环
  88.       if (child > currentSize) {
  89.          return;
  90.       }
  91.       // 对比有两个子节点 那么需要对比它们两个 找出最小的一个
  92.       if ((child + 1 <= currentSize)
  93.             && arr[child].compareTo(arr[child + 1]) > 0) {
  94.          child++;
  95.       }
  96.       if (arr[child].compareTo(arr[i]) < 0) {
  97.          swap(i, child);
  98.          down(child);
  99.       }
  100.    }
  101.  
  102.    // 交换
  103.    private void swap(int i, int j) {
  104.       Comparable temp = arr[i];
  105.       arr[i] = arr[j];
  106.       arr[j] = temp;
  107.  
  108.    }
  109.  
  110.    @Override
  111.    public String toString() {
  112.       List l = Arrays.asList(arr).subList(1, currentSize);
  113.       return Arrays.toString(l.toArray());
  114.    }
  115. }

打印:

[1, 3, 6, 5, 7]

1

[3, 5, 6, 8]

[2, 5, 3, 8, 7, 4, 6]

 

原始的二叉堆使用数组实现,是一个完全二叉树,其实现简单,但是在合并方面不尽人意,只能通过构建一个新的堆来实现两个堆的合并,时间复杂度为O(N)。而左式堆和斜堆是两种合并高效的堆,并且左式堆以及斜堆的insert以及deleteMin等操作都是以merge操作为基础的。merge时间复杂度可以达到O(logN)。

posted on 2017-07-17 00:31  张小贱1987  阅读(212)  评论(0编辑  收藏  举报

导航