堆排序模板

题目描述
在未排序的数组中找到第 k 个最大的元素。请注意,你需要找的是数组排序后的第 k 个最大的元素,而不是第 k 个不同的元素。

示例 1:
输入: [3,2,1,5,6,4] 和 k = 2
输出: 5
示例 2:
输入: [3,2,3,1,2,4,5,5,6] 和 k = 4
输出: 4
说明:你可以假设 k 总是有效的,且 1 ≤ k ≤ 数组的长度。

堆排序实现模板(大根堆)
注意:

  • 堆是完全二叉树,插入是插入到空的位置即操作叶子节点,然后push_up 即可负责将树中大的节点替换上去,构成一个堆结构,操作的是叶子节点;操作根节点,就要进行push_down操作,负责将子树中大的节点替换上去重新得到新的根节点。堆中基本的操作就是这两种。.
  • 堆排序中下标是从1开始的,且数组编号是按照顺序来的,使用一维数组存储。给定 u ,左儿子就是 u * 2 右儿子就是u*2+1
  • push_down() 传入的参数是 数组,数组大小以及当前要push的数下标u,t 表示比 u 节点大的下标,先比较左边的节点,然后比较右边的节点,如果 t!=u 说明存在比u大的节点,需要交换这两个节点,递归进行下去
  • push_up() 传入的参数是数组以及左右儿子下标,与其父节点相比,如果父节点比该节点小的话,需要交换这两个节点,u/2表示到达上一层,继续比较直到循环结束
  • removetop() 删除根节点,将最后一个元素覆盖掉根节点,然后做一遍push_down操作即可
  • heapsort 完整过程,首先需要建堆,将元素全部push_up产生一个堆,因为是从小到大排序,每次需要把最大的元素放到最后,由于改变的是堆顶元素,所以要push_down一遍

本题目是找最大的第k个元素,因此main函数里面多了一步输出。

class Solution {
public:
    void push_down(vector<int>& heap,int size,int u)
    {
        int t=u,left=u*2,right=u*2+1;
        if(left<=size&&heap[left]>heap[t]) t=left;
        if(right<=size&&heap[right]>heap[t]) t=right;
        if(t!=u) 
        {
            swap(heap[t],heap[u]);
            push_down(heap,size,t);
        } 
    }
    void push_up(vector<int>& heap,int u)
    {
        while(u/2&&heap[u/2]<heap[u])
        {
            swap(heap[u/2],heap[u]);
            u/=2;
        }
    }
 
    void heapsort(vector<int> &heap,int n)
    {
        for(int i=1;i<=n;i++) push_up(heap,i);
        int size=n;
        for(int i=1;i<=n;i++)
        {
            swap(heap[1],heap[size]);
            size--;
            push_down(heap,size,1);
        }
    }
    void removetop(vector<int> &heap,int &size)
    {
        heap[1]=heap[size];
        size--;
        push_down(heap,size,1);
    }
    int findKthLargest(vector<int>& nums, int k) {
        int n = nums.size();
        vector<int> q(n+1);
        for(int i=1;i<=n;i++) q[i]=nums[i-1];
        heapsort(q,n);
       // for(auto x:q) cout<<x<<" ";
        return q[n-k+1];

    }
};

其余排序算法

实现堆排序:
1)小根堆,只使用push_down操作,最后需要将排序的结果保存到另一个数组里,使用push_down建堆,从n/2开始建堆

class Solution {
public:
    void push_down(vector<int>& q,int u,int size)
    {
        int t=u,left=u*2,right=u*2+1;
        if(left<= size  && q[t]>q[left]) t=left;
        if(right<= size && q[t]>q[right]) t=right;
        if(t!=u)
        {
            swap(q[t],q[u]);
            push_down(q,t,size);
        }
    }
    vector<int> sortArray(vector<int>& nums) {
        int n=nums.size();
        vector<int> q(n+1);
        for(int i=1;i<=n;i++) q[i]=nums[i-1];
        for(int i=n/2;i;i--) push_down(q,i,n);
        vector<int> res;
        int heapsize=n;
        while(n--)
        {
            res.push_back(q[1]);
            q[1] = q[heapsize];
            heapsize--;
            push_down(q,1,heapsize);
        }
        return res;
    }
};
  1. 小根堆,使用push_up建堆,要将排序的结果保存到另一个数组里,使用push_down建堆,从n/2开始建堆,小根堆的两个操作的符号与大根堆的两个操作的符号相反。
class Solution {
public:
    void push_down(vector<int>& q,int u,int size)
    {
        int t=u,left=u*2,right=u*2+1;
        if(left<= size  && q[t]>q[left]) t=left;
        if(right<= size && q[t]>q[right]) t=right;
        if(t!=u)
        {
            swap(q[t],q[u]);
            push_down(q,t,size);
        }
    }
     
    void push_up(vector<int>& heap,int u)
    {
        while(u/2&&heap[u/2]>heap[u])
        {
            swap(heap[u/2],heap[u]);
            u/=2;
        }
    }
    vector<int> sortArray(vector<int>& nums) {
        int n=nums.size();
        vector<int> q(n+1);
        for(int i=1;i<=n;i++) q[i]=nums[i-1];
        for(int i=1;i<=n;i++) push_up(q,i);
        vector<int> res;
        int heapsize=n;
        while(n--)
        {
            res.push_back(q[1]);
            q[1] = q[heapsize];
            heapsize--;
            push_down(q,1,heapsize);
        }
        return res;
    }
};

3)大根堆,push_down建堆,由于是从大到小排序,因此交换第一个元素和最后一个元素,然后push_down根节点

class Solution {
public:

     void push_down(vector<int>& heap,int size,int u)
    {
        int t=u,left=u*2,right=u*2+1;
        if(left<=size&&heap[left]>heap[t]) t=left;
        if(right<=size&&heap[right]>heap[t]) t=right;
        if(t!=u) 
        {
            swap(heap[t],heap[u]);
            push_down(heap,size,t);
        } 
    }
    void heapsort(vector<int> &heap,int n)
    {
        for(int i=n/2;i;i--) push_down(heap,n,i);
        int size=n;
        for(int i=1;i<=n;i++)
        {
            swap(heap[1],heap[size]);
            size--;
            push_down(heap,size,1);
        }
    }
    vector<int> sortArray(vector<int>& nums) {
        int n = nums.size();
        vector<int> q(n+1);
        for(int i=1;i<=n;i++) q[i]=nums[i-1];
        heapsort(q,n);
        q.erase(q.begin());
        return q;
    }
};

4)大根堆,push_up建堆,由于是从大到小排序,因此交换第一个元素和最后一个元素,然后push_down根节点

class Solution {
public:

     void push_down(vector<int>& heap,int size,int u)
    {
        int t=u,left=u*2,right=u*2+1;
        if(left<=size&&heap[left]>heap[t]) t=left;
        if(right<=size&&heap[right]>heap[t]) t=right;
        if(t!=u) 
        {
            swap(heap[t],heap[u]);
            push_down(heap,size,t);
        } 
    }
    void push_up(vector<int>& heap,int u)
    {
        while(u/2&&heap[u/2]<heap[u])
        {
            swap(heap[u/2],heap[u]);
            u/=2;
        }
    }
 
    void heapsort(vector<int> &heap,int n)
    {
        for(int i=1;i<=n;i++) push_up(heap,i);
        int size=n;
        for(int i=1;i<=n;i++)
        {
            swap(heap[1],heap[size]);
            size--;
            push_down(heap,size,1);
        }
    }

    vector<int> sortArray(vector<int>& nums) {
        int n = nums.size();
        vector<int> q(n+1);
        for(int i=1;i<=n;i++) q[i]=nums[i-1];
        heapsort(q,n);
        q.erase(q.begin());
        return q;
    }
};

综上,建堆方式可以push_up也可以push_down,但是在堆排序时只能push_down,因为第一个元素要么是最大要么是最小,是确定的。
堆的五个操作:(小根堆)
1)插入一个数字 heap[++size]=x,push_up(x);
2) 求集合中的最小值 heap[1]
3)删除最小值 heap[1]=heap[size],size–;down(1);
4) 删除任意一个值 heap[k]=heap[size],size–;down(k);
5)修改任意一个元素 heap[k]=x,push_down(k),push_up(k);

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值