[英]C/C++ Bit Array or Bit Vector
我正在學習C / C ++編程,遇到了“位數組”或“位向量”的用法。 無法理解其目的? 這是我的疑問-
int
數組嗎? (當然,更多的內存,但是..) 我正在尋找應用程序,以便可以更好地理解。 例如
問:您將得到一個文件,其中包含整數(1到1百萬)。 有一些重復項,因此缺少一些數字。 找到找到遺漏號碼的最快方法?
對於上述問題,我已經閱讀了告訴我使用位數組的解決方案。 一個整數如何存儲一個整數?
我認為您在數組和數字之間感到困惑,尤其是操縱二進制數字的含義。
我將通過示例進行介紹。 假設您有許多錯誤消息,並且想要從函數的返回值中返回它們。 現在,您可以將錯誤1,2,3,4 ...標記為您的腦海,但是,僅給出一個數字,您如何確定發生了哪些錯誤?
現在,嘗試標記錯誤1,2,4,8,16 ...基本上增加2的冪。 為什么這樣做? 好吧,當您以2為基數時,您正在操縱一個像00000000
數字,其中每個數字對應於2的冪乘以其從右邊開始的位置。 因此,假設發生錯誤1、4和8。 好吧,那可以表示為00001101
。 相反,第一個數字= 1 * 2 ^ 0,第三個數字1 * 2 ^ 2和第四個數字1 * 2 ^ 3。 將它們全部加在一起就可以得到13。
現在,我們可以通過應用位掩碼來測試是否發生了此類錯誤。 例如,如果您想找出是否發生錯誤8
,請使用8 = 00001000
的位表示形式。 現在,為了提取是否已發生該錯誤,請使用二進制文件,如下所示:
00001101
& 00001000
= 00001000
我確定您知道an和and的工作原理或可以從上面推論得出-在數字上工作,如果任何兩位數字均為1,則結果為1,否則為0。
現在,在C中:
int func(...)
{
int retval = 0;
if ( sometestthatmeans an error )
{
retval += 1;
}
if ( sometestthatmeans an error )
{
retval += 2;
}
return retval
}
int anotherfunc(...)
{
uint8_t x = func(...)
/* binary and with 8 and shift 3 plaes to the right
* so that the resultant expression is either 1 or 0 */
if ( ( ( x & 0x08 ) >> 3 ) == 1 )
{
/* that error occurred */
}
}
現在,要實用。 當內存稀疏並且協議沒有冗長的xml等的奢侈時,通常將字段定義為這么多位寬。 在該字段中,將各種位(標志,2的冪)分配給某種含義,並應用二進制運算來推斷是否已設置它們,然后對其進行運算。
我還應該補充一點,二進制運算在思想上與計算機的底層電子設備非常接近。 想象一下,如果位字段對應於各種電路的輸出(是否帶電)。 通過使用足夠多的上述電路組合,您可以制造出……台計算機。
關於bits數組的用法:
如果您知道“只有”一百萬個數字,則使用一百萬個比特的數組。 在開始時,所有位都將為零,並且每次您讀取一個數字時-將此數字用作索引並將該索引中的位更改為1(如果還不是一個的話)。
讀取所有數字后-缺失的數字是數組中零的索引。
例如,如果我們只有0-4之間的數字,則數組開頭應為:0 0 0 00。如果我們讀取數字:3、2、2,則數組將如下所示:read 3- > 0 0 0 1 0.再次讀取3-> 0 0 0 1 0.讀取2-> 0 0 1 1 0.檢查零的索引:0,1,4-這些是缺少的數字
順便說一句,您當然可以使用整數而不是位,但是它可能占用(取決於系統)32倍的內存
西萬
位向量的位陣列用作從位置到某個位值的映射。 是的,它基本上與Bool數組相同,但是典型的Bool實現長度為一到四個字節,並且占用了太多空間。
通過使用單詞數組和二進制掩碼操作以及轉移來存儲和檢索它們,我們可以更有效地存儲相同數量的數據(減少了使用的總內存,減少了對內存的訪問,減少了緩存未命中,減少了內存頁面交換)。 訪問單個位的代碼仍然非常簡單。
還有一些用C語言內置的位域支持(您編寫int i:1;
類的東西int i:1;
說“只消耗一位”),但是它不適用於數組,並且您對整體結果的控制較少(詳細信息實施方式取決於編譯器和對齊問題)。
以下是回答“搜索遺漏號碼”問題的一種可能方法。 我將int大小固定為32位以使事情簡單,但是可以使用sizeof(int)編寫它以使其可移植。 並且(取決於編譯器和目標處理器)只能使用>> 5
代替/ 32
和& 31
和& 31
代替% 32
來使代碼更快,但這只是為了給出想法。
#include <stdio.h>
#include <errno.h>
#include <stdint.h>
int main(){
/* put all numbers from 1 to 1000000 in a file, except 765 and 777777 */
{
printf("writing test file\n");
int x = 0;
FILE * f = fopen("testfile.txt", "w");
for (x=0; x < 1000000; ++x){
if (x == 765 || x == 777760 || x == 777791){
continue;
}
fprintf(f, "%d\n", x);
}
fprintf(f, "%d\n", 57768); /* this one is a duplicate */
fclose(f);
}
uint32_t bitarray[1000000 / 32];
/* read file containing integers in the range [1,1000000] */
/* any non number is considered as separator */
/* the goal is to find missing numbers */
printf("Reading test file\n");
{
unsigned int x = 0;
FILE * f = fopen("testfile.txt", "r");
while (1 == fscanf(f, " %u",&x)){
bitarray[x / 32] |= 1 << (x % 32);
}
fclose(f);
}
/* find missing number in bitarray */
{
int x = 0;
for (x=0; x < (1000000 / 32) ; ++x){
int n = bitarray[x];
if (n != (uint32_t)-1){
printf("Missing number(s) between %d and %d [%x]\n",
x * 32, (x+1) * 32, bitarray[x]);
int b;
for (b = 0 ; b < 32 ; ++b){
if (0 == (n & (1 << b))){
printf("missing number is %d\n", x*32+b);
}
}
}
}
}
}
位數組或位向量可以是布爾值數組 。 通常,布爾變量至少需要存儲一個字節,但是在位數組/向量中僅需要一位。 如果您有很多這樣的數據,這將很方便,這樣可以節省大量內存。
另一種用法是,如果您的數字不完全適合 8、16、32或64位大小的標准變量 。 您可以通過這種方式將一個由4位組成的數字存儲到16位的位向量中,一個是2位,另一個是10位。 通常,您必須使用3個大小分別為8,8和16位的變量,因此浪費的存儲空間僅為50%。
但是所有這些用途很少在業務應用中使用,當通過pinvoke / interop功能連接驅動程序並執行低級編程時,經常會使用這些用途。
它用於位標志存儲,以及用於解析不同的二進制協議字段,其中1個字節被划分為多個位字段。 它廣泛用於TCP / IP等協議,高達ASN.1編碼,OpenPGP數據包等。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.