zoukankan      html  css  js  c++  java
  • 算法入门(一)排序之桶排序

    问题引入

    当我们需要对一组数据(无序)进行排序时,假设期末考试完了,老师要按照分数对大家的名次进行排序,这里假设五个同学分别考了 5分、3分、5分、2分、8分 (满分十分)。当然,我们一下子就看出了其中的奥妙,但是我们用程序该怎么写呢?

    思路引导

    我们可以创建一个大小为11的数组(因为这里统计的是0到10之间的数字出现次数),现在我们有11个变量,即从a[0]~a[10],刚开始我们将数组中所有的变量a[0]~a[10]的初始值设定为0(即这些分数没有人得过)。即a[0] = 0; 代表没人得过0分,a[1] = 0; 代表没人得过1分。

    接下来我们开始处理每一个人的分数,若该分数出现一次,其对应的数组下标的值加一,即第一个同学的分数为5分,代表分数5出现一次,则相对应的a[5]++; 即现在a[5] = 1。

    以此类推:第二个同学的分数为3分,此时3分出现一次,其对应的数组下标的值加一,则对应的a[3]++; 即a[3] = 1。

    然后我们分别拿到2分,5分,8分(第三个同学的成绩也是5分,则a[5]原来值为1的基础上再加一,a[5]++; a[5] = 2)

    一路分析下来,很明确,a[0]~a[10]中的数值就是0~10中每个分数出现的次数,接下载,我们只需要根据出现过分数的次数打印数组的下标(该分数)即可,出现几次就打印几次(比如5分出现两次,a[5] = 2,则将下标5打印两次)。

    代码实现

    #include "stdio.h"
    int main()
    {
        //创建一个长度为11的数组,用来判断0-10数字出现的次数
        int arr[11], i, j, n;
        //将数组内所有下标值初始化为0,代表此数字出现0次
        for (i = 0; i <= 10; i++) {
            arr[i] = 0;
        }
        //循环读入五个0-10内的整数
        for (i = 0; i < 5; i++) {
            //将每个数读到变量n中
            scanf("%d", &n);
            //如果出现该数字,则对应的数组角标值加一
            arr[n]++;
        }
        //第一层循环依次判断arr[0]-arr[10]中的值
        for (i = 0; i <= 10; i++) {
            //第二层循环判断该数字出现的次数,有几次就打印几次
            for (j = 1; j <= arr[i]; j++) {
                printf("%d", i);
            }
        }
    }

    运行结果:

    要想从大到小排序,将for (i = 0; i <= 10; i++)改为for (i = 10; i >= 0;  i--)即可。

    解析

    这个算法就好比有 11 个桶,编号从 0~10。每出现一个数,就在对应编号的桶中放一个 小旗子,最后只要数数每个桶中有几个小旗子就 OK 了。例如 2 号桶中有 1 个小旗子,表示 2 出现了一次;3 号桶中有 1 个小旗子,表示 3 出现了一次;5 号桶中有 2 个小旗子,表示 5 出现了两次;8 号桶中有 1 个小旗子,表示 8 出现了一次。

    当然,我们可以想一下,这个算法是十分浪分空间的,当我们要统计要排序数的范围是 0~2100000000 之间,那你则需要申请 2100000001 个变量,也就是说要写 成 int a[2100000001]。因为我们需要用 2100000001 个“桶”来存储 0~2100000000 之间每一 个数出现的次数。即便只给你 5 个数进行排序(例如这 5 个数是 1、1912345678、2100000000、 18000000 和 912345678),你也仍然需要 2100000001 个“桶”,这真是太浪费空间了!还有, 如果现在需要排序的不再是整数而是一些小数,比如将 5.56789、2.12、1.1、3.123、4.1234 这五个数进行从小到大排序,这就显得无法实现了。

    显然,简化版桶排序算法,其本质上还不能算是一个真正意义上的排序算法,其有很大的局限性,作为排序入门了解一下就可以了。

    总结

    简化版桶排序,用数组角标值从0自增的方式记录该角标(即输入的数字)出现的次数,然后遍历数组根据对应角标值的大小确认打印该角标的次数(即数字出现的次数)。

    算法新手上车,请多指教!

  • 相关阅读:
    C#学习之Enum
    Ten MustHave Tools Every Developer Should Download Now
    C#学习之Random
    C#学习之Exception
    WCF Data Contract之KnownType
    ESQL应该注意的地方
    Windows 安全认证是如何进行的?
    十个必备的.NET开发小工具
    c#中判断一个process是32bit还是64bit
    怎么用python和javascript把多张png拼成一个gif
  • 原文地址:https://www.cnblogs.com/itjiangpo/p/14181233.html
Copyright © 2011-2022 走看看