堆模板以及应用

 

1.堆数据结构

堆排序模板

void heapInsert(vector<int>& arr, int index) {
    while (arr[index] > arr[(index - 1) / 2]) {
        //这里实际上考虑了多种情况了
        swap(arr[index], arr[(index - 1) / 2]);
        index = (index - 1) / 2;
    }
}
/*
heapify的作用是向下调整
@size:代表最后堆中的最后一个元素索引
*/
void heapify(vector<int>& arr, int index, int size) {
    int left = index * 2 + 1;
    while(left < size) {
        //判断左右两边的数哪一个比较大
        int largest = left + 1 < size && arr[left + 1] > arr[left] ? left + 1 : left;
        largest = arr[largest] > arr[index] ? largest : index;
        if (largest == index) {
            break;
        }
        swap(arr[largest], arr[index]);
        index = largest;
        left = index * 2 + 1;
    }
}
void HeapSort(vector<int>& arr) {
    if (arr.size()<2) {
        return;
    }
    for (int i = 0; i < arr.size(); i++) {
        heapInsert(arr, i);//先建成大根堆,然后弹出一个节点
    }
    int size = arr.size();
    swap(arr[0],arr[--size]);//因为我们从序号0开始存放数据
    while (size > 0) {
        heapify(arr, 0, size);
        swap(arr[0], arr[--size]);
    }
}

上面的模板仅仅适用于直接给出一组数据的情况,不能处理当一个新的数据进来时候怎么操作,我们手动实现了一个类似大根堆的操作,当然这个模板存在一定的问题,但无大碍了....HeapSort的接口我们实际上没有删除元素

//注意堆排序的模板与优先级队列的实现还是有些区别的
//优先级队列需要考虑删除和增加元素,而堆排序元素的个数一开始就是确定的了
//插入元素,删除元素,取极值以及将某一整组数据配成一个heap
//我们的模板是从0位置开始存储数据的
class Heap {
public:
    Heap() { size = 0; }
    Heap(const vector<int>& arr) {
        m_arr = arr;
        size = arr.size();
        HeapSort(m_arr);
    }
    bool isEmpty() { return size==0; }
    void heapInsert(vector<int>& arr, int index);
    void heapify(vector<int>& arr, int index, int size);
    void HeapSort(vector<int>& arr);
    void insert(int element);
    int  delMax();
    int  top();
    int  length(){ return size; }
    void print();
private:
    int size ;
    vector<int> m_arr;
};
void Heap::print() {
    for (auto it : m_arr) {
        cout << it << " ";
    }
}
void Heap::insert(int element) {
    size++; //数据量+1
    m_arr.push_back(element);
    heapInsert(m_arr,size-1);//需要调整的节点

}
int  Heap::delMax() {
    swap(m_arr[0], m_arr[--size]);
    heapify(m_arr, 0, size);
    int res = m_arr[size];
    m_arr.pop_back();
    return res;
}
int  Heap::top() {
    if (!isEmpty()) {
        return m_arr[0];
    }
}
/*
@index : 需要调整位置的节点index
*/
void Heap::heapInsert(vector<int>& arr, int index) {
    while (arr[index] > arr[(index - 1) / 2]) {
        //这里实际上考虑了多种情况了
        swap(arr[index], arr[(index - 1) / 2]);
        index = (index - 1) / 2;
    }
}
/*
heapify的作用是向下调整
@index:需要调整位置的节点Index
@size:代表堆中的最后一个元素索引
*/
void Heap::heapify(vector<int>& arr, int index, int size) {
    int left = index * 2 + 1;
    while(left < size) {
        //判断左右两边的数哪一个比较大
        int largest = left + 1 < size && arr[left + 1] > arr[left] ? left + 1 : left;
        largest = arr[largest] > arr[index] ? largest : index;
        if (largest == index) {
            break;
        }
        swap(arr[largest], arr[index]);
        index = largest;
        left = index * 2 + 1;
    }
}
void Heap::HeapSort(vector<int>& arr) {
    if (arr.size()<2) {
        return;
    }
    for (int i = 0; i < arr.size(); i++) {
        heapInsert(arr, i);//先建成大根堆,然后弹出一个节点
    }
    int size = arr.size();
    swap(arr[0],arr[--size]);
    while (size > 0) {
        heapify(arr, 0, size);
        swap(arr[0], arr[--size]);
    }
}

 

STL中优先级队列中的定义 https://blog.csdn.net/weixin_36888577/article/details/79937886

priority_queue <class T,Sequence = vector<T>, class Compare = less<typename Sequemcr::value_type>>,默认是大根堆。可以看到优先队列完全以底层容器为依据,再加上heap的处理规则。

//升序队列
priority_queue <int,vector<int>,greater<int> > q;
//降序队列
priority_queue <int,vector<int>,less<int> >q;

//greater和less是std实现的两个仿函数(就是使一个类的使用看上去像一个函数。其实现就是类中实现一个operator(),这个类就有了类似函数的行为,就是一个仿函数类了)
  • top 访问队头元素
  • empty 队列是否为空
  • size 返回队列内元素个数
  • push 插入元素到队尾 (并排序)
  • emplace 原地构造一个元素并插入队列
  • pop 弹出队头元素
  • swap 交换内容
struct tmp2 //重写仿函数
{
    bool operator() (tmp1 a, tmp1 b) 
    {
        return a.x < b.x; //大顶堆
    }
};

2.堆的题目

最小的K个数用大根对,最大的K个数用小根堆

面试题40. 最小的k个数 https://leetcode-cn.com/problems/zui-xiao-de-kge-shu-lcof/

class Solution {
public:
    vector<int> getLeastNumbers(vector<int>& arr, int k) {
        //求最小的k个数应该建一个大根堆
        priority_queue<int> m_queue;
        for(int i = 0; i < arr.size(); i++){
            m_queue.push(arr[i]);
            if(m_queue.size() > k){
                m_queue.pop();
            }  
        }
        vector<int> res;
        while(!m_queue.empty()){
            int tmp = m_queue.top();
            res.push_back(tmp);
            m_queue.pop();
        }
        return res;

    }
};

347. 前 K 个高频元素 https://leetcode-cn.com/problems/top-k-frequent-elements/


struct tmp2 //重写仿函数
{
    bool operator() (pair<int,int>& p1,pair<int,int>& p2)
    {
       return p1.second > p2.second;
    }
};

class Solution {
public:  
    vector<int> topKFrequent(vector<int>& nums, int k) {
        map<int,int> Table;
        for(int i = 0 ; i < nums.size(); i++){
            Table[nums[i]]++;
        }

        priority_queue<pair<int,int>,vector<pair<int,int>>,tmp2> m_queue;
        for(auto item : Table){
            m_queue.push(item);
            if(m_queue.size() > k){
                m_queue.pop();
            }
        }
        vector<int> res;
        while(!m_queue.empty()){
            pair<int,int> tmp = m_queue.top();
            res.push_back(tmp.first);
            m_queue.pop();
        }
        return res;
    }
};

692. 前K个高频单词 https://leetcode-cn.com/problems/top-k-frequent-words/

class Solution {
public:
    int findKthLargest(vector<int>& nums, int k) {
            //实际上就是大小为k小根堆,然后弹出顶部就可以了
            priority_queue<int,vector<int>,greater<int>> m_queue;
            for(int i = 0 ; i < nums.size(); i++){
                m_queue.push(nums[i]);
                if(m_queue.size() > k){
                    m_queue.pop();
                }
            }
            return m_queue.top();
    }
};

合并K个链表 https://leetcode-cn.com/problems/merge-k-sorted-lists/

没想到答案与这个老哥如出一辙https://leetcode-cn.com/problems/merge-k-sorted-lists/

 struct cmp{
     bool operator()(const ListNode* p1, const ListNode* p2){
         return p1->val > p2->val;
     }
 };
class Solution {
public:
    ListNode* mergeKLists(vector<ListNode*>& lists) {
        if(lists.size() == 0) return nullptr;

        priority_queue<ListNode*,vector<ListNode*>,cmp> m_queue;
        for(int i = 0 ; i < lists.size(); i++){
            if(lists[i] == nullptr) continue; //非常关键
            m_queue.push(lists[i]);
        }
        ListNode* dummy = new ListNode(-1);
        ListNode* curNode = dummy;
        while(!m_queue.empty()){
            ListNode* nextNode =  m_queue.top();
            curNode->next = nextNode;
            curNode = nextNode;
            m_queue.pop();
            if(nextNode->next!=NULL){
                m_queue.push(nextNode->next);
            }
        }
        return dummy->next;
    }
};

 

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值