在文章以前我先抛出一个有趣的问题,相信有的同窗是看过的,没有看过的也不打紧儿,文章下面会进行解答。问题以下:数据库
如今有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,哎。