在文章以前我先拋出一個有趣的問題,相信有的同窗是看過的,沒有看過的也不打緊兒,文章下面會進行解答。問題以下:數據庫
如今有1000個瓶子,裏面999瓶是水,1瓶是毒藥。最少經過多少次的試驗,能肯定哪瓶是毒藥。編程
這個問題能夠先行思考一下,我說一說最近在生活中遇到的另外一間相關的事。安全
前段時間在設計一張數據表的時候遇到了一個小問題。狀況是這樣的,一條數據有着三種狀態,這三種狀態是可能疊加而且重複的。什麼意思呢?我舉一個通俗的例子來類比一下。編程語言
孔子曰:吾日三省吾身。高乎?帥乎?富乎?高、富、帥能夠說是一我的的三種狀態。好比經過「骨骼生長」這個函數的處理,人能夠擁有「高」這個狀態;經過「自我打理、運動健身」這個函數的處理,人能夠擁有「帥」這個狀態;經過「發奮圖強」這個函數的處理,人能夠擁有「富」這個狀態。什麼是疊加?就是一我的能夠擁有其中的多種狀態;什麼是重複?好比一我的屢次「奮發圖強」,依然會擁有「富」的狀態。函數
解釋完這些,再回到問題自己。我當時想的是,給每一個狀態一個單獨的布爾類型(能夠判斷真或假)的字段,而後在進行處理時對相應狀態進行分別判斷。這樣雖然也能完成任務,可是顯得笨重且不優雅。舉兩個顯而易見的例子:優化
針對這些問題,X叔(組裏一位我很敬重的老哥)建議我能夠用一個籠統的字段status
,而後每種狀態的值能夠設置爲一、二、4...這樣。我心想,妙啊。設計
多重狀態疊加產生的值是不會產生重複的,好比「高富」=3,「高帥」=5,「富帥」=6等等。並且之後有新的狀態,假設新增「健康」這些,到時候,直接約定爲相應值八、16等等。3d
那這和位運算有什麼關係呢?咱們來看下面這張圖。code
而在重複處理方面,位與運算帶來了更加簡潔的操做。舉個例子,假如當前狀態時是「高帥」,須要再次進行「帥」處理,若是按照傳統的加減方式,須要判斷當前有沒有「帥」這個狀態4,有的話不加,沒有的話加上4。這無疑是很是繁瑣的。cdn
使用位與,會簡潔不少,好比:
很方便。在進行位或的時候也是如此,能夠結合具體狀況試一試。
除此以外,在一些編程語言的源碼裏,常常會用到位運算,由於它不只高效,並且有時候更靈活。好比JDK8裏在優化HashMap的擴容時,將取模運算換成了位運算。能夠參考上篇滴滴好用,可是不安全。HashMap:我也是。
解決了這個問題。回頭看看文章開頭的智力題。
能夠先公佈一下答案:10。
假設如今有十隻小白鼠,如何10只小白鼠的生死來找出那一瓶毒藥呢?咱們先將1000個瓶子用二進制編號,就像下圖:
從000000001-1111111111,表明1號到1024號(1001-1024個瓶子能夠忽視,由於只須要1000個),能夠看到,每一個數都有十位,那麼咱們讓每隻小白鼠負責一列,將這一列的編號出現1的瓶子中的液體混合着喝下去。若是某隻小白鼠死了那麼能夠斷定這列爲1的全部瓶子中,有一瓶是毒藥。經過十隻小白鼠的生死狀況組合來看,不難發現那瓶是毒藥的瓶子編號。
若是你以爲數量太大,有些納悶,能夠減小數量,假設總共共有八個瓶子,其中一瓶是毒藥。仔經過這種方式來計算一下。
使用位運算來吾日三省吾身,天天都是4,哎。