范围域转化为前缀域
给定一个范围,将其转化成有数字和掩码组成的前缀域。
例:
[45,208]
即[0b00101101,0b11010000]
转化为前缀域表达为:
00101101/11111111
00101110/11111110
00110000/11110000
01000000/11000000
10000000/11000000
11000000/11110000
11010000/11111111
思路1:
两两合并直到直至不能合并为止
以[7,13]
为例
则[7,13]
以前缀表示为
0111/1111
1000/1100
1100/1110
题解1:
#include <stdio.h>
#include <string.h>
#include <stdint.h>
#include <stdlib.h>
void printbits(uint16_t v, int size)
{
for (int i = size - 1; i > -1; i--)
{
printf("%d", (v >> i) & 1);
}
}
void mask(const uint16_t a, const uint16_t b)
{
uint16_t value[65536], mask[65536];
uint32_t index = 0;
uint32_t count = b - a + 1;
printf("count%d\n", count);
memset(mask, 0xFFU, 65536 * sizeof(uint16_t));
for (uint32_t i = 0, j = a; i < count; i++, j++)
{
value[i] = j;
}
for (uint32_t k = 0; k < 16; k++)
{
index = 0;
for (uint32_t i = 0, j = 1; i < count; i++, j++) //单次循环
{
if ((j < count) && (mask[i] == mask[j]) && ((value[i] & (mask[i] << 1U)) == (value[j] & (mask[j] << 1U))))
{
value[index] = value[i];
mask[index] = mask[i] << 1U;
i++;
j++;
}
else
{
value[index] = value[i];
mask[index] = mask[i];
}
index++;
}
if (count == index)
{
break;
}
else
{
count = index;
}
}
printf("[%u,%u]\n", a, b);
for (int i = 0; i < count; i++)
{
printbits(value[i], 16);
printf(" / ");
printbits(mask[i], 16);
printf("\n");
}
}
int main(int argc, char *argv[])
{
mask((uint16_t)atoi(argv[1]), (uint16_t)atoi(argv[2]));
return 0;
}
题解2:
上个版本中只是两两合并,这次使用贪婪合并,能合并8个就不合并4个
具体思路:
看当前数值的二进制表示时,末位有几个0
有0个0 至多可以合并2^0=1项,即当前是最简的,无法合并的
有1个0 至多可以合并2^1=2项
有2个0 至多可以合并2^2=4项
…
为什么说至多,是因为如果只有1个数据,就算末位有再多0,也无法合并了
只有三个数据,也是无法合并四项的,有可能是能合并两项的
000
001
010
[0,3]
那么现在考虑怎么实现
首先数据都是连续的,这是后续操作的基础
当前数据是v,末位有n个0
v + 2^n - 1是否<=b,是的话就代表能合并,当前值存起来,计算掩码为1…100…00 (16-n个1,n个0) 然后继续计算下个值
不是的话,将n–,再次判断,直至找到符合的,因为最少也会有一个 所以算法是收敛的
#include <stdio.h>
#include <stdlib.h>
#define VAILDWIDTH 16
#define MAX(a, b) (a > b ? a : b)
#define BIT(value, index) ((value >> index) & 1)
#define PRINTBITS(value) \
{ \
int size = VAILDWIDTH; \
while (size--) \
{ \
printf("%d", BIT(value, size)); \
} \
}
int tail0nums(int num)
{
int count = 0;
while (!BIT(num, count) && count <= VAILDWIDTH)
{
num >> 1;
count++;
}
return count;
}
void range2prefix(const int a, const int b)
{
int index = 0;
int tail_zero_num = 0;
struct
{
int value[128]; // 16位的时候其实至多只会有30个,组合是[1,65534]
int mask[128];
int count;
} result;
result.count = 0;
for (index = a; index <= b; index++)
{
tail_zero_num = tail0nums(index);
do
{
if (0 == tail_zero_num) /*末位没有0的操作*/
{
result.value[result.count] = index;
result.mask[result.count] = tail_zero_num;
result.count++;
}
else if ((2 << (tail_zero_num - 1)) <= (b - index + 1)) //(index + (2 << (tail_zero_num - 1)) - 1 <= b) /*末位有0的操作*/
{
result.value[result.count] = index;
result.mask[result.count] = tail_zero_num;
result.count++;
index += (2 << (tail_zero_num - 1)) - 1;
break; //打破while循环
}
} while (tail_zero_num--);
}
printf("[%5u,%5x] %u\n", a, b, result.count);
printf("%u\n", result.count);
for (int i = 0; i < result.count; i++)
{
PRINTBITS(result.value[i]);
printf("/%u\n", VAILDWIDTH - result.mask[i]);
}
}
int main(int argc, char *argv[])
{
int a, b;
a = atoi(argv[1]);
b = atoi(argv[2]);
{
int a = 90;
}
if (argc > 2 && -1 < a && a <= b && b < (1 << VAILDWIDTH))
{
range2prefix(a, b);
}
return 0;
}