码迷,mamicode.com
首页 > 其他好文 > 详细

9.5位操作(三)——给定一个正整数,找出与其二进制表示中1的个数相同,且大小最接近的那两个数

时间:2015-08-06 13:17:24      阅读:236      评论:0      收藏:0      [点我收藏+]

标签:java   数据结构   算法   位操作   二进制   

/**
 * 功能:给定一个正整数,找出与其二进制表示中1的个数相同,且大小最接近的那两个数。
 * (一个略大一个略小。)
 */

三种方法:
方法一:蛮力法

方法二:位操作法
<span style="white-space:pre">	</span>/**
	 * 方法:位操作法
	 * 思路:获取后一个较大的数
	 * 		1)计算c0和c1。c1是拖尾1的个数,c0是紧邻拖尾1的作坊一连串0的个数。
	 * 		2)将最右边、非拖尾0变为1,其位置为p=c1+c0。
	 * 		3)将位p右边的所有位清零。
	 * 		4)在紧邻位置p的右方,插入c1-1个1。
	 * @param n
	 * @return
	 */
	public static int getNext(int n){
		int c=n;
		int c0=0;
		int c1=0;
		
		while((c&1)==0&&(c!=0)){
			c0++;
			c>>=1;
		}
		
		while((c&1)==1){
			c1++;
			c>>=1;
		}
		
		if(c0+c1==31||c0+c1==0)//c0+c1+1=32,1表示p所在位。
			return -1;
		
		int p=c0+c1;//最右边处,非拖尾0的位置。
		n|=(1<<p);//翻转0为1
		n&=~((1<<p)-1);//将p右边的所有位清零
		n|=(1<<(c1-1))-1;//在右边填入(c1-1)个1
		
		return n;
	}
	
	/**
	 * 思路:获取前一个较小的数
	 * 		1)计算c0和c1。c1是拖尾1的个数,c0是紧邻拖尾1的作坊一连串0的个数。
	 * 		2)将最右边、非拖尾1变为0,其位置为p=c1+c0。
	 * 		3)将位p右边的所有位清零。
	 * 		4)在紧邻位置p的右方,插入c1+1个1。
	 * 		注意:步骤2和3可以合并。
	 * @param n
	 * @return
	 */
	public static int getPrev(int n){
		int c=n;
		int c0=0;
		int c1=0;
		
		while((c&1)==1){
			c1++;
			c>>=1;
		}
		
		if(c==0)
			return -1;//错误检查!!!全为1时,无法找到
		
		while((c&1)==0&&(c!=0)){
			c0++;
			c>>=1;
		}
		
		int p=c0+c1;
		n&=~((1<<(p+1))-1);//将最右边、非拖尾1变为0,其位置为p=c1+c0;将位p右边的所有位清零。
		int mask=(1<<(c1+1))-1;//在紧邻(!!!)位置p的右方,插入c1+1个1。
		n|=mask<<(c0-1);
		
		return n;
	}

方法三:算术法
<span style="white-space:pre">	</span>/**
	 * 方法:算术法
	 * 思路:获取后一个较大的数,重新表述问题
	 * 		1)计算c0和c1。c1是拖尾1的个数,c0是紧邻拖尾1的作坊一连串0的个数。
	 * 		2)将p位置1。
	 * 		3)将位p右边的所有位清零。
	 * 		4)在紧邻位置p的右方,插入c1-1个1。
	 * 步骤2,3有一种快速做法,将拖尾0置为1(得到p个拖尾1),然后再加1。加1后,所有拖尾1都会翻转,最终位p变为1,后边跟p个0.
	 * @param n
	 * @return
	 */
	public static int getNextArith(int n){
		int c=n;
		int c0=0;
		int c1=1;
		
		while((c0&1)==0&&(c!=0)){
			c0++;
			c>>=1;
		}
		
		while((c1&1)==1){
			c1++;
			c>>=1;
		}
		
		if(c0+c1==31||c0+c1==0)
			return -1;
		
		//将拖尾0置1,得到p个拖尾1
		n|=(1<<c0)-1;
		//先将p个1清零,然后位p改为1
		n+=1;
		//在右边填入(c1-1)个1
		n|=(1<<(c1-1))-1;
		
		return n;
	}
	/**
	 * 方法:算术法
	 * 思路:获取前一个较小的数,重新表述问题
	 * 		1)计算c0和c1。c1是拖尾1的个数,c0是紧邻拖尾1的作坊一连串0的个数。
	 * 		2)将p位清零。
	 * 		3)将位p右边的所有位置1。
	 * 		4)将位0到位c0-1清零。
	 * @param n
	 * @return
	 */
	public static int getPrevArith(int n){
		int c=n;
		int c0=0;
		int c1=0;
		
		while((c&1)==1){
			c1++;
			c>>=1;
		}
		
		while((c&1)==0&&(c!=0)){
			c0++;
			c>>=1;
		}
		
		if(c==0)
			return -1;//错误检查!!!全为1时,无法找到
		
		n-=(1<<c1)-1;//清除拖尾1,此时p位为1,后面全部为零
		n-=1;//将p为置0,后面所有位置置1
		n&=~(1<<(c0-1)-1);//将最后边置c0-1个0
		
		return n;
	}


版权声明:本文为博主原创文章,未经博主允许不得转载。

9.5位操作(三)——给定一个正整数,找出与其二进制表示中1的个数相同,且大小最接近的那两个数

标签:java   数据结构   算法   位操作   二进制   

原文地址:http://blog.csdn.net/shangqing1123/article/details/47314713

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!