美文网首页Android开发经验谈Android技术知识Android开发
数据结构算法 - 优先级队列和堆排序

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

作者: 红橙Darren | 来源:发表于2018-09-22 00:27 被阅读16次

    队列是一种特征为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;
        }
    
        E 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 个位置进行调整
        }
    }
    

    视频链接:https://pan.baidu.com/s/1qdCz_n01FkKLO0UWpNEN9A
    视频密码:rktg

    相关文章

      网友评论

      本文标题:数据结构算法 - 优先级队列和堆排序

      本文链接:https://www.haomeiwen.com/subject/mkndnftx.html