收集的各種位運算

2021-06-22 12:14:56 字數 2974 閱讀 6683

由樹狀陣列得到的位運算:

lowbit(x):用於獲得數x在二進位制形式下的最低位的1,比如12的二進位制是1100,lowbit(12) = 4。lowbit(x) = x&(x^(x-1)) = x&(-x);

下面是《**之美》裡面用於統計數二進位制下有多少個1的各種**。

從最基本的,數都在32位內。

ans = 0;

for(int i = 0;i < 32;i ++)

每次都要遍歷32位。

下面的**在矩陣快速冪裡面有用到

ans = 0

while(x)

這個**最大迭代次數為最高位1的位置。

下面的**的統計次數就是1的個數

ans = 0

while(x)

手動分析下就明白了,比如8的二進位制1000,8-1就是0111,做一下與運算,就是0了,就消去了最後一位的1。

下面是乙個lightoj的題目 **:

該題目的實現演算法是:首先把數的低位的連續一進製,然後把比進製低的後面的1全都挪向最低位,以下都是二進位制,比如1100,最低位的連續1是11進製後是10000,進製前有1個1,挪到最後是10001。輸出10進製的答案。

演算法就是這樣的,實現有各種方法。

下面的實現比較樸素

#include #include #include #include using namespace std;

int big[34];

bool cmp(int a,int b)

int main()

int lt;

for(int i = 0;i < 32;i ++)

if(big[i] == 1 && big[i + 1] == 0 )

sort(big,big+lt,cmp);

long long ans = 0;

for(int i = 0;i <= 32;i ++)

if(big[i])ans += 1ll《把二進位制提取到陣列裡面找到有連續1的一段,排序,使得連續1都到低位去。然後把重組後的陣列變回十進位制。不僅空間大,而且比較慢。

下面的乙個實現複雜度跟末尾連續1的個數有關:

#include int main()

return 0;

}

x為最低位的1,lowbit(n+x)是進製後的最低位1,減去之前最低位的1(就是除法,相當於移位),就是這之間的1個數,減1獲得全部的1,由於進製有了乙個1,右移一位減去乙個1,n += x進製後,將低位的1或進去就是答案了。

位運算主要用處是快和節省空間,bitmap就是乙個應用,在另一篇文章有寫實現:

乙個用位運算篩素數也是乙個應用,其實跟bitmap原理差不多,通過位進行標記。在網上意外找到一些位運算篩素數**。。。。剛開始都看不懂,現在終於懂了:

const int n = 1666666

int np[n>>6],prm[n],pn;

void getprm1() }}

}

-_-雖然看起來很酷炫,其實還是可以看懂的(看了好久。。。。)。我來說明下,這個篩素數比一般的線性曬素數有點不一樣,由於素數除了2之外都是偶數(很容易想的,素數定義是除了1和自己沒別的約數,大於2的偶數肯定有2這個約數)。

所以這個**只是遍歷奇數從3開始的奇數裡面找質數,所以後面是兩個連續的i++(可以寫i+=2)這是第一層迴圈。

判斷語句裡面np[i>>6]是先找到大的區間,後面的按照bitmap裡面的思想應該是np[i>>6] &(1<<(i&63),這裡是怎麼回事呢?由於i一定是奇數,奇數二進位制最後一位一定是1,所以i右移一位不影響對於乙個數的標記,少了一位的餘數當然是跟31做按位與運算。

另一點是不能用1<<(i&63)因為2的30多次方就整型越界了,但是1<<31也會越界所以應該換成1ll<<31,而1ll<<63long long也會越界。雖然1ll<<31與int型別按位與也會使得陣列值越界,但是我們使用的是陣列元素裡面的位,越界只是改變了符號位使得輸出變為負數(這裡不需要輸出值),對應二進位制位的值是不變的,所以沒有影響。

這**對位做了充分的利用,不浪費,也可以降低篩素數時用的額外空間。

第二層迴圈裡面j開始是從3倍的i開始的,因為2倍的肯定是偶數,跳過,不寫3*i是因為乘法比加法慢很多,位運算和加法會快很多,(i>>1)+i相當於乘2並加1個i,再看後面的j += (i << 1)每次加的是i的2倍不是i,這也是為了避免遍歷偶數,因為j開始是3i,如果加奇數個i就會得到偶數倍的i,所以要加偶數倍的i,下面就是用或運算為非素數做一下標記。

下面的是用位運算實現除法,儘管做一次加法比一次除法要快很多,但是由於用了很多加法,速度反而慢很多,在自己機器上通過乙個比較大的數除以乙個較小數,迭代執行1000000次,檢測得到一次除法僅用3ms,而位運算實現的需要680多ms。不過思路還是可以借鑑的。

int integer_div_1(int dividend, int divisor,int sum = 0)

比之前找到的稍微改了點,主體思路沒變。

如果除數是0,除非無意義,列印警告,異常退出。

這個演算法思路是這樣的:把被除數寫成2^k×除數的和的形式,如果總剩餘小於除數當然是0,結果符合計算機的整數除法。

下面看看這個巨集定義:

#define _intsizeof(n)	( (sizeof(n) + sizeof(int) - 1) & ~(sizeof(int) - 1) )
作用就是求n的型別所佔位元組最接近4的倍數的位元組數,就是位元組對齊。比如3,最接近的且大於它的(如果小於就肯定存不下了)數是4。因為int佔位元組數是4,所以說是4的倍數,後面部分就是&~3,這部分的作用是去除模4後的餘數。如果sizeof(n)已經是4的倍數了,那麼加了乙個3,去除模還是原來的4的倍數不變,如果不是的話,這個數至多加3就可以達到最近的大於它的4的倍數,至於多餘的數就被後面的運算去除餘數了,同樣可以得到乙個最近的4的倍數。

各種小馬收集

asp eval request sb execute request sb execute request sb execute request sb loop loop execute request sb execute request sb loop code code execute re...

位運算 57 普通的位運算

要求說明 當 a 2,b 4,c 6,d 8時程式設計求a c b d a d a的值。解 單目運算子 都是對對應整數轉化成二進位制數後按位比較計算 兩個相應二進位中,都為1,該位為1,否則為0 兩個相應二進位中,有乙個1,該位為1,否則為0 兩個相應二進位,相同為0,不同為1 單目運算子,作用對二...

各種排序演算法收集

排序演算法是一種基本並且常用的演算法。由於實際工作中處理的數量巨大,所以排序演算法 對演算法本身的速度要求很高。而一般我們所謂的演算法的效能主要是指演算法的複雜度,一般用o方法來表示。在後面我將 給出詳細的說明。對於排序的演算法我想先做一點簡單的介紹,也是給這篇文章理乙個提綱。我將按照演算法的複雜度...