• 非比较排序算法之计数排序及其实现


      计数排序是3大非比较排序(计数、基数及桶排序)之一,其基本原理是利用额外的存储空间(计数数组)对每个元素进行计数并将之存储到新的数组中(牺牲空间换时间)。此处的关键是计数数组的下标是原数据的元素值,即利用原数据的关键之进行索引(类似于hash表的索引)。其时间复杂度为Θ(n+k),即Θ(n)。注意,此处的计数排序时稳定排序算法(这是为什么step3从后往前扫描的原因)。

         主要有3个步骤:

        step1:记录待排序集合A中的每一个元素i具有的个数,存放到计数数组C[i]中

        step2:在C的相应位置处确定不比该位置大的数据个数

        step3:从大到小依次扫描原数据,将其存储到其应该存储的位置处

         实现的C程序如下:参考了http://www.cppblog.com/shongbee2/archive/2009/04/24/80991.html

    #include <stdio.h>
    #include <stdlib.h>
    
    //计数排序
    int CountSort(int* pData, int nLen)
    {
        int* pCount = NULL;            //保存记数数据的指针
        pCount = (int*)malloc(sizeof(int) * nLen);    //申请空间
        int* pSort = NULL;            //保存排序结果的指针
        pSort = (int*)malloc(sizeof(int) * nLen);    //申请空间
        
        //step1:记录待排序集合A中的每一个元素i具有的个数,存放到C[i]中
        for (int i = 0; i < nLen; ++i)//初始化记数为0
            pCount[i] = 0;
        for (int i = 0; i < nLen; ++i)//记录排序记数,在排序的值相应记数加1
            ++pCount[pData[i]];        
    
        //step2:确定不比该位置大的数据个数
        for (int i = 1; i < nLen; ++i)
            pCount[i] += pCount[i - 1];    //不比他大的数据个数为他的个数加上前一个的记数。
    
        //step3:从大到小依次扫描原数据,将其存储到其应该存储的位置处
        for (int i = 0; i < nLen; ++i)
        {
            //把数据放在指定位置,因为pCount[pData[i]]的值就是不比他大数据的个数
            //为什么要先减一,因为pCount[pData[i]]保存的是不比他大数据的个数中包括了
            //他自己,此处的下标是从零开始的!所以要先减一。
            --pCount[pData[i]];    //因为有相同数据的可能,所以要把该位置数据个数减一
            pSort[pCount[pData[i]]] = pData[i];        
        }
    
        //排序结束,复制到原来数组中
        for (int i = 0; i < nLen; ++i)
            pData[i] = pSort[i];
    
        //最后要注意释放申请的空间
        free(pCount);
        free(pSort);
    
        return 1;
    }
    
    int main()
    {
        int nData[10] = {8,6,3,6,5,8,3,5,1,0};
        CountSort(nData, 10);
        for (int i = 0; i < 10; ++i)
        {
            printf("%d ", nData[i]);
        }
        printf("\n");
    
        system("pause");
        return 0;
    }

      实现的C++程序如下(参考《算法导论》):

    #include <iostream>
    #include <vector>
    using namespace std;
    
    
    void counting_sort(const vector<int>& A, vector<int>& B, int k)
    {
        //注意:此处A,B是从1开始存储元素的,如果从0开始的话,则要step3处应先-1
        int i=0, j=0;
        vector<int> C(k+1,0);
        //step1:记录待排序集合A中的每一个元素i具有的个数,存放到C[i]中
        //for (i=0; i<=k; ++i) //初始化
        //    C[i] = 0;
        for (j=1; j<A.size(); ++j) //C存储A中每个元素出现的个数,用A的关键字索引C
            C[A[j]] +=1;
        
        //step2:确定不比该位置大的数据个数
        for (i=1; i<=k; ++i) //C[i]记录了<=C[i]的元素个数
            C[i] += C[i-1];
    
        //step3:从大到小依次扫描原数据,将其存储到其应该存储的位置处
        for (j=A.size()-1; j>=1; --j) //从大到小扫描A,将A[j]存入到其应该存入的位置C[A[j]]中
        {
            B[C[A[j]]] = A[j];
            C[A[j]] -= 1;
        }
    }
    
    int main()
    {
        int i=0, n = 9,k = 5;
        vector<int> A(n,0), B(n,0);
        A[1] = 2; A[2] = 5; A[3] = 3;
        A[4] = 0; A[5] = 2; A[6] = 3;
        A[7] = 0; A[8] = 3; 
        counting_sort(A,B,k);
        for (i=1; i<n; ++i)
            cout << B[i] << ' ';
        cout << endl;
        return 0;
    }

       如果不考虑计数排序的稳定性,则由C中的下标就是A中元素的值可以直接利用C的下标及其相应的个数来给A重新排序,即可以不用额外的B空间。参考:http://www.cnblogs.com/eaglet/archive/2010/09/16/1828016.html,程序如下:

    void counting_sort(vector<int> &A , int k)  
    {  
        vector<int> C(k+1);//初始化为0  
        int i;  
        for ( i=1 ; i<A.size() ; i++)//C[i]包含等于i的个数  
            C[A[i]] = C[A[i]] + 1 ;  
        
        int j=0;
        for (i=0 ; i<=k ; i++)  
        {  
            while (C[i]--  > 0)  
                A[++j] = i;  
        }  
    }  

      

  • 相关阅读:
    全局索引 truncate有数据的分区,索引失效,没数据的分区,索引不失效
    数组的操作
    调存储过程shell
    Flex中的折线图
    SecurityError:Error #2048:安全沙箱冲突
    Flex中对表格中某列的值进行数字格式化并求百分比
    Flex中对表格中某列的值进行数字格式化
    ORA-00904:"T1"."AREA_ID" :标识符无效
    严重:IOException while loading persisted sessions:java.io.EOFException.
    开放的平台、向上的文化——揭秘万达电商(4)
  • 原文地址:https://www.cnblogs.com/lyfruit/p/2968807.html
Copyright © 2020-2023  润新知