常见的排序算法都是基于比较的,这些算法的时间复杂度最好也只能到O (n*lg (n)),而实际上的排序算法的时间复杂度也是能够达到O(n)的,用空间来换时间,比如说这里的计数排序:
使用计数排序有一定的前提,需要知道数组中最大的元素(其实不知道也是可以的,多遍历一次找出最大值罢了),假设这个值为k。基本的原理是构造一个长度为k + 1的数组c,用来保存要排序数组a中每个元素的出现次数。
算法中包括4个循环,第一个循环仅仅是把这个数组c置零(我忽然想起来,为啥不用memset呢……)。
第二个循环取得了数组a中每个元素出现的次数。
那么要怎么进行排序呢?
直接遍历数组c?不行,这样时间复杂度变变成O(n^2)了
于是,第三个循环从第二个元素开始,依次累加前一个元素的值。对于数组a中的每个元素a[i],这样我们得到了整个数组中有几个元素小于等于a[i],这也就是a[i]应该出现的位置。
第四个循环就按照这个位置在新的数组b中填充元素,排序完成。这一步不是很好理解,看看代码仔细体会一下。
BTW,这个代码还有点问题,假如元素中还有负数,算法就需要修改了;
假如传入的两个数组长度不同,也没法得到完整的排序。
#include "array_sort.h" #include "base.h" /** * @brief counting sort * * @note Complexity O ( n ); * @param a the input array; * @param b the sorted output array, only len_b elements will be written * @param len_a length of array a; * @param len_b length of array b; * @param k all elements in array a should be lesser than or equal to k; * @return the sorted array, that is array b; */ int *counting_sort (int *a, int *b, int len_a, int len_b, int k) { int i, j; /* there are (k + 1) elements between 0 and k */ int c[k + 1]; for (i = 0; i <= k; i++) { c[i] = 0; } /* c[i]: contains number of element i */ for (j = 0; j < len_a; j++) { c[a[j]]++; } /* c[i]: contians numbers than lesser than or equal to element i */ for (i = 1; i <= k; i++) { c[i] += c[i-1]; } for (j = len_a - 1, i = 0; (i < len_b) && (j >= 0); j--, i++) { /** * j: index of array i, range (0, len_a - 1); * a[j]: In array a, what's in index j? * c[ a[j] ]: how many elements are lesser than or equal to a[j]? * c[a[j]] - 1: In array b, where's the position for a[j]? * b[c[a[j]] - 1] = a[j]: place a[j] to the right position on array b. */ b[c[a[j]] - 1] = a[j]; /* we have add a[j] to array b, reduce counting by 1 */ (c[a[j]])--; } return b; }