2010年11月12日星期五

简单二值信息的存储

在我们写程序的的时候,有时候我们经常需要存储许多的二值的信息量,如:一件事情有没有发生、很多灯的亮灭的状态、网络传输中判断重复数据包等。这时我们就需用用一个信息单元来存储1、0 信息来表示有或无。那我们该怎么表示呢?最简单的方法就是使用数组了
1
char buf[256];
这个数组中就可以存储256个信息量的状态,每个数组单位中存储一个0或1(buf[0] = 1, buf[1] = 0;)。这里我们有一种更好的方法就是用C语言中的位操作来实现这个需求。使用char类型的8位表示8个信息量,使用每一位01表示不同。这样我们用char buf[32]就可以存储256个二值信息量,大大节约了空间。位操作不能像数组操作那样直接简单,所以我们封装了几组函数如下:
1
2
3
4
5
6
7
8
9
#define BITSPERWORD 32
#define SHIFT 5
#define MASK 0x1F
#define N 10000000
int a[1 + N/BITSPERWORD];
 
void set (int i) {        a[i>>SHIFT] |=  (1<<(i & MASK)); }
void clr (int i) {        a[i>>SHIFT] &= ~(1<<(i & MASK)); }
int  test(int i) { return a[i>>SHIFT] &   (1<<(i & MASK)); }

上面是我一个程序中的例子。这里我们使用的是int类型表示32个信息量。
a[i>>SHIFT]来确定设置a数组的哪一个元素,(1<<(i & MASK))用来确定设置一个a数组元素中的某一位!
我们的需求是判断0 ~ 10000000 之中的数字是否出现过,而set(1)、clr(1)、test(1)函数就可以将表示数字一是否存在的哪一位置为1、清零、判断是否为1。这样我们就可以通过这几个函数来实现位的操作。
在我看《编程珠玑》的过程中,出现了新的需求,就是记录 0 ~ 10000000之中数字出现的次数,最多为15次。这里用一位就不可能表示了,所以我们设计为用4位表示一个数字出现的次数。(0000 ~ 1111 : 0 ~ 15)
代码如下:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
#define BITSPERWORD 8
#define SHIFT 3
#define MASK 0x07
#define N 10000000
int a[1 + N/BITSPERWORD];
 
 
/* 输出整数j的所有的位 */
void prnt(int j)
{
    int i;
 
    for (i = 31; i >= 0; i--) {
 if (j & (1 << i )) {
     printf("1");
 } else {
     printf("0");
 }
    }
 
    printf("\n");
}
 
 
void clr(int i)
{
    a[i>>SHIFT] &= ~(15<< ((i & MASK) * 4));
}
 
void set(int i)
{
    int t;
    t = a[i>>SHIFT] >> ((i & MASK) * 4);
    t = ((t & 0x0f) + 1) & 0x0f; /* 这里限定,出现次数最大的数据为15 */
    t = t << ((i & MASK) * 4);
 
    clr(i);
    a[i>>SHIFT] |= t;
}
 
 
int get(int i)
{
    int t;
    t = ( a[i>>SHIFT] >> ((i & MASK) * 4) ) & 0x0f;
    return t;
}
 
int test(int i)
{
    return a[i>>SHIFT] & ( 15 << ((i & MASK) * 4));
}

没有评论:

发表评论