priority_queue/LeetCode 23题

priority_queue

priority_queue的本质是一个堆,堆的概念就是一个存储数据的数组。

  • 堆可以看成是一个完全二叉树。
  • 其中,根节点最大的堆是大根堆,根节点最小的堆是小根堆。堆中某个节点的值总是不大于或者不小于其父节点的值。
  • 算法思想:交换。例如在一个已经是大根堆的堆中插入一个新的值,首先把其插入到堆一个子节点上,称为新的一个节点,如果这个值已经比其父节点要小了,那么就成了。如果这个值比父根节点大,就通过交换把它和父节点的位置调换,再次比较。直到找到一个比它大的父节点。那么同样的,弹出只需要把堆顶元素和最后一个元素交换,再把现在的新根节点通过交换下沉到合适位置就好了。然后数组的最后一个值pop出来就是它的最大值了。
  • 堆的一次一般操作的时间复杂度在O(1)~O(logn)之间,效率还是比较高的。

堆的实现可以参照:https://blog.csdn.net/xiajun07061225/article/details/8553808

使用时,一开始我是用了heap,使用如下函数:make_heap、push_heap、pop_heap、sort_heap、is_heap、is_heap_until。感受就是很混乱,代码修改起来也不是很方便,但是一套流程走下来可以对堆的实现原理有一个比较清楚的了解。
后面我就发现了priority_queue,这个封装的比较好,易于使用。

  1. 头文件:头文件是#include< queue >
  2. 模板申明:priority_queue,其中Type 为数据类型,Container为保存数据的容器,Functional 为元素比较方式。Container必须是用数组实现的容器,比如vector,deque等等,但不能用 list。STL里面默认用的是vector。
  3. 比较方法是可以重写的,默认是operator<,即降序输出。重写方法有很多:
********************************方法一
struct Node {
    int x,y;
    bool operator <(Node a) const  {    //必须加const
        return y < a.y;
    }
    bool operator >(Node a) const  {    //必须加const
        return y > a.y;
    }
};
//  priority_queue A;   //默认  大根堆
priority_queue, less>A;    //大根堆
priority_queue, greater > B;    //小根堆
********************************类似方式法一
struct Node {
    int x;
    int y;
    friend  bool operator<(const Node &a,const Node &b) {
        return  a.x < b.x;  //大顶堆
    }
    friend  bool operator>(const Node &a,const Node &b) {
        return  a.x > b.x;  //小顶堆
    }
};

priority_queue A;   //默认  大根堆
priority_queue, greater > B;    //小根堆
********************************方法二:
struct Node {
    int x;
    int y;
};

bool operator<(const Node &a, const Node &b) {
    return a.x(const Node &a, const Node &b) {
    return a.x>b.x;         //小顶堆
}

priority_queue,less > A;    //大根堆
priority_queue, greater > B;    //小根堆
//********************************方法三:
struct Node {
    int x;
    int y;
};

struct cmp {
    bool operator()(Node a,Node b) {
        return  a.x > b.x;  //小顶堆
    }
};

struct cmp1 {
    bool operator()(Node a,Node b) {
        return  a.x < b.x;  //大顶堆
    }
};

priority_queue,cmp1 > A;      //大根堆
priority_queue, cmp > B;    //小根堆
//当队列节点是指针时,用法不同
struct Node {
    int x;
    int y;
};
struct cmp {
    bool operator () (Node const *n1, Node const *n2) {
        return n1->xx;     //大顶推
    }
};
struct cmp1 {
    bool operator () (Node const *n1, Node const *n2) {
        return n1->x>n2->x;     //小顶推
    }
};

priority_queue, cmp > A;   //大根堆
priority_queue, cmp1 > B;  //小根堆

此部分参考https://blog.csdn.net/qq_32541007/article/details/71057282

具体实现:
使用LeetCode上第23题,合并K个排序链表为例。
priority_queue/LeetCode 23题_第1张图片
算法思路:

  1. 构建一个小根堆(重写一个比较函数,使堆按节点对应的val值从小到大排序),把k个链表的第一个节点都放进去。
  2. 构建一个新的链表res作为最终的输出链表。
  3. 把堆顶元素加入到res中,并且把堆顶pop出去。
  4. 如果被弹出的节点还有下一个节点(t->next!=NULL),就把它的下一个节点push到堆中。
  5. 回到第3步,直到堆最后为空才退出循环。

代码如下:

class Solution {
public:
    struct cmp {
	bool operator()(ListNode* a,ListNode* b) {
        return  a->val > b->val;  //小顶堆
    }
    };
    ListNode* mergeKLists(vector& lists) {
        if(lists.size() == 0){
            return nullptr;
        }
        if(lists.size() == 1){
            return lists[0];
        }
        priority_queue, cmp> B;
    	for(int i=0;inext=t;
            }
            if(t->next!=NULL){
                B.push(t->next);
            }
        }
        return res;
    }
};

你可能感兴趣的:(LeetCode刷题笔记)