计数排序(BitMap实现)
来源:互联网 发布:淘宝店装修流程图解 编辑:程序博客网 时间:2024/06/06 00:43
计数排序假设n个输入元素中的每一个都是介于0到k之间的整数,对每一个输入元素x,确定出小于x的元素的个数,就可以把x直接放到最终输出数组的位置上。例如有17个元素小于x,那么x位于第18个输出位置。而当有几个元素相同时,方案需要修改,不能把他们放在同一个输出位置上。也就是说,计数排序比较适合元素之间没有重复的情况。
就时间效率来看,计数排序几乎是只需要扫描一遍数组就可以将数放在正确的位置上,这比快速排序,堆排序等时间复杂度为nlog(n)快得多(时间复杂度为n),但时间上的缩短将会导致空间上的支出。对于计数排序,可以打个比方,假设输入的数据的最大值为1000,那么新开辟的数组必然要有1000个空间,因为排序的过程可以看成一种过程:假设输入250,那么就将这个数组的第250号位置记为1,而其他的初始化为0(当然,这样的话就不能允许重复的元素出现,所以实际的代码会略有变化,这里可以先这么理解)。所以,即使输入只有3个数,而最大的数是1000的话,那么至少也要开辟1000个数组空间,这样就造成了极大的资源浪费。所以,计数排序的一个缺点就是不适于处理输入值过大的情况(当然,后面使用BitMap也就是位图的话可以缓解这种压力,例如32位机器的话可以使开辟的数组空间减少32倍)。
这里先给出一般情况的计数排序的代码:
#include<stdio.h>#include<string.h>//数组的最多输入是MAX个,最大不会超过NewMax#define Max 10#define NewMax 100/*程序中需要两个数组作为参数,数组A为待排序的数组,数组B为排序成功后输出的数组,当然,两者是一样大的k表示新开辟的数组C的空间*/void Counting_Sort(int* A,int* B,int k){ int i,j; int C[k]; /*将k全部初始化为0*/ for(i=0;i<k;i++) C[i]=0; /*对A进行扫描,在数组C中相应的地方加上1*/ for(j=0;j<Max;j++) C[A[j]]+=1; /*一面这一步就是所谓的计算“比他小”的元素有几个,就是通过不断的累加得到*/ for(i=1;i<k;i++) C[i]=C[i]+C[i-1]; /*这一步向B数组输入元素,需要注意输入的方法 方向是从大到小,原因就在于输入一个后,那么对于”比他大“的元素来说,”比他小“的就少了一个了 从左网友的话,右边所有的元素都要一次减1,而从右向左就只需要把自己减去1就可以了 当然,注意下B的修改方式*/ for(j=Max-1;j>=0;j--) { B[C[A[j]]-1]=A[j]; C[A[j]]-=1; }}//主程序进行测试int main(void){ int A[Max]={23,54,99,56,23,5,78,12,3,56}; int B[Max]={}; Counting_Sort(A,B,NewMax); int i; for(i=0;i<Max;i++) printf("%d ",B[i]); printf("\n");return 0;}
当然了,新开辟的空间的大小令人无法忍受,而使用BitMap的话,虽然不能完全不需要新开辟空间,但却能够大大减小新空间的开支。
所谓的BitMap,其实就是一组位的集合,例如32位的int类型可以将它拆分成一个32个0/1的集合,上面的程序中C数组的每一个元素是用int来实现的,那么BitMap中每一个元素是用一个位来实现的,这样可以使空间缩小到原来的32分之1,但由于一个位只能表示0和1,那么以BitMap实现的计数排序就必然不允许有重复的元素出现了。
下面给出以BitMap实现计数排序的代码(位操作代码确实很蛋疼。。。好在我在几乎每一行代码都写了注释了,还看不懂拿块豆腐撞死算了= =):
#include<stdio.h>#include<string.h>#define MAX 10//测试数组的最大空间#define BITSPERWORD 32//32位的位的集合,就是说是以32个元素为一组#define SHIFT 5//偏移量5,什么是偏移量?将某个数右移5为是不是相当于除以32了呢?#define MASK 0x1F//除去了32,那么还需要获取余数,就拿这货来做下位运算就行了#define N 1000000//最大的数这里设置成1000000int a[ 1 + N/BITSPERWORD ];//需要1000000个元素集合,那么换算成普通的int数组,需要多少个呢?,只需要除个32加1就行了/*就是把数组里头清零,没什么特别的*/void clear(){ memset( a, 0, sizeof(a) );}/*下面这个函数是重点,传入一个int值,在位图中特定部分置1所谓i>>SHIFT,就是确定是在哪一个int里面的位要做修改那么,i&MASK是神马意思呢?想一下MASK的值是多少?0x1F,化成10进制就是31,一个32位的数,和这玩意儿与一下,相当于是得到了i除以32后的余数,而让1左移那么多为也可以理解了:不要把它想象成单独的1,而是一个32位的1,前头全是0,左移那么多位相当于就是在特定的位置置1了在整个数组中置1的具体实现就是或操作一下就行了*/void set( int i ){ a[ i>>SHIFT] |= ( 1<<( i&MASK ) );}/*下面这个函数是把特定的位置清零的,具体分析和上面的差不多,这里就不赘述了*/void clr( int i ){ a[ i>>SHIFT ] &= ~(1<<( i&MASK ) );}/*测试某一个位是否为1,1<<( i&MASK )就是这个数正常情况下该置一的地方a[ i>>SHIFT ]是之前修改过的地方,右边的那一位必然为1,只有左边的先前置1了,相与之后才能返回非0值*/int test( int i ){ returna[ i>>SHIFT ] & ( 1<<( i&MASK ) );}//主函数进行测试int main(void){int i;clear();int A[MAX]={123,2345,767554,23,5,5467,234564,125,54657,99};for(i=0;i<MAX;i++) set(A[i]);for( i = 0; i < N; i++ ){ if(test(i)) printf("%d ",i);}printf("\n");return 0;}
- 计数排序(BitMap实现)
- 计数排序(c++实现)
- 计数排序(CountingSort)的实现
- 计数排序算法实现(C版)
- 计数排序算法(C语言实现)
- 计数排序算法实现(函数模板)
- 算法导论计数排序实现(C++)
- 计数排序的实现(python)
- 计数排序的实现
- 计数排序简单实现
- 计数排序Java实现
- 计数排序-java实现
- 计数排序C实现
- C++实现计数排序
- Python实现计数排序
- 计数排序 实现
- Java实现计数排序
- Java实现计数排序
- WM_CHAR,WM_KEYDOWN和WM_SYSKEYDOWN
- Extjs.Date 常用函数
- 从6万到6000万:网络作家上演比特币投资神话
- JAVA实现多线程生产者消费者模型
- tcp 与udp 的区别
- 计数排序(BitMap实现)
- 关于linux(centos)安装有些软件时,出现 Requires: libstdc++.so.6(GLIBCXX_3.4.15)的解决方法
- 黑马程序员----IO(Input Output)流及File类
- 杭电 2023 求平均成绩
- java作用域public ,private ,protected 及不写时的区别
- iframe高度自适应
- 黄淮学院CSDN高校俱乐部java培训
- hdu_1249 三角形
- 九、蓝牙之间通信四个步骤