这篇文章并不是讨论上一篇中的优化问题,而解决一另相关问题,在空间换时间的算法里面,有一个256长的maskArray数组,这篇文章是写如何来初使化这个数组的算法。
最初的想法极其简单:
void initMaskArray(char maskArray[])
{
maskArray[0] = 8;
for (unsigned char i = 0xFF; i > 0; i--)
{
unsigned char mask = 0x1;
for (int j = 0; j < 8; j++)
{
if ((i & mask) != 0)
{
maskArray[i] = j;
break;
}
mask <<= 1;
}
}
}
但突然想到,另一种算法,与前面遍历是反向的,前面是由数字去查找第一个非0bit,而另一种算法是逆向,从bit生成数字,当时突然想法就像1bit从左往右移动,最后生成256个数一样。
void cycleInitMask(unsigned char number, char step, char maskArray[])
{
if (step < 0)
return;
int tmp = number|(0x1 << step);
maskArray[tmp] = step--;
cycleInitMask(number, step, maskArray);
cycleInitMask(tmp, step, maskArray);
}
void cycleInitMaskArray(char maskArray[])
{
int number = 0, step = 7;
maskArray[0] = 8;
cycleInitMask(0, 7, maskArray);
}
这就是一个二叉树的形式往下面展开,用图来解释:
优化方案便是下面这个:
template<int STEP>
class MaskInitClass
{
public:
static const unsigned char mask = (0x1 << STEP);
static void initMask(unsigned char number, char maskArray[])
{
unsigned char tmp = number | mask;
maskArray[tmp] = STEP;
MaskInitClass<STEP-1>::initMask(tmp, maskArray);
MaskInitClass<STEP-1>::initMask(number, maskArray);
}
};
template<> class MaskInitClass<0>
{
public:
static const unsigned char mask = 0x1;
static void initMask(unsigned char number, char maskArray[])
{
maskArray[number | mask] = 0;
}
};
void templateInitMask(char maskArray[])
{
maskArray[0] = 8;
MaskInitClass<7>::initMask(0, maskArray);
}
其逻辑是递归算法一样,不过将一些行为变成编译时。
都做到这一步,肯定想会不会有已经算好了的情况,也便有了下面一个版本
template<unsigned char NUM, unsigned char MASKPOS, unsigned char STEP>
class DetailMaskClass
{
public:
static const unsigned char mask = (0x1 << STEP);
static void initMask(char maskArray[])
{
maskArray[NUM] = MASKPOS;
DetailMaskClass<NUM, MASKPOS, STEP-1>::initMask(maskArray);
DetailMaskClass<NUM|mask, STEP, STEP-1>::initMask(maskArray);
}
};
template<unsigned char NUM, unsigned char MASKPOS>
class DetailMaskClass<NUM, MASKPOS, 0>
{
public:
static const unsigned char mask = 0x1;
static void initMask(char maskArray[])
{
maskArray[NUM] = MASKPOS;
DetailMaskClass<NUM|mask, 0, 0>::initMask(maskArray);
}
};
template<unsigned char NUM>
class DetailMaskClass<NUM, 0, 0>
{
public:
static void initMask(char maskArray[])
{
maskArray[NUM] = 0;
}
};
void templateDetailInit(char maskArray[])
{
DetailMaskClass<0, 8, 7>::initMask(maskArray);
}
这一个版本就是为每个节点都生成了一个类,其NUM为数的值, MASKPOS则是第一个非0bit的记录。
想起以前在H公司看过大佬曾经写过如何让编译器一直运行,就是用这种方式,用template一层一层展开也行,但文章里面说最多只能到50层,编译器便会出错,而这种方式将STEP与MASKPOS都弄成31与32,那么将会生成最后叶子节点便有42亿的类,统计下32层等比数列的总合便清楚,中间生成多少类对象。
mask.cpp
#include <sys/timeb.h>
#include <stdio.h>
#include <stdlib.h>
long long systemtime()
{
timeb t;
ftime(&t);
return t.time*1000+t.millitm;
}
void arrayPrint(char maskArray[])
{
for (int i = 0; i < 256; i++)
{
printf("%d ", (int)maskArray[i]);
}
printf("\n");
}
int getFirstNoZeroByte(unsigned char number)
{
unsigned char mask = 1;
for (int i = 0; i < 8; i++)
{
if ((mask & number) != 0)
return i;
mask <<= 1;
}
return 8;
}
template<int STEP>
class MaskInitClass
{
public:
static const unsigned char mask = (0x1 << STEP);
static void initMask(unsigned char number, char maskArray[])
{
unsigned char tmp = number | mask;
maskArray[tmp] = STEP;
MaskInitClass<STEP-1>::initMask(tmp, maskArray);
MaskInitClass<STEP-1>::initMask(number, maskArray);
}
};
template<> class MaskInitClass<0>
{
public:
static const unsigned char mask = 0x1;
static void initMask(unsigned char number, char maskArray[])
{
maskArray[number | mask] = 0;
}
};
template<unsigned char NUM, unsigned char MASKPOS, unsigned char STEP>
class DetailMaskClass
{
public:
static const unsigned char mask = (0x1 << STEP);
static void initMask(char maskArray[])
{
maskArray[NUM] = MASKPOS;
DetailMaskClass<NUM, MASKPOS, STEP-1>::initMask(maskArray);
DetailMaskClass<NUM|mask, STEP, STEP-1>::initMask(maskArray);
}
};
template<unsigned char NUM, unsigned char MASKPOS>
class DetailMaskClass<NUM, MASKPOS, 0>
{
public:
static const unsigned char mask = 0x1;
static void initMask(char maskArray[])
{
maskArray[NUM] = MASKPOS;
DetailMaskClass<NUM|mask, 0, 0>::initMask(maskArray);
}
};
template<unsigned char NUM>
class DetailMaskClass<NUM, 0, 0>
{
public:
static void initMask(char maskArray[])
{
maskArray[NUM] = 0;
}
};
void templateInitMask(char maskArray[])
{
maskArray[0] = 8;
MaskInitClass<7>::initMask(0, maskArray);
}
void templateDetailInit(char maskArray[])
{
DetailMaskClass<0, 8, 7>::initMask(maskArray);
}
void cycleInitMask(unsigned char number, char step, char maskArray[])
{
if (step < 0)
return;
int tmp = number|(0x1 << step);
maskArray[tmp] = step--;
cycleInitMask(number, step, maskArray);
cycleInitMask(tmp, step, maskArray);
}
void cycleInitMaskArray(char maskArray[])
{
int number = 0, step = 7;
maskArray[0] = 8;
cycleInitMask(0, 7, maskArray);
}
void initMaskArray(char maskArray[])
{
maskArray[0] = 8;
for (unsigned char i = 0xFF; i > 0; i--)
{
unsigned char mask = 0x1;
for (int j = 0; j < 8; j++)
{
if ((i & mask) != 0)
{
maskArray[i] = j;
break;
}
mask <<= 1;
}
}
}
int main(int argc, char* argv[])
{
char maskArray1[255];
char maskArray2[255];
char maskArray3[255];
char maskArray4[255];
long beg = systemtime();
for (int i = 0; i < 1000000; i++)
cycleInitMaskArray(maskArray1);
long test1 = systemtime() - beg;
beg = systemtime();
for (int i = 0; i < 1000000; i++)
initMaskArray(maskArray2);
long test2 = systemtime() - beg;
beg = systemtime();
for (int i = 0; i < 1000000; i++)
templateInitMask(maskArray3);
long test3 = systemtime() - beg;
beg = systemtime();
for (int i = 0; i < 1000000; i++)
templateDetailInit(maskArray4);
long test4 = systemtime() - beg;
printf("%d, %d, %d, %d\n", test1, test2, test3, test4);
arrayPrint(maskArray1);
arrayPrint(maskArray2);
arrayPrint(maskArray3);
arrayPrint(maskArray4);
return 0;
}