lyd读书笔记 0x05 排序(上)

好长,好复杂。。


排序算法

第一类 O(n2) O ( n 2 ) 算法:选择、插入、冒泡
第二类 O(nlogn) O ( n l o g n ) 算法:堆排、归并、快排
第三类玄学算法:计数、基数、桶排
然而我并没有仔细学过。。所以就先从最基础的地方开始。

  • 选择排序:每次从序列中选一个最小的放在最前面,重复执行。
  • 插入排序:假设前k个已经排好序,我们就可以找到新的数插进去。如果用二分查找仍然是 O(n2) O ( n 2 ) 的,因为找到之后移动数组是 O(n) O ( n ) 的。
  • 希尔排序:插入排序的一个变种。希尔排序的执行过程是这样的:
    对于一个序列,我们首先选取相隔k个的一组数。例如, n=10,k=5 n = 10 , k = 5 ,我们就选出来 [1,6],[2,7],[3,8],[4,9],[5,10] [ 1 , 6 ] , [ 2 , 7 ] , [ 3 , 8 ] , [ 4 , 9 ] , [ 5 , 10 ] 这些数
    然后对每一组元素分别进行插入排序,合并起来。
    下一次,我们就选取 k=2 k = 2 ,然后对 [1,3,5,7,9] [ 1 , 3 , 5 , 7 , 9 ] [2,4,6,8,10] [ 2 , 4 , 6 , 8 , 10 ] 进行插入排序再合并。以此类推,当最终 k=1 k = 1 的时候,进行的插入排序工作量会大大减少。我们将k称为增量,如果k像这样倍减其复杂度仍然是 O(n2) O ( n 2 )
    事实上,增量的选取对希尔排序的复杂度有着重要影响。一种常见的选取是Hibbard增量, an=2n1 a n = 2 n − 1 ,其时间复杂度是 O(nn) O ( n n ) 的。
  • 冒泡排序:重复访问数组,遇到相反元素就交换直到未有能交换者。
  • 计数排序:值域内的排序,开一个数组维护某个值的数量,然后扫一遍数组即可,复杂度 O(n+m) O ( n + m ) ,其中m是值域。
  • 基数排序:类似建一张hash表。我们以个位为基准放桶里,然后对每个桶取出来元素以十位为单位放到桶里。。。这样递归下去即可。分成两种,一种是MSD,一种是LSD。LSD的复杂度是 O(d(n+r)) O ( d ( n + r ) ) ,d为位数,r为基数。
  • 桶排序:假定将值域为 m m ,将数据分布在 k k 个桶中,然后对桶进行排序,如果选择插入排序复杂度是 Θ(n+n2k) Θ ( n + n 2 k ) ,前提是数据均匀随机分布。当 k=n k = n 时复杂度为 O(n) O ( n ) ,k增大会使得算法效率发生显著改变,当 k=n k = n 时退化为计数排序。
    事实上,如果我们进行一些总结,可以发现计数排序是桶排序对k进行选择的一种情况,而如果对桶中的数据递归调用桶排序过程,那么这个排序就是基数排序。
  • 二叉排序树排序:插到二叉排序树即可。平均 O(nlogn) O ( n l o g n ) ,但可能退化到 O(n2) O ( n 2 ) 。也可以用替罪羊树、treap等平衡树使之稳定到 O(nlogn) O ( n l o g n ) ,不过会增加时间开销。
  • 堆排序:加入一个堆中,然后不断删除元素并维护堆的性质,复杂度 O(nlogn) O ( n l o g n )
    推荐:https://www.cnblogs.com/chenweichu/articles/5710567.html
    http://www.cnblogs.com/chenweichu/articles/5710635.html
  • 分治排序:个人认为最优雅的排序算法,没有之一。对数列进行分治,然后对子数列排序,最后再合并。复杂度 O(nlogn) O ( n l o g n ) ,实现参见之后的逆序对。
  • 快速排序:选取一个数,然后将比它大的放在前面,否则放在后面,对此过程进行递归处理即可。选取的数可以随机一下。

离散化

这里给一种比较神奇的黑科技。。

for(int i = 1; i <= n; ++i) b[i]=a[i];
sort(b+1,b+n+1);
int un=unique(b+1,b+n+1)-b-1;
for(int i=1;i<=n;++i) a[i]=lower_bound(b+1,b+un+1,a[i])-b;

cf670C
懒所以开了个map,发现用map离散化瞎搞一搞就好了的样子。。

#include 
#include 
#include 
using namespace std;

#define N 200003

int n, t, cnt;
int aud[N];
int ansy, anss, arr;
struct node {
    int voice, sub; 
}movie[N];
map<int, int> m;

int main() {
    ios::sync_with_stdio(0);
    cin.tie(0); cout.tie(0);
    cin>>n;
    for(int i = 1; i <= n; ++i) cin>>aud[i];
    cin>>t;
    for(int i = 1; i <= t; ++i) cin>>movie[i].voice;
    for(int i = 1; i <= t; ++i) cin>>movie[i].sub;
    for(int i = 1; i <= n; ++i) 
        if(!m.count(aud[i]))
            m.insert(make_pair(aud[i], 1));
        else ++m[aud[i]];
    for(int i = 1; i <= t; ++i) {
        if(!m.count(movie[i].voice)) { 
            if(ansy == 0) 
                ansy = 0, 
                anss = (m.count(movie[i].sub) ? m[movie[i].sub] : 0), arr = i;
            }
        else {
            if(m[movie[i].voice] > ansy) 
                ansy = m[movie[i].voice], 
                anss = (m.count(movie[i].sub) ? m[movie[i].sub] : 0), 
                arr = i;
            if(m[movie[i].voice] == ansy && m.count(movie[i].sub) && m[movie[i].sub] > anss) 
                anss = m[movie[i].sub], arr = i;             
        } 
    }
    cout<

是不是非常sabi。。用时24秒。。
然后就看了一下楼下大佬的,发觉有这样一种操作:如果用upper_bound减去lower_bound就可以得出值了..好有道理诶


参考资料

https://baike.baidu.com/item/%E5%B8%8C%E5%B0%94%E6%8E%92%E5%BA%8F/3229428?fr=aladdin
https://www.cnblogs.com/chengxiao/p/6104371.html
http://blog.csdn.net/foliciatarier/article/details/53891144
https://www.cnblogs.com/dwj411024/p/5978821.html
http://blog.csdn.net/cauchyweierstrass/article/details/49919559
https://www.cnblogs.com/jingmoxukong/p/4311237.html

你可能感兴趣的:(排序,算法,读书笔记,离散化,读书笔记,基础算法)