zoukankan      html  css  js  c++  java
  • 13.堆排序

     对应到c++容器是优先队列

    优先队列做法

     1 #include <bits/stdc++.h>
     2 using namespace std;
     3 int main() {
     4     int n, m;
     5     cin >> n >> m;
     6     priority_queue<int, vector<int>, greater<int> > q;
     7     //升序队列
     8     //priority_queue <int,vector<int>,greater<int> > q;
     9     //降序队列
    10     //priority_queue <int,vector<int>,less<int> >q;
    11     for (int i = 1; i <= n; i++) {
    12         int t;
    13         cin >> t;
    14         q.push(t);
    15     }
    16     while (m--) {
    17         cout << q.top() << " ";
    18         q.pop();
    19     }
    20     return 0;
    21 }

     手写堆做法:

    前三个功能是stl里的堆支持的基本操作

    后面两个操作是stl里的堆无法直接实现,也就是说没有一步到位的函数支持

    先讲一下堆的基本结构

    堆是一个完全二叉树, 除了最后一层,上面所有节点都是满的,最后一层的叶子节点是从左到右排列

    堆又有大根堆和小根堆

    以小根堆为例:每一个点都是小于等于左右儿子的,所以根节点就是整个树的最小值

    堆的存储:用一维数组存储,1号点是根节点

     堆有两个基本操作

    up():将一个节点往上移和down():将一个节点往下移

    上面提到的5个操作都可以用这两个函数实现

    down(x)函数 { //如果把某一个点变大了,需要把它往下移

      

       将最上面的1换为6之后,然后6应该咋样移动到它应该在的位置

      在x点,和x点的两个儿子(如果有的话),一共最多三个点中找到一个最小值min

      交换x和min的位置

      

      然后递归处理

       

      当交换到不能交换时,整个树更新为一个新的堆

    }

    up() { //如果把某一个点变小了,需要把它往上移

      

       如果把右下角的5改为2

      

       只需要把变的这个点和根节点进行比较

      

       然后递归处理

      

    }

    用se表示当前堆的大小

    用heap[]数组表示堆

     up操作和down操作的时间复杂度和树的高度成正比,都是log n

    在建堆操作时,我们是从下往上递归的,所以可以保证两个儿子都是堆

     1 #include <bits/stdc++.h>
     2 using namespace std;
     3 const int N = 100010;
     4 int h[N], se;
     5 void down(int u) {
     6     int t = u; //用t来表示这三个点的最小值
     7     if (2 * u <= se && h[2 * u] < h[t]) { //如果有左儿子,并且左儿子更小的话
     8         t = 2 * u;
     9     }
    10     if (2 * u + 1 <= se && h[2 * u + 1] < h[t]) { //如果有右儿子,并且右儿子更小的话
    11         t = 2 * u + 1;
    12     }
    13     if (u != t) { //如果根节点不是最小值
    14         swap(h[u], h[t]);
    15         down(t);
    16     }
    17 }
    18 void up(int u) {
    19     while (u / 2 > 0 && h[u / 2] > h[u]) { //只要有父节点,并且父节点比我大
    20         swap(h[u / 2], h[u]);
    21         u /= 2;
    22     }
    23 }
    24 int main() {
    25     int n, m;
    26     cin >> n >> m;
    27     for (int i = 1; i <= n; i++) {
    28         cin >> h[i];
    29     }
    30     se = n;
    31     for (int i = n / 2; i > 0; i--) { //O(n)的建堆方式
    32         //cout << i << endl;
    33         down(i);
    34     }
    35     while (m--) {
    36         cout << h[1] << " ";
    37         h[1] = h[se];
    38         se--;
    39         down(1);
    40     }
    41     return 0;
    42 }
  • 相关阅读:
    Java知识系统回顾整理01基础02面向对象03方法
    可插件化拓展改造器 slot-maven-plugin
    数据治理框架
    Java读写hdfs上的avro文件
    FTPClient的使用
    Java读写hdfs上的avro文件
    图片上传预览
    css hack 用法注意
    获取get请求后面的参数
    js全局变量污染
  • 原文地址:https://www.cnblogs.com/fx1998/p/13301538.html
Copyright © 2011-2022 走看看