zoukankan      html  css  js  c++  java
  • 经典排序算法分析和代码-下篇

    这篇文档我们来讲两种非比较排序,计数排序,基数排序

    计数排序

    计数排序是一种非比较算法,其时间复杂度为O(N+K)

    举例说明

    先用一个例子来说明计数排序算法,比如需要排序的集合为{1, 2, 1, 0, 4, 5},在该集合中,最大的数值为5,那么通过遍历整个集合,

    可以得到这样的数组

       int counter[] = {1, 2, 1, 0, 1, 1}

                                  0, 1, 2, 3, 4, 5

    counter数组描述了被排序数组里有1个0, 2个1, 1个2, 0个3, 1个4和1个5,当这个数组形成时,排序也就结束了。

    代码设计

    1)根据集合中最大的数值K,来申请辅助空间counter数组

    2)遍历被排序集合,讲计数记录到counter数组中

    代码实现

    #include <stdio.h>
    #include <stdlib.h>
    #include <string.h>
    
    int data[] = {1, 2, 1, 0, 4, 5};
    
    // 计数排序参数列表
    // int d[] 为待排序数据列表
    // int n 为待排序数据个数
    // int min, max为待排序数据中最大和最小的数,通过其计算待排数据跨度K
    void sort_counter(int d[], int n, int k)
    {
        int i, j = 0;
        k++; // 实际申请空间比K大1
        // 申请辅助空间
        int* counter = malloc(sizeof(int)*k);
        memset(counter, 0, sizeof(int)*k);
    
        // 计数
        for(i=0; i<n; ++i)
        {
            ++counter[d[i]];
        }
    
        // 讲计数结果保存到待排数据空间
        for(i=0; i<k; ++i)
        {
            while(counter[i]-- > 0)
            {
                d[j++] = i;
            }
        }
    
        // 释放辅助空间
        free(counter);
    }
    
    int main(void)
    {
        sort_counter(data, 6, 5);
        int i;
        for(i=0; i<6; ++i)
        {
            printf("%d
    ", data[i]);
        }
        return 0;
    }




    特点

    计数排序的特单是时间复杂度,与其他的排序算法不同,它的时间复杂度为O(N+K),这个时间复杂度表明了当K相对比较大时,不适合使用,比如对集合{1, 0, 100}

    但是对于N远大于K的情况下,是相当适合的

    基数排序

    在数量大时,计数排序需要大量的辅助空间,并且时间复杂度有可能比较大,所以推出基数排序。

    举例说明

    假如有待排序数据 data[] = {312, 213, 545, 893};

    先排序个位数:排序结果为 312, 213, 893, 545

    再排序十位数:排序结果为 321, 213, 545, 893

    再排序百位数:排序结果为 213, 312, 545, 893

    完毕

    对位数的排序,可以使用计数排序,速度快而且稳定。

    代码设计

    1)获取待排序数据中的最大位数

    2)对位数进行循环,按位对待排序数据进行计数排序,并将其中间结果保存到临时空间

    3)将临时数据保存到待排序数据,继续步骤2)

    代码实现

    #include <stdio.h>
    
    // int data[] = {1, 100, 321, 121, 333, 586, 1100};
    
    // 该函数计算data中最大位数,本例子中,最大位数是1100,所以结果是4
    int maxbit(int data[],int n)
    {
        int d = 1; //保存最大的位数
        int p =10;
        for(int i = 0;i < n; ++i)
        {
            while(data[i] >= p)
            {
                p *= 10;
                ++d;
            }
        }
        return d;
    }
    
    // 基数排序
    void sort_radix(int data[],int n)
    {
        int d = maxbit(data, n);    // 计算位数
        int * tmp = new int[n];     // 中间变量,用来存储中间排序结果
        int * count = new int[10];  // 计数排序中的计数器
        int i,j,k;
        int radix = 1;
    
        // 根据最大位数进行循环,对没一位进行计数排序
        for(i = 1; i<= d;i++)
        {
            // 初始化计数器
            for(j = 0; j < 10; j++)
                count[j] = 0;
    
            // 对位数进行计数排序
            for(j = 0; j < n; j++)
            {
                k = (data[j]/radix)%10; // 注意这里进行取模
                count[k]++;             // 计数
            }
            for(j = 1; j < 10; j++)
                count[j] = count[j-1] + count[j];
    
            // 将排序中间结果保存到tmp
            for(j = n-1; j >= 0;j--)
            {
                k = (data[j]/radix)%10;
                tmp[count[k]-1] = data[j];
                count[k]--;
            }
    
            // 将中间结果保存到data
            for(j = 0;j < n;j++)
                data[j] = tmp[j];
    
            // 取模时的被除数,需要提高一位
            radix = radix*10;
        }
        delete [] tmp;
        delete [] count;
    }
    
    int main()
    {
        int data[] = {1, 100, 321, 121, 333, 586, 1100};
        sort_radix(data, 7);
        for(int i=0; i<7; i++)
        {
            printf("%d
    ", data[i]);
        }
        return 0;
    }


    特点

    基数排序比较适合对取值很大的数进行排序,也可用来对字符串进行排序。

    但基数排序的缺点是不呈现时空局部性,因为在按位对每个数进行排序的过程中,一个数的位置可能发生巨大的变化,所以不能充分利用现代机器缓存提供的优势。同时计数排序作为中间稳定排序的话,不具有原地排序的特点,当内存容量比较宝贵的时候,还是有待商榷。

  • 相关阅读:
    C#如何取硬件标志
    在C#中利用Excel做高级报表
    C#实现网段扫描
    用C#编写一个抓网页的应用程序
    C# 中操作API
    C#串口操作
    C#里的InputBox
    使用C#进行Word 2002和Excel 2002编程
    用C#快速往Excel写数据
    postgres 查看数据库大小
  • 原文地址:https://www.cnblogs.com/new0801/p/6177573.html
Copyright © 2011-2022 走看看