数据结构算法 - 优先级队列和堆排序

Posted 数据结构与算法

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了数据结构算法 - 优先级队列和堆排序相关的知识,希望对你有一定的参考价值。

Linux编程
点击右侧关注,免费入门到精通!


作者红橙Darren

https://www.jianshu.com/p/547dc64724c7


队列是一种特征为FIFO的数据结构,每次都是从队首弹出。优先队列与其不同的是,它不遵循先进先出的规则,而是根据队列中元素的优先权,优先权最大的先被取出。今天我们来读读源码层的优先级队列,到底是怎么实现的,在这之前我们不妨思考一下。如果要我们自己去实现,我们怎么去实现一个优先级队列?


存储结构分为数组和链表,假设我们用普通的数组去实现,我们要么入队列的时候找到其合适的位置,让优先级最高的排在数组的最前面。要么每次出队列的时候遍历整个数组,选出优先级最高的出队列。不管怎样时间复杂度都是 O(n) , 那么有没有一种更好的方法?答案都是采用二叉堆。


template<class E>
class PriorityQueue {

    int count;// 数组的大小,不够要扩容
    int index = 0;// 当前数据的角标位置
    E *array = NULL;// 数据数组

private:
    // 往上调整为大根堆
    void shiftUp(int index) {
        if (index > 1 && array[index] > array[index / 2]) {
            swap(array[index], array[index / 2]);
            shiftUp(index / 2);
        }
    }

    // 往下调整为大根堆
    void shiftDown(int k) {
        while (k * 2 <= index) {// 到底的情况
            // 最大指向左孩子
            int max = 2 * k;
            // 有右孩子且右孩子大于左孩子
            if (max + 1 <= index && array[max + 1] > array[max]) {
                max = max+1;
            }
            // 最大的是自己
            if(array[k] > array[max]){
                break;
            }
            // 交换,最大的网上冒
            swap(array[k],array[max]);
            k = max;
        }
    }

public:
    PriorityQueue(int count) {
        this->count = count;
        array = new E[count];
    }

    bool isEmpty() {
        return index == 0;
    }

    pop() {
        E max = array[1];
        // 最后两个
        array[1] = array[index];
        index--;
        shiftDown(1);
        return max;
    }

    void push(E e) {
        array[index + 1] = e;
        index++;
        // 不断的调整堆
        shiftUp(index);
    }
};


当我们不断往优先级队列中取数据是,会发现我们的数据是从大到小排列的,那是因为当数据插入和移除时,我们都会在内部维持一个最大堆,因此优先级队列就可以延伸到堆排序了。在没有了解过优先级队列之前,我们往往比较难以理解堆排序(我知道大家都会写),但当我们了解了优先级队列之后,就会发现堆排序原来如此。


/**
 * 调整大根堆
 */

void adjustHeap(int arr[], int k, int n) {
    while (k * 2 + 1 < n) {// 到底的情况
        // 最大指向左孩子
        int max = 2 * k + 1;
        // 有右孩子且右孩子大于左孩子
        if (max + 1 < n && arr[max + 1] > arr[max]) {
            max = max + 1;
        }
        // 最大的是自己
        if (arr[k] > arr[max]) {
            break;
        }
        // 交换,最大的网上冒
        swap(arr[k], arr[max]);
        k = max;
    }
}

void headSort(int arr[], int len) {
    // 1. 从最后一个不是叶子节点的节点,开始调整为大根堆
    for (int i = len / 2 - 1; i >= 0; --i) {
        adjustHeap(arr, i, len);
    }

    // 2. 第一个与最后一个进行交换,然后再调整为大根堆,但是不考虑最后一个了
    for (int i = len - 1; i > 0; i--) {
        swap(arr[0], arr[i]);
        adjustHeap(arr, 0, i);// 对第 0 个位置进行调整
    }
}


 推荐↓↓↓ 

以上是关于数据结构算法 - 优先级队列和堆排序的主要内容,如果未能解决你的问题,请参考以下文章

堆和堆的应用:堆排序和优先队列

数据结构与算法——优先队列和堆

漫画|理解堆和堆排序

PHP堆和堆排序

堆和堆排序

PHP面试:说下什么是堆和堆排序?