Brian Kernighan's Algorithm
Brian Kernighan's Algorithm是一種高效計(jì)算一個(gè)整數(shù)二進(jìn)制表示中1的個(gè)數(shù)的算法。它的基本思想是利用 x &= x-1
操作來(lái)消除一個(gè)整數(shù) x
的二進(jìn)制表示中最右邊的1。
算法的步驟如下:
初始化一個(gè)計(jì)數(shù)器
count
為0。當(dāng)
x
不等于0時(shí),執(zhí)行以下操作:執(zhí)行
x &= x-1
,將x
中最右邊的1及其右邊的所有位都置為0。將計(jì)數(shù)器
count
加1。返回計(jì)數(shù)器
count
的值,即二進(jìn)制表示中1的個(gè)數(shù)。
該算法的原理是,每次執(zhí)行 x &= x-1
操作,都會(huì)消除 x
中最右邊的1,并且僅有該位變?yōu)?,而其他位保持不變。通過(guò)重復(fù)執(zhí)行這個(gè)操作直到 x
變?yōu)?,就能統(tǒng)計(jì)出二進(jìn)制表示中1的個(gè)數(shù)。
相比于遍歷所有的位數(shù)進(jìn)行判斷,Brian Kernighan's Algorithm的優(yōu)勢(shì)在于,它只需要執(zhí)行與1的個(gè)數(shù)相等的循環(huán)次數(shù),即執(zhí)行次數(shù)等于二進(jìn)制表示中1的個(gè)數(shù)。這使得該算法在時(shí)間復(fù)雜度上更加高效。
這個(gè)算法以Brian Kernighan的名字命名,因?yàn)樗?988年的《The C Programming Language》一書(shū)中介紹了這種方法,用于計(jì)算一個(gè)整數(shù)的二進(jìn)制表示中1的個(gè)數(shù)。

在這個(gè)代碼中,我們使用 num &= (num - 1)
的操作來(lái)清除 num
的二進(jìn)制表示中最右邊的一個(gè)1。通過(guò)重復(fù)執(zhí)行這個(gè)操作直到 num
變?yōu)?,我們可以計(jì)算出二進(jìn)制表示中1的個(gè)數(shù)。
每次執(zhí)行 num &= (num - 1)
時(shí),都會(huì)將 num
中最右邊的1及其右邊的所有位都置為0,因?yàn)?(num - 1)
將最右邊的1變?yōu)?,而該1右邊的所有位都變?yōu)?,然后與原來(lái)的 num
進(jìn)行與運(yùn)算,結(jié)果就是將最右邊的1及其右邊的所有位都置為0。重復(fù)這個(gè)操作直到 num
變?yōu)?,就能計(jì)算出二進(jìn)制表示中1的個(gè)數(shù)。
這種方法的優(yōu)勢(shì)在于,對(duì)于有多少個(gè)1的問(wèn)題,只需要執(zhí)行相應(yīng)數(shù)量的循環(huán)次數(shù),而不是遍歷所有的位數(shù)。這使得該方法在時(shí)間復(fù)雜度上更加高效。

在這個(gè)修改后的代碼中,我們使用了一個(gè)無(wú)符號(hào)整數(shù)變量mask
來(lái)進(jìn)行左移操作。循環(huán)中,我們檢查num
與mask
的與運(yùn)算結(jié)果,如果結(jié)果為非零,則說(shuō)明對(duì)應(yīng)位是1,將計(jì)數(shù)器加1。然后,將mask
左移1位,繼續(xù)下一次循環(huán)。循環(huán)終止的條件是mask
變?yōu)?,即所有位都被檢查過(guò)。
需要注意的是,為了避免負(fù)數(shù)左移導(dǎo)致的問(wèn)題,我們將mask
聲明為無(wú)符號(hào)整數(shù)。這樣,在左移操作中,高位會(huì)自動(dòng)補(bǔ)0,而不是補(bǔ)1。這樣可以確保計(jì)數(shù)結(jié)果正確,無(wú)論輸入的整數(shù)是正數(shù)還是負(fù)數(shù)。

在這個(gè)程序中,countOnes
函數(shù)接受一個(gè)整數(shù)作為輸入,然后通過(guò)不斷右移這個(gè)整數(shù)并檢查最低位是否為1來(lái)計(jì)算1的個(gè)數(shù)。在每次循環(huán)中,使用位運(yùn)算符&
來(lái)檢查最低位是否為1,如果是則計(jì)數(shù)器加1。然后將整數(shù)右移1位,繼續(xù)下一次循環(huán),直到整數(shù)變?yōu)?為止。
在main
函數(shù)中,首先獲取用戶輸入的整數(shù),然后調(diào)用countOnes
函數(shù)計(jì)算二進(jìn)制表示中1的個(gè)數(shù),并將結(jié)果打印出來(lái)。
請(qǐng)注意,這個(gè)方法是一種常見(jiàn)的解決方案,但是對(duì)于負(fù)數(shù),右移操作可能會(huì)引入高位補(bǔ)1的情況,導(dǎo)致計(jì)數(shù)結(jié)果不正確。如果需要計(jì)算負(fù)數(shù)的二進(jìn)制表示中1的個(gè)數(shù),可以使用位運(yùn)算和循環(huán)來(lái)處理特殊情況。