zoukankan      html  css  js  c++  java
  • 数据结构和算法分析 优先队列

    也可以使用普通的数组来实现优先队列,当然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)。

  • 相关阅读:
    数据结结构学习 赫夫曼树
    C++ 类中特殊的成员变量(常变量、引用、静态)的初始化方法
    Linux/Unix time时间戳的处理转换函数
    gcc中include文件的搜索路径
    数据结结构学习 2叉树
    C++ 虚函数表解析
    数据结结构学习 线性表
    C#实现MD5加密
    学习的艺术
    C# 3.0实现类本身的方法扩展
  • 原文地址:https://www.cnblogs.com/xiaolang8762400/p/7192531.html
Copyright © 2011-2022 走看看