位數組(bit數組)


使用到位數組的代碼,一般出於兩個考慮: 1. 降低存儲空間。2. 加快查找效率(能迅速判斷某個地元素是否在一個集合中)。

知識准備

1. 計算機中的位操作: 與(&)、或(|) 、非(~)

  1 & 1 = 1        1 | 1 = 1        ~1 = 0

  1 & 0 = 0        1 | 0 = 1        ~0 = 1                  

  0 & 1 = 0        0 | 1 = 1

  0 & 0 = 0        0 | 0 = 0

2.  左移(<<)和右移(>>)

  左移一位相當於乘以2。左移操作后,右邊空缺位自動補0。右移(本文僅考慮邏輯右移)與左移相反方向操作,相當於除以2,左邊空缺自動補0。

3. 置1、置0,判斷置位。

  eg: x = 221,其二進制為11011101,若要將它的第5位由0變為1(置1),則只須第5位與1或即可

    11011101
    00100000
   |--------
    11111101
若要將它的第4位由1變為0(置0),則只須第4位與0與即可
    11011101
    11101111
   &--------
    11001101
判斷第5位是否置1
    11111101
    00100000
   &--------
    00100000  (相與的結果非0則表明相應位已置1,否則置0)

4.  非(~)運算

  eg: x = 221,其二進制為11011101

    11011101
   ~--------
    00100010

實例演示

假設要求11個數(0~10)存儲在位數組里,11個數就需要11個bit位, 而1個byte有8個bit位,故須2個byte才能存儲11個數。0存儲在第0個byte的第0位,1存儲在第0個byte的第1位...存儲在第1個byte的第0位,9存儲在第1個byte的第1位,10存儲在第1個byte的第2位。如下

    |high                      low|
|--- 1 byte ---|--- 0 byte ---|
0 0 0 0 0 0 0 0|0 0 0 0 0 0 0 0
10 9 8 7 6 5 4 3 2 1 0

一個數x(非負整數)若要存儲在位數組里, 會面臨兩個問題:

1. x存儲在第幾個byte里?

  因為一個byte可以存儲8個bit,那很顯然,x應該存儲在第(x/8)個byte里。

2. x存儲在第(x/8)個byte的第幾位上?

  通過觀察,x應該存儲在第(x%8)位上。

綜上, x應該存儲在第(x/8)個byte的第(x%8)位上。

在計算機里,位操作比除法和求模操作更高效點。x/8 相當於 x>>3(右移一位,相當於除以2;右移三位,相當於除以8);x%8相當於x&0x7。

我們要使得x存儲在位數組里,就是要使得第(x>>3)個byte的第(x&0x7)位上置1。由知識准備第3點的置1,可以得出,要使第0位置1,則與之相與的數為1(00000001);要使第1位置1,則與之相與的數為2(00000010);要使第2位置1,則與之相與的數為4(00000100) ...

由上可得,把x存儲在位數組里,則需要:

  bitArray[x>>3] |= (1<<(x&0x7))

進而可以得出,判斷x存儲在位數組里,則需要返回

       bitArray[x>>3] & (1<<(x&0x7))

把x從位數組里刪除,則需要

  bitArray[x>>3] &= ~(1<<(x&0x7))

C語言實現舉例

#include <stdlib.h>
#include <stdio.h>

#define SHIFT 3  
#define MASK 0x7 

#define BITARRAY_SIZE(size)             ((size >> SHIFT) + 1)
#define BYTE_INDEX(num)                 (num >> SHIFT)
#define ADD_TO_BITARRAY(array, num)		(array[BYTE_INDEX(num)] |= (1 << (num & MASK)))
#define IS_IN_BITARRAY(array, num)		(array[BYTE_INDEX(num)] & (1 << (num & MASK)))
#define CLEAR_BITARRAY(array, num)		(array[BYTE_INDEX(num)] &= ~(1 << (num & MASK)))

//檢測
void test(int value)
{
	if (value)
	{
		printf("In the array.\n");
	}
	else
	{
		printf("Not in the array.\n");
	}
}

int main()
{
	//存儲0~10這11個數
	int max_size = 11;
	//存儲9
	int number = 9;
	char *bitArray = (char*)malloc(BITARRAY_SIZE(max_size) * sizeof(char));
	
	printf("Init: ");
	test(IS_IN_BITARRAY(bitArray, number));

	//9放到位數組上
	ADD_TO_BITARRAY(bitArray, number);
	printf("ADD_TO_BITARRAY: ");
	test(IS_IN_BITARRAY(bitArray, number));
	
	//9從位數組上清除
	CLEAR_BITARRAY(bitArray, number);
	printf("CLEAR_BITARRAY: ");
	test(IS_IN_BITARRAY(bitArray, number));
	
	if (bitArray)
	{
		free(bitArray);
		bitArray = NULL;
	}
	return 0;
}

 

其它比較高級的語言,封裝成特定的類去實現位數組,提供了豐富的操作位的方法,比較方便。如:

C++ bitset
C# BitArray
JAVA BitSet
GO

 

 

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM