排序算法的c++实现——计数排序

    任何比较排序算法的时间复杂度的上限为O(NlogN), 不存在比o(nlgN)更少的比较排序算法。如果想要在时间复杂度上超过O(NlogN)的时间复杂度,肯定需要加入其它条件。计数排序就加入了限制条件,从而使时间复杂度为O(N).

    计数排序的核心思想(来自算法导论):计数排序要求待排序的n个元素的大小在[0, k]之间,并且k与n在一个数量级上,即k=O(n).对于每一个输入元素x, 确定小于等于x的个数为i。利用这一信息,就可以把元素x放到输出数组的正确位置,即把元素x放到输出数组下标为i-1的位置。
 
   重要说明:
   1. 计数排序要求待排序的n个元素的大小在[0, k]之间,并且k与n在一个数量级上,即k=O(n).
   此时使用计数排序可以把时间复杂度降到O(n)上。
   2. 计数排序不是基于比较的排序算法,它基于计数策略。
   3. 写计数排序算法时,应该把它写成稳定排序的。
   4. 计数排序还是原址排序,它需要借助额外的内存空间。

代码如下:

  1   /***********************************************************************
  2   *   Copyright (C) 2019  Yinheyi. <chinayinheyi@163.com>
  3   *   
  4   * This program is free software; you can redistribute it and/or modify it under the terms
  5   * of the GNU General Public License as published by the Free Software Foundation; either 
  6   * version 2 of the License, or (at your option) any later version.
  7   
  8   *   Brief:    
  9   *   Author: yinheyi
 10   *   Email: chinayinheyi@163.com
 11   *   Version: 1.0
 12   *   Created Time: 2019年05月11日 星期六 10时19分07秒
 13   *   Modifed Time: 2019年05月11日 星期六 14时00分09秒
 14   *   Blog: http://www.cnblogs.com/yinheyi
 15   *   Github: https://github.com/yinheyi
 16   *   
 17   ***********************************************************************/
 18   #include<string.h>
 19   #include<iostream>
 20   
 21   // 任何比较排序算法的时间复杂度的上限为O(NlogN), 不存在比o(nlgN)更少的比较排序算法。
 22   // 如果想要在时间复杂度上超过O(NlogN)的时间复杂度,肯定需要加入其它条件。计数排序就加入
 23   // 了限制条件,从而使时间复杂度为O(N).
 24   //
 25   // 计数排序的核心思想(来自算法导论):
 26   // 计数排序要求待排序的n个元素的大小在[0, k]之间,并且k与n在一个数量级上,即k=O(n).
 27   // 对于每一个输入元素x, 确定小于等于x的个数为i。利用这一信息,就可以把元素x放到输出数组
 28   // 的正确位置,即把元素x放到输出数组下标为i-1的位置。
 29   //
 30   // 重要说明:
 31   // 1. 计数排序要求待排序的n个元素的大小在[0, k]之间,并且k与n在一个数量级上,即k=O(n).
 32   // 此时使用计数排序可以把时间复杂度降到O(n)上。
 33   // 2. 计数排序不是基于比较的排序算法,它基于计数策略。
 34   // 3. 写计数排序算法时,应该把它写成稳定排序的。
 35   // 4. 计数排序还是原址排序,它需要借助额外的内存空间。
 36   //
 37   // 计数排序代码如下:
 38   // 参数说明:array表示数组指针,nLength_表示数组的最大长度,nMaxNumber_表示数组元素中的最大>  值;
 39   void CountingSort(int array[], int nLength_, int nMaxNumber_)
 40   {
 41       // 参数的合法化检测
 42       if (nullptr == array || nLength_ <= 1 || nMaxNumber_ <= 0)
 43           return;
 44   
 45       // 统计待排序数组中每一个元素的个数
 46       // 注意:此处new出来的数组的大小为nMaxNumber_ + 1, 用于统计[0, nMaxNumber_]范围内的元素
 47       int* ArrayCount = new int[nMaxNumber_ + 1]{0};
 48       for (int i = 0; i < nLength_; ++i)
 49       {
 50           ++ArrayCount[array[i]];
 51       }   
 52   
 53       // 此处计算待排序数组中小于等于第i个元素的个数. 
 54       // 备注:如果要进行大到小的排序,就计算大于等于第i个元素的个数, 也就从后向前进行累加;
 55       for (int i = 1; i < nMaxNumber_ + 1; ++i)
 56       {   
 57           ArrayCount[i] += ArrayCount[i-1];
 58       }
 59   
 60       // 把待排序的数组放到输出数组中, 为了保持排序的稳定性,从后向前添加元素
 61       int* ArrayResult = new int[nLength_];
 62       for (int i = nLength_ - 1; i >=0; --i)
 63       { 
 64           int _nIndex = ArrayCount[array[i]] - 1; // 元素array[i]在输出数组中的下标
 65           ArrayResult[_nIndex] = array[i];
 66   
 67           // 因为可能有重复的元素,所以要减1,为下一个重复的元素计算正确的下标;
 68           --ArrayCount[array[i]];
 69       }       
 70   
 71       // 交换数据并释放内存空间
 72       memcpy(array, ArrayResult, sizeof(int) * nLength_);
 73       delete [] ArrayCount;
 74       ArrayCount = nullptr;
 75       delete [] ArrayResult;
 76       ArrayResult = nullptr;
 77   }
 78   
 79   // 测试代码
 80   /***************    main.c     *********************/
 81   static void PrintArray(int array[], int nLength_);
 82   int main(int argc, char* argv[])
 83   {
 84       int test[10] = {12, 12, 4, 0, 8, 5, 2, 3, 9, 8};
 85       std::cout << "排序前:" << std::endl;
 86       PrintArray(test, 10);
 87       CountingSort(test, 10, 12);
 88       std::cout << "排序后:" << std::endl;
 89       PrintArray(test, 10);
 90   
 91       return 0;
 92   }
 93   
 94   // 打印数组函数
 95   static void PrintArray(int array[], int nLength_)
 96   {
 97       if (nullptr == array || nLength_ <= 0)
 98           return;
 99   
100       for (int i = 0; i < nLength_; ++i)
101       {
102           std::cout << array[i] << " ";
103       }
104   
105       std::cout << std::endl;
106   }

 

posted @ 2019-05-11 19:30  殷大侠  阅读(3488)  评论(0编辑  收藏  举报