任何比较排序算法的时间复杂度的上限为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. <[email protected]> 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: [email protected] 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 }
原文地址:https://www.cnblogs.com/yinheyi/p/10849708.html
时间: 2024-10-13 08:58:09