之前接触过的排序,都是基于交换的,这种类型的排序,对数据的内容木有限制,可以是小数,整数都无所谓。并且有理论证明基于这种交换的排序的时间下界是n*log(n)复杂度。但是如果当数据是又一些规律同时空间复杂度要求木有那么高的时候,就可以引入其他算法,来提高时间的效率,计数排序就是这样的一种思路。
假设我们的问题是这样的, 我们输入一组数值,如果我们知道是从 0-10,当如可以更大,但是如果特别特别特别大的时候,这种算法的空间开销太大在实际使用中就不划算了,例如已经能够大的超过内存云云。然后输入的数据是
8 9 2 3 7 8 9
因为我们知道数组中出现的数的范围,并且排序的方式明确,例如 9就是比2大。所以我们可以借助一个数组记录出现的情况,然后分析这个出现的情况来得到排序的结果
例如数组是 statastics[10]
那么扫描一遍以后数组值是
0 0 1 1 0 0 0 1 2 2
如果要是从小到大排序的话,我们知道2 出现一次,3一次....9是2次
则最后结果是 2 3 7 8 8 9 9这样排序就完成了
算法效率高O(n)但是借助辅助空间,并且通用性不好,例如数据是小数云云。
其实很多算法都是在特定的数据类型下有效,牺牲空间换来效率(谁叫内存越来越便宜呢),,例如trie树,hash表
计数排序可以处理的典型问题可以是,给定一个串A串B,看串B是不是包含在串A当中,
例如 A = ACEDSAG B = DSAG 这个类型的扩展可以参看 http://blog.csdn.net/v_JULY_v/article/details/6347454 博主很强大。
另外一个题目来自pku 2159 http://poj.org/problem?id=2159
其实就是统计出现的字母的个数,然后将个数排序,只要两个串排序后的计数一致,则认为他们可以被互相编码
代码
#include <stdio.h> #include <string.h> #include <algorithm> int cmp(const void*pIntA,const void *pIntB) { return *((int*)pIntA) - *((int*)pIntB); } int main() { int numofA[26]; int numofB[26]; char sA[104]; char sB[104]; int i,j; while(scanf("%s%s",sA,sB) != EOF) { memset(numofA,0,sizeof(numofA)); memset(numofB,0,sizeof(numofB)); const int lenA = strlen(sA); const int lenB = strlen(sB); for( i = 0; i < lenA; i++) { numofA[sA[i]-'A']++; } for( i = 0; i < lenB; i++) { numofB[sB[i]-'A']++; } //sort(numofA,numofA+26,) qsort(numofA,26,sizeof(numofA[0]),cmp); qsort(numofB,26,sizeof(numofB[0]),cmp); for(i = 0; i < 26 ; i++) { if(numofA[i] != numofB[i]) break; } if( i == 26) { printf("YES\n"); } else { printf("NO\n"); } } return 0; }
另外一种做法是采用哈希,不过其实本质是一样的,代价也是O(m+n)
一点其他的狂想,其实有一些问题有类似的要求,例如问A串是不是B的字串,对于这类问题景点算法是KMP。如果给定一个很大的字典库,问给定串是不是在字典中出现过,这种情况用trie树会有比较好的结果,因为效率很好,存储空间和实际所有串多存储比其他也比较也不是特别浪费空间。
,,,,,,,,,