《編程之美》讀書筆記1——求二進制數中1的個數

前言:又到了一週一次的寫博客環節了,嗯···沒什麼存貨了,上一週沒有看多少關於數據結構的內容,也沒記什麼筆記;我掙扎了一下,想停更一週,但是好不容易堅持了9周,一定要堅持到今年考研結束,甚至堅持到以後。我決定借鑑一下上次湊單買的《編程之美》的一個關於位運算的案列,“水”一期博客。

一、問題提出

  • 對於一個字節(8bit)的無符號整型變量,求其二進制表示中"1"的個數
  • 相關概念補充:1字節包含8位,C語言用字節(byte)表示存儲系統字符集所需的大小(注意:計算機界通常用默認一字節是8位的)。如下圖所示,從左往右給這八位分別編號7~0。在1字節中,編號爲7的位被稱爲高階位,編號是0的位被稱爲低階位;每一位對應的編號對應2相應的指數。

位編號和位值

  • 這裏,128是2的7次冪,以此類推;該字節能表示的最大數字都設置爲1:11111111.則這個二進制數的值爲:
  • 128 + 64 + 32+ 16 + 8 + 4+ 2 +1 = 256
  • 而該字節最小的二進制數是00000000,其值是0;因此,一字節可以存儲0~255範圍內的數字,共256個。

二、分析與解法
1、解法一;O(log2v)

  • 對於二進制操作,每除一個2,原來的數字將會減少一個0,如果除的過程有餘,就表示當前位置有一個1;
  • 以10100010爲例:
  • 第一次除2,商爲1010001,餘0;
  • 第二次除2,商101000,於1.
  • 因此,可以根據上述特點,讓一個二進制數依次除以2,判斷餘數是否爲1來計數1的個數。
int count(byte v)
{
	int num = 0;
	while(v)
	{
		if(v%2 ==1)
		{
			num++;
		}
		v = v/2;
	}
	return num;
}

2、解法二;O(log2v)

  • 使用向右移的位操作同樣可以達到相除的效果,這裏的問題是如何判斷是否有1處在?
  • 解決方法,用該八位數與00000001相”與",如果結果爲1,則表示當前的八位數最後一位是1,否則爲0.
int count(byte v)
{
	int num = 0;
	while(v)
	{
		num + = v & 0x01;
		v >>= 1;    //v每位數字向右移動1
	}
	return num;
}

3、解法三;O(M)M爲1的個數

  • 前面兩個解法,都需要經過8次相除或者移位來累計1的個數,能不能只考慮1所在的位置,跳過0的位置,來直接累計呢?
  • 假設只有一個1:01000000;
  • 判斷操作爲:01000000&(01000000 - 00000001) =01000000&00111111 =0;
  • 即通過v直接減1跳過0所在的位
int count(byte v)
{
	int num = 0;
	while(v)
	{
		v &= (v-1);
		num++;
	}
	return num;
}

4、解法4;O(1)
以空間換時間,直接將八位二進制數所有的可能情況預先算出寫入表中,遇到時直接查詢即可,適用於頻繁使用的算法中;

/* 預定義結果表 */
int countTable[256] =
{
	0,1,2...//懶得打字了
	...
	...
};
int count(byte v)
{
//查表
return countTable[v];
}

解法1和2很多人都想得到,而3、4可能有少數老哥能想到,這也許是靈機一動的頭腦風暴,但是大多數因該是見多識廣的經驗使然。
結束——

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章