区分三个int的值

时间:2013-11-01 18:45:23

标签: c++ math bit-manipulation

我有三个整数变量,只能使用值012。我想区分我所有三个数字的组合,排序不计算在内。假设变量名为xyz。在这种情况下,x=1, y=0, z=0x=0, y=1, z=0以及x=0, y=0, z=1都是相同的数字,我将此组合称为001

现在有一百种方法可以做到这一点,但我要求一个优雅的解决方案,只是出于教育目的。

我想到按位数001逐位移位:

001 << 0 = 1
001 << 1 = 2
001 << 2 = 4

但数字002111都会给6

5 个答案:

答案 0 :(得分:7)

移位的想法很好,但你需要 2 位来计算为3.所以尝试移位两次位数:

1 << (2*0) = 1
1 << (2*1) = 4
1 << (2*2) = 16

为所有3个数字添加这些数字,前2位将计算您有多少0,第二个2位将计算多少1,第三个2位将计算多少2 { {1}}。

编辑虽然结果是6位长(每个数字选项0,1,2为2位),但您只需要最低4位作为唯一标识符 - 就好像您知道多少{您拥有{1}}和0,然后确定1的数量。

所以不要做

2

你可以做到

res = 1<<(2*x);
res+= 1<<(2*y);
res+= 1<<(2*z);

因为那时

res = x*x;
res+= y*y;
res+= z*z;

因此仅使用4位而不是6位。

答案 1 :(得分:4)

当不同可能性的数量很小时,可以使用查找表。

首先,对三个数字的所有可能组合进行编号,如下所示:

Combinations                  N     Indexes
-------------                 -     ------
000                           0     0
001, 010, 100                 1     1, 3, 9
002, 020, 200                 2     2, 6, 18
011, 101, 110                 3     4, 10, 12
012, 021, 102, 120, 201, 210  4     5, 7, 11, 15, 19, 21
022, 202, 220                 5     8, 20, 24
111                           6     13
112, 121, 211                 7     14, 16, 22
122, 212, 221                 8     17, 23, 25
222                           9     26

第一列显示相同的组合;第二列显示组合的编号(我任意分配);第三列显示每个组合的索引,计算为9*<first digit> + 3*<second digit> + <third digit>

接下来,使用此表达式作为索引,为这十种组合中的每一种构建一个查找表:

9*a + 3*b + c

其中abc是您拥有的三个数字。该表如下所示:

int lookup[] = {
    0, 1, 2, 1, 3, 4, 2, 4, 5, 1
,   3, 4, 3, 6, 7, 4, 7, 8, 2, 4
,   5, 4, 7, 8, 5, 8, 9
};

这是第一个表的重写,索引处的值对应于列N中的值。例如,组合号1位于索引139;合并2位于索引2618,依此类推。

要获得组合编号,只需检查

int combNumber = lookup[9*a + 3*b + c];

答案 2 :(得分:1)

对于这么小的数字,最简单的方法就是单独检查它们,而不是试图模仿,例如:

bool hasZero = false;
bool hasOne = false;
bool hasTwo = false;

// given: char* number or char[] number...

for(int i = 0; i < 3; ++i)
{
    switch (number[i])
    {
        case '0': hasZero = true; break;
        case '1': hasOne = true; break;
        case '2': hasTwo = true; break;
        default: /* error! */ break;
    }
}

答案 3 :(得分:1)

如果我理解正确,你有一些数字序列可以是1,2或3,其中它们的排列无关紧要(只是不同的组合)。

情况就是这样:

std::vector<int> v{1, 2, 3};
std::sort(v.begin(), v.end());

这将使所有不同的组合保持正确对齐,并且您可以轻松编写循环来测试相等性。

或者,您可以使用std::array<int, N>(其中N是可能值的数量 - 在本例中为3)。

std::array<int, 3> a;

您要将a[0]设置为等于1的数量,a[1]等于'2的数量等等

// if your string is 111
a[0] = 3;

// if your string is 110 or 011
a[0] = 2;

// if your string is 100 or 010 or 001
a[0] = 1;

// if your string is 120
a[0] = 1;
a[1] = 1;

// if your string is 123
a[0] = 1;
a[1] = 1;
a[2] = 1;

如果您希望将其存储在一个32位整数中:

unsigned long x = 1; // number of 1's in your string
unsigned long y = 1; // number of 2's in your string
unsigned long z = 1; // number of 3's in your string
unsigned long result = x | y << 8 | z << 16;

要检索每个的数量,您可以

unsigned long x = result & 0x000000FF;
unsigned long y = (result >> 8) & 0x000000FF;
unsigned long z = (result >> 16) & 0x000000FF;

这与RBG宏中发生的情况非常相似。

答案 4 :(得分:1)

int n[3]={0,0,0};
++n[x];
++n[y];
++n[z];

现在,在n数组中,对于x,y,z的每个唯一无序组合,您都有唯一的有序值组合。

例如,x = 1,y = 0,z = 0且x = 0,y = 0,z = 1将给出n = {2,1,0}