堆和优先队列

优先队列

-普通队列:先进先出
-出队顺序和入队顺序无关,和优先级相关
-操作系统划分时间片执行任务采用的就是动态优先队列

优先队列的实现

-入队出队
普通数组O(1)O(n)
顺序数组O(n)O(1)
O(lgn)O(lgn)

-使用堆实现优先队列

对于总共N个请求
使用普通数组或者顺序数组,最差的情况:O(n^2)
使用堆:O(nlgn)

用数组存储二叉堆

这里写图片描述

最大堆

-代码实现

public class MaxHeap<E extends Comparable<? super E>> {

    private static final int DEFAULT_CAPACITY = 10;
    private int currentSize;
    private E[] array;
    private int capacity;

    // 构造函数
    public MaxHeap() {
        this(DEFAULT_CAPACITY);
    }

    public MaxHeap(int capacity) {
        currentSize = 0;
        // 数组内容从1开始,故+1
        array = (E[]) new Comparable[capacity + 1];
        this.capacity = capacity;
    }

    // 获取堆大小
    public int size() {
        return currentSize;
    }

    // 按最大堆方式插入元素
    public void insert(E x) {
        // 避免数组越界
        assert (currentSize + 1 <= capacity);
        array[currentSize + 1] = x;
        currentSize++;
        shiftUp(currentSize);
    }

    // 元素上移直到满足最大堆定义
    private void shiftUp(int k) {
        while (k > 1 && array[k / 2].compareTo(array[k]) < 0) {
            E temp;
            temp = array[k / 2];
            array[k / 2] = array[k];
            array[k] = temp;
            k /= 2;
        }
    }

    // 判断是否为空
    public boolean isEmpty() {
        return currentSize == 0;
    }

    // 重新构建最大堆,并返回根元素
    public E extractMax() {
        assert (currentSize > 0);
        E ret = array[1];
        // 将最后的元素放到堆顶
        E temp;
        temp = array[1];
        array[1] = array[currentSize];
        array[currentSize] = temp;
        currentSize--;
        shiftDown(1);

        return ret;
    }

    public E printElement(int i) {
        E ret = array[i + 1];
        return ret;
    }

    // 将堆顶元素下移到合适的位置
    private void shiftDown(int k) {
        while (k * 2 <= currentSize) {
            // 在此轮循环中,data[k]和data[j]交换位置
            int j = 2 * k;
            // 判断左右孩子大小
            if (j + 1 <= currentSize && array[j + 1].compareTo(array[j]) > 0)
                j += 1;
            if (array[k].compareTo(array[j]) >= 0)
                break;
            E temp;
            temp = array[k];
            array[k] = array[j];
            array[j] = temp;
            k = j;
        }
    }

    public static void main(String[] args) {
        MaxHeap<Integer> maxHeap = new MaxHeap<Integer>(100);
        // 随机添加元素
        System.out.println("=插入元素=");
        for (int i = 0; i < 15; i++) {
            int a = (int) (Math.random() * 100);
            maxHeap.insert(a);
            System.out.print(a + " ");
        }
        System.out.println("");
        System.out.println("=打印元素=");
        for (int i = 0; i < 15; i++)
            System.out.print(maxHeap.printElement(i) + " ");
        System.out.println("");
        while (!maxHeap.isEmpty()) {
            System.out.print(maxHeap.extractMax() + " ");
        }
        System.out.println("");
        System.out.println("元素个数" + maxHeap.size());
    }
}

-输出结果

=插入元素=
72 9 42 51 4 35 38 88 15 5 0 87 13 16 40
=打印元素=
88 72 87 51 5 42 40 9 15 4 0 35 13 16 38
88 87 72 51 42 40 38 35 16 15 13 9 5 4 0
元素个数0

堆排序

基础堆排序

-代码实现

// 堆排序算法1
    public <E extends Comparable<? super E>> void heapSort1(MaxHeap<E> maxHeap, E[] arr,int n) {
        // 将数据插入堆
        for (int i = 0; i < n; i++) 
            maxHeap.insert(arr[i]);
        // 倒序插入最大数据完成从小到大的排序
        for (int i = n-1; i >= 0; i--) {
            arr[i] = maxHeap.extractMax();
        }
        System.out.println("=打印元素=");
        for (int i = 0; i < 15; i++)
            System.out.print(arr[i] + " ");
    }

-输出结果

=插入元素=
20 57 81 86 28 21 57 51 12 92 50 84 46 14 91
=打印元素=
92 86 91 51 81 57 84 20 12 28 50 21 46 14 57
进行堆排序
=打印元素=
12 14 20 21 28 46 50 51 57 57 81 84 86 91 92

-算法复杂度

Nlog(N)

从建堆(heapify)角度优化排序

    // heapify
    public MaxHeap(E[] arr, int n) {
        array = (E[]) new Comparable[n + 1];
        this.capacity = n;
        for (int i = 0; i < n; i++)
            array[i + 1] = arr[i];
        currentSize = n;
        // 从第一个不是叶子节点的点开始进行下移操作,将数组整合成堆
        for (int i = currentSize / 2; i >= 1; i--)
            shiftDown(i);
    }
    // 堆排序算法2
    // 效率比第一种高,将N个元素逐一插到空堆中算法复杂度为O(nlogn) heapify建堆过程为O(n)
    public <E extends Comparable<? super E>> void heapSort2( E[] arr, int n) {
        MaxHeap<E> maxHeap = new MaxHeap<>(arr,n); 
        // 倒序插入最大数据完成从小到大的排序
        for (int i = n - 1; i >= 0; i--) {
            arr[i] = maxHeap.extractMax();
        }
        System.out.println("=打印元素=");
        for (int i = 0; i < n; i++)
            System.out.print(arr[i] + " ");
    }

效率比第一种高,主要差别在于两者建堆的方式不同。将N个元素逐一插到空堆中算法复杂度为O(nlogn) heapify建堆过程为O(n)

原地堆排序

-不需要开辟额外的空间

算法思想

-通过heapify构建最大堆
这里写图片描述

-由最大堆的性质可知数组第一个元素是最大的
这里写图片描述

-将最大的元素放到最后的位置,第二大的元素会被放到倒数第二的位置,以此类推
这里写图片描述

-当v和w换位置时,不在满足最大堆,需要进行相应的shitfdown操作重新构建最大堆
这里写图片描述

相应代码
    // 堆排序算法3
    public <E extends Comparable<? super E>> void heapSort3(E[] arr, int n) {
        // 算法1和2中的堆从1开始索引,算法3从0开始索引
        for (int i = (n - 1) / 2; i >= 0; i--)
            shiftDown(arr, n, i);
        for (int j = n - 1; j > 0; j--) {
            // 把当前堆中最大的数放到合适的位置中
            E temp;
            temp = arr[0];
            arr[0] = arr[j];
            arr[j] = temp;
            shiftDown(arr, j, 0);
        }
        System.out.println("=打印元素=");
        for (int i = 0; i < n; i++)
            System.out.print(arr[i] + " ");
    }

    private <E extends Comparable<? super E>> void shiftDown(E[] arr, int n, int k) {
        while (k * 2 + 1 < n) {
            // 在此轮循环中,arr[k]和arr[j]交换位置
            int j = 2 * k + 1;
            // 判断左右孩子大小
            if (j + 1 < n && arr[j + 1].compareTo(arr[j]) > 0)
                j += 1;
            if (arr[k].compareTo(arr[j]) >= 0)
                break;
            E temp;
            temp = arr[k];
            arr[k] = arr[j];
            arr[j] = temp;
            k = j;
        }
    }
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值