二分法查找第一个不为0 bit 续。

    这篇文章并不是讨论上一篇中的优化问题,而解决一另相关问题,在空间换时间的算法里面,有一个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;
}

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值