zoukankan      html  css  js  c++  java
  • 算法导论5:基数排序和计数排序 2016.1.5

      今天的这个比较神奇,是一个线性复杂度的排序算法O(n),算法导论在这一部分先证明了比较排序的复杂度下界是nlgn,所以基数排序不是基于比较的排序。

      其实这种比较方法我们应该都接触过。假设输入的数都是三位以下的数(当然其他位数也可以,类比一下,这里就假设是三位数、两位数、一位数),那么只需要大致3n的复杂度就可以排好序。过程是这样:

      先设置辅助空间t[0..9][n]

      然后扫第一遍n个数,个位是几就放在t[几]那一行。然后扫一遍t数组,按顺序放回原数组中

      然后扫第二遍n个数,十位是几就放在t[几]那一行。然后扫一遍t数组,按顺序放回原数组中

      然后扫第三遍n个数,百位是几就放在t[几]那一行。然后扫一遍t数组,按顺序放回原数组中

     现在原数组已经是按顺序排好的了。其实就是最原始的比较方法,先比较个位,再比较十位,再比较百位。

    代码如下:(这里为了好理解先用冗长的代码,其实这里的代码还可以再简化,然后修改以后适用于任何位数)

    #include<stdio.h>
    #include<string.h>
    
    int t[10][20];
    int cou[10];
    
    void jishusort(int *a,int l,int r)
    {
        memset(cou,0,sizeof(cou));
        memset(t,0,sizeof(t));
        int i;
        for (i=l;i<=r;i++) {
            int k=a[i]%10;
            t[k][cou[k]]=a[i];
            cou[k]++;
        }
        int c=l;
        for (i=0;i<=9;i++) {
            int j;
            for (j=0;j<cou[i];j++) {
                a[c]=t[i][j];
                c++;
            }
        }
        memset(cou,0,sizeof(cou));
        memset(t,0,sizeof(t));
        for (i=l;i<=r;i++) {
            int k=a[i]/10%10;
            t[k][cou[k]]=a[i];
            cou[k]++;
        }
        c=l;
        for (i=0;i<=9;i++) {
            int j;
            for (j=0;j<cou[i];j++) {
                a[c]=t[i][j];
                c++;
            }
        }
        memset(cou,0,sizeof(cou));
        memset(t,0,sizeof(t));
        for (i=l;i<=r;i++) {
            int k=a[i]/100;
            t[k][cou[k]]=a[i];
            cou[k]++;
        }
        c=l;
        for (i=0;i<=9;i++) {
            int j;
            for (j=0;j<cou[i];j++) {
                a[c]=t[i][j];
                c++;
            }
        }        
    }
    
    int main()
    {
        int n;
        scanf("%d",&n);
        int i;
        int a[20]={};
        for (i=1;i<=n;i++) {
            scanf("%d",&a[i]);
        }
        jishusort(a,1,n);
        for (i=1;i<=n;i++) {
            printf("%d |",a[i]);
        }
        return 0;
    }

    在这之前,书中还讲了一个计数排序,也是一种线性复杂度的算法。大体思想是这样:如果输入的数一定在1..k之间,那么对于每一个输入的元素x,确定出小组x的元素个数。利用这一信息就可以直接把x放在输出数组的相应位置了。算法导论里的伪代码真的太厉害了,用了几个线性的操作就实现了上面的思想。

    下面是代码:(按照输入的数不超过100写的)

    #include<stdio.h>
    #include<string.h>
    
    int c[101];
    
    void ji4shusort(int *a,int *b,int k,int n)
    {
        memset(c,0,sizeof(c));
        int i;
        for (i=1;i<=n;i++) {
            c[a[i]]++;
        }
        for (i=1;i<=k;i++) {
            c[i]+=c[i-1];
        }
        for (i=1;i<=n;i++) {
            b[c[a[i]]]=a[i];
            c[a[i]]--;
        }
        for (i=1;i<=n;i++) a[i]=b[i];
    }
    
    int main()
    {
        int n;
        scanf("%d",&n);
        int i;
        int a[20]={},b[20]={};
        int max=0;
        for (i=1;i<=n;i++) {
            scanf("%d",&a[i]);
            if (a[i]>max) max=a[i];
        }
        ji4shusort(a,b,max,n);
        for (i=1;i<=n;i++) {
            printf("%d |",a[i]);
        }
        return 0;
    }

    可以注意到上面两个算法基本上只适用于排整数。
    然后书上又讲了桶排序,目测虽然思想和基数排序差不多,但好像略复杂一些,以后有机会再研究。部分习题也不好意思先略过了。

  • 相关阅读:
    大数据学习笔记之一:大数据初识
    从漏洞中总结编程规范(转发)+自我补充
    软件性能测试的基本概念和计算公式(转发)
    系统吞吐量、TPS(QPS)、用户并发量、性能测试概念和公式(转发)
    Linux学习记录(三):time 相关
    Linux报错第一弹: /bin/sh^M: bad interpreter: No such file or directory
    Linux学习记录(二)----if
    SVN 提交出错1
    java.lang.NoClassDefFoundError
    git 将文件取消版本控制
  • 原文地址:https://www.cnblogs.com/itlqs/p/5104074.html
Copyright © 2011-2022 走看看