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

    堆:

    #include <cstdio>
    #include <iostream>
    using namespace std;
    const int N = 100010;
    int n,m,h[N],s;
    void down(int u)
    {
        int t = u;
        if(u * 2 <= s && h[u*2] < h[t]) t = 2 * u;
        if(u * 2 + 1 <= s && h[u * 2 + 1] < h[t]) t = 2 * u + 1;
        if(u != t)
        {
            swap(h[u],h[t]);
            down(t);
        }
    }
    
    int main()
    {
        cin>>n>>m;
        for(int i = 1;i <= n;i++) cin>>h[i];
        s = n;
        for(int i = n/2;i;i--) down(i);
        
        while(m--)
        {
            cout<<h[1]<<" ";
            h[1] = h[s--];
            down(1);
        }
    }

    STL当中有优先队列:priority_queue。

    本题:输入一个长度为n的整数数列,从小到大输出前m小的数。是用小根堆,手写堆,根小于等于左右子结点,堆顶是最小值。

    存储:放在一个一维数组里面,根节点为1(x),左子结点为2(2 * x),右子结点为3(2 * x + 1). 1 2 3 4 5 6 7 8 9 ……

    down(x):当把值变大时,需要将他的位置移动到合适的地方,下移。

    up(x):当把值变小时,需要将他的位置移动到合适的地方,上移。

    插入一个数:heap[++size] = x, up(x);

    求出最小值:heap(1);

    删除最小数:因为存储方式是一维数组,删最后的方便,只需要size--即可,头中间不好删,所以先将最后的数替换到第1个结点,heap(1) = heap[size]; size--;down(1);

    删除任意一个元素: heap[k] = heap[size--]; down(k);

    修改任意元素:heap[k] = x; up(x) OR down(x);

    本题是默认先把数组里面所有的元素放在一维数组,然后对应到二叉堆里面,然后递归循环通过down操作来使得每个元素归位放在合适的位置。

    for(int i = n/2 ;i ; i--) down(i); 因为对于一个满二叉树来说,最后一层个数为n/2,根节点到倒数第二层的总数也为n/2,下移的层数为第一层到倒数第二层,个数为n/2。

    这里操作的次数小于n: S = n/4 + 2 * n/ 8 + 3 * n/16 + ……  2S = n/2 + 2 * n /4 + 3 * n / 8 …… 后面减去前面的S = n/2 + n/4 +n/8 + …… = n * 1/2 (1 - 1/(2^n)/(1-1/2) = n * (1 - 1 / 2 ^ n) < n; 所以总的down次数为小于O(n)。

     此题还可以用STL的有限队列来写:

    priority_queue<int , vector<int>, greater<int> > q;

    #include <iostream>
    #include <queue>
    using namespace std;
    const int N = 100010;
    int a[N];
    priority_queue<int, vector<int>, greater<int> >q;//小根堆,less是大根堆,可以认识是根以下的更小,根最大所以是大根堆,greater同理
    int main()
    {
        int n,m;
        cin>>n>>m;
        for(int i = 0;i<n;i++) {
            cin>>a[i];
            q.push(a[i]);
        }
        while(m--)
        {
            cout<<q.top()<<" ";
            q.pop();
        }
        return 0;
    }

     模拟堆:

    维护一个集合,初始时集合为空,支持如下几种操作:

    1. “I x”,插入一个数x;
    2. “PM”,输出当前集合中的最小值;
    3. “DM”,删除当前集合中的最小值(数据保证此时的最小值唯一);
    4. “D k”,删除第k个插入的数;
    5. “C k x”,修改第k个插入的数,将其变为x;
    #include <cstdio>
    #include <iostream>
    #include <string.h>
    
    using namespace std;
    const int N = 100010;
    int h[N],ph[N],hp[N],s;//ph[k]第k个插入的点,hp[k]堆上对应的ph[]数组。 ph[j] = k; hp[k] = j;
    void heap_swap(int a, int b)
    {
        swap(ph[hp[a]], ph[hp[b]]);
        swap(hp[a],hp[b]);
        swap(h[a],h[b]);
    }
    void down(int u)
    {
        int t = u;
        if(u * 2 <= s && h[u*2] < h[t]) t = 2 * u;
        if(u * 2 + 1 <= s && h[u * 2 + 1] < h[t]) t = 2 * u + 1;
        if(u != t)
        {
            heap_swap(u,t);
            down(t);
        }
    }
    
    void up(int u)
    {
        while(u / 2 && h[u / 2] > h[u])
        {
            heap_swap(u/2, u);
            u /= 2;
        }
    }
    
    int main()
    {
        int n, m = 0;
        cin>>n;
        while(n--)
        {
            char op[10];
            int k,x;
            scanf("%s",op);
            if(!strcmp(op,"I"))
            {
                cin>>x;
                s++;
                m++;
                ph[m] = s;
                hp[s] = m;
                h[s] = x;
                up(s);
            }
            else if(!strcmp(op,"PM"))
            {
                cout<<h[1]<<endl;
            }
            else if(!strcmp(op, "DM"))
            {
                heap_swap(1, s);
                s--;
                down(1);
            }
            else if(!strcmp(op, "D"))
            {
                cin>>k;
                k = ph[k];
                heap_swap(k, s);
                s--;
                down(k), up(k);
            }
            else{
                cin>>k>>x;
                k = ph[k];
                h[k] = x;
                down(k), up(k);
            }
        }
    }
  • 相关阅读:
    解决span中的内容不换行
    javascript中apply、call和bind的区别
    vuex及其属性应用
    55.动态加载Html
    58.圆角图片
    57.动态添加子View(Java/XML两种方式)
    56.Java与js交互
    59.仿微信的图片浏览器
    64.判断当前线程是否是主线程
    61.自定义Indicator
  • 原文地址:https://www.cnblogs.com/longxue1991/p/12692858.html
Copyright © 2011-2022 走看看