zoukankan      html  css  js  c++  java
  • 算法总结——三大排序(快排,计数排序,归并)

    快排:

    适用条件:方便...只要数字不是很多

    复杂度:O(nlogn)  每一层n复杂度,共logn层

    原理:利用一个随机数与最后面一个数交换,那么这个随机数就到了最后一位,然后循环,如果前面的数大于最后一个数,那么把这个数放到前面去,经过一次排序之后,前面的数都是大于最后一个的,然后对1到k和k+1到n进行排序,一层一层地下去

    模板:

    #include<cstdio>
    #include<algorithm>
    #include<time.h>
    using namespace std;
    void Sort(int *a,int l,int r)
    {
    int k = 0;
    int len = l - r;
    if(len <= 1) return ;
    srand(time(NULL));
    int pos = rand()%len;
    swap(a[r-1],a[pos+l]);
    for(int i = l; i < r; i++){
          if(a[i] >a[r-1]){
               swap(a[i],a[l+k]);
              k++;
          }
    }
    Sort(a,l,l+k-1);
    Sort(a,l+k,r);
    }

    计数排序

    复杂度:O(n+k)

    适用条件:正数

    原理:计数排序的基本思想是对于给定的输入序列中的每一个元素x,确定该序列中值小于x的元素的个数。一旦有了这个信息,就可以将x直接存放到最终的输出序列的正确位置上。例如,如果输入序列中只有17个元素的值小于x的值,则x可以直接存放在输出序列的第18个位置上。当然,如果有多个元素具有相同的值时,我们不能将这些元素放在输出序列的同一个位置上,因此,上述方案还要作适当的修改(来自百度百科

    通俗来说,用a来记录所有的要排序的值,w来记录以该值为下标的值的个数,通过计数,w就变成小于这个数的下标的数有多少个,w[a[i]]也就是小于当前a[i]的数有多少个,也就是确定了位置,用一个数组p来记录这个位置下的这个值,然后小于这个数的其他数的个数就少了一个,那么位置全部确定了直接输出就行

    计数排序的一个特点就是要开这个数值一样多的结点,比如7000,那就要开7000个,显然如果数字少并且大的话很不合算,但是多的话计数排序比快排快了六倍。

    模板:

    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    using namespace std;
    const int maxn = 222222;
    int p[maxn],w[maxn],a[maxn];
    void sort(int *a,int n,int mx)
    {
        for(int i = 1; i <= mx; i++)
            w[i] = 0;
        for(int i = 1; i <= n; i++)
            w[a[i]]++;
        for(int i = 1; i <= mx; i++)
            w[i] += w[i-1];
        for(int i = n; i >= 1; i--){
            p[w[a[i]]] = a[i];
            w[a[i]]--;
        }
    }
    int main()
    {
        int n,mx = 0;
        while(~scanf("%d",&n)){
            for(int i = 1; i <= n; i++){
                scanf("%d",&a[i]);
              mx = max(mx,a[i]);
            }
            sort(a,n,mx);
            for(int i = 1; i < n; i ++)
                printf("%d ",p[i]);
            printf("%d
    ",p[n]);
        }
        return 0;
    }

    ps:orz,原来叫计数排序,不叫桶排,醉了~~~~~~

    归并排序(Merge_Sort):

    适用范围:可以用来求逆序数,在第二部分块比较上就有排序的功能,在这里记录就行,详情看代码注释处,如果数字多的话就使用,毕竟稳定,但所占内存也比较多

    复杂度:O(nlogn)  合并O(n) 分成每一小块O(logn)

    原理:用了分治思想,要使得所有串都排序好,那么把整块不断的分成小块,直到最后几个数,然后从下往上对于整个序列进行比较排序,用了递归(分治:把大问题分成每一个小问题来解决),也就是这个算法分成两个部分:1.对整个串进行分块 2.对分好块的进行比较排序进行合并

    模板:

    #include<cstdio>
    #include<cstring>
    using namespace std;
    const int MAX = 222222;
    int a[MAX],temp[MAX];
    int ans = 0;
    void mergesort(int *a,int first,int mid,int last,int *temp)
    {
        int i = first, j = mid + 1;
        int k = first ;
        while( i <= mid && j <= last){
            if(a[i] <= a[j])
            temp[k++] = a[i++];
            else {
           // ans += j - k; 逆序数求法,因为a都都是从小到大排好的,如果a[i]>a[j]说明a[i]后面的数都大于a[j]前面的数,那么逆序数就要增加j-k个
            temp[k++] = a[j++];
    
            }
        }
        while( i <= mid )
            temp[k++] = a[i++];
        while( j <= last)
            temp[k++] = a[j++];
        for(int i = first ; i <= last;i++)
            a[i] = temp[i];
    }
    void mergearray(int *a,int first,int last,int *temp)
    {
        if(first < last){
                int mid = (first + last) >> 1;
                mergearray(a,first,mid,temp);
                mergearray(a,mid+1,last,temp);
                mergesort(a,first,mid,last,temp);
        }
    }
    int main()
    {
        int n;
        scanf("%d",&n);
        for(int i = 1; i <= n ;i++)
        scanf("%d",&a[i]);
        mergearray(a,1,n,temp);
        for(int i = 1; i < n; i++)
            printf("%d ", a[i]);
           printf("%d
    ",a[n]);
           printf("%d
    ",ans);
        return 0;
    }

    总结:三大排序用的最多的还是快排和归并,毕竟归并可以用来求逆序数,快排方便,计数一般不用吧~~~

  • 相关阅读:
    [JSOI2010]解题报告+2010~2011小结
    有用的东西(emacs配置和bzoj数据下载网址)
    [JSOI2011]解题报告
    [JSOI2010]旅行题解
    [BOI2007]Mokia题解
    分块总结
    统计数字
    爬不出去的水井
    采药
    沙漠储油点
  • 原文地址:https://www.cnblogs.com/zero-begin/p/4354395.html
Copyright © 2011-2022 走看看