标签:srand 数组 算法 直接 打表 namespace 长度 不能 统计
给定一个byte数组,要求统计byte数组的bitcount,也就是byte数组中为1的位的个数。
Redis提供了位数组数据结构,位数组是相对独立的一个程序,在《Redis设计与实现》(黄建宏著)一书中,对此有详细介绍。
回到问题上来,看到这个问题的第一印象就是暴力。假设byte数组长度为n,那么时间复杂度为8n。
我们的目的就是优化常数。
很容易想到的是用空间换时间,预先打表0~255之间的全部数字的bitcount,用到时直接查表,复杂度将为O(n).
这种方法的缺点在于只能存储8位而不能存储太多,因为随着位数的增加,空间消耗指数级增长。
最高级的一种优化方法建立在位运算基础上。这种方法的思想基于分治算法。
首先两两一组分成16组,然后四四一组分成8组,八八一组分成4组,16、16一组分成两组。
统计各个组内1的个数,然后归并可以通过移位运算和加法运算实现。
#include<iostream>
#include<stdlib.h>
#include<time.h>
using namespace std;
int bitcountBruteForce(char*a,int len){
int s=0;
for(int i=0;i<len;i++){
for(int j=0;j<8;j++){
if(a[i]&(1<<j)){
s++;
}
}
}
return s;
}
int table[1<<8];
int bitcountTable(char*a,int len){
int s=0;
for(int i=0;i<len;i++){
s+=table[int(a[i]&0xff)];
}
return s;
}
int swar(int x){
x=(x&0x55555555)+((x>>1)&0x55555555);
x=(x&0x33333333)+((x>>2)&0x33333333);
x=(x&0x0f0f0f0f)+((x>>4)&0x0f0f0f0f);
x=(x*0x01010101)>>24;
return x;
}
int swar2(int x){
x=(x&0x55555555)+((x>>1)&0x55555555);
x=(x&0x33333333)+((x>>2)&0x33333333);
x=(x&0x0f0f0f0f)+((x>>4)&0x0f0f0f0f);
x=(x&0x00ff00ff)+((x>>8)&0x00ff00ff);
x=(x&0x0000ffff)+((x>>16)&0x0000ffff);//x=(x>>16)+(x&31);
return x;
}
int bitcountSWAR(char*a,int len){
int s=0;
int intLen=len/4;
int left=len%4;
int*ia=(int*)a;
for(int i=0;i<intLen;i++){
s+=swar2(*ia);
ia++;
}
for(int i=intLen*4;i<len;i++){
s+=table[a[i]];
}
return s;
}
void initTable(){
for(int i=0;i<(1<<8);i++){
int s=0;
for(int j=0;j<8;j++){
if(i&(1<<j)){
s++;
}
}
table[i]=s;
}
}
int timeit(int(*f)(char*,int),char*a,int len,int manytimes){
int begtime=time(0);
int res=0;
for(int i=0;i<manytimes;i++){
res=f(a,len);
}
cout<<"ans "<<res<<endl;
int endtime=time(0);
int timeused=endtime-begtime;
return timeused;
}
int main(){
const int n=1e6;
int a[n];
initTable();
srand(time(0));
for(int i=0;i<n;i++){
a[i]=rand();
}
cout<<"brute force "<<timeit(bitcountBruteForce,(char*)a,n*sizeof(int),10)<<endl;
cout<<"table method "<<timeit(bitcountTable,(char*)a,n*sizeof(int),10)<<endl;
cout<<"swar method "<<timeit(bitcountSWAR,(char*)a,n*sizeof(int),10)<<endl;
return 0;
}
标签:srand 数组 算法 直接 打表 namespace 长度 不能 统计
原文地址:https://www.cnblogs.com/weiyinfu/p/9090813.html