使用二进制和位移运算实现简单的算法

1.将一个二进制数向左位移n位就等于该数乘以2的n次方,当乘法运算中的某个数符合这个特点的时候,可以用位移运算代替乘法运算,从而提高效率。

package pp.suanfa;

/**
 * 乘法运算转位移运算
 * 
 * @author xiaoGd
 *
 */

public class MulAndShift {
	
	public static int isPower(int m,int n)//m乘以2的n次方
	{
		for(int i=0;i<n;i++)//将m向左位移n位
		{
			m = m<<1;
		}
		return m;
	}
	
	public static void main(String[] args) {
		
		System.out.println("3乘以8等于:"+isPower(3, 3));
		System.out.println("4乘以4等于:"+isPower(4, 2));
	}

}

2.判断一个数是否是2的n次方

2的n次方转换成数学表达式:2^0,2^1,2^2,2^3……,在二进制数中,最小的为0001,接下来依次为0010,0100,1000,因此每次都是将1向左位移,可以以1为基准数,每次向左移一位之后进行比较,判断与给出的数是否相等:

package pp.suanfa;

/**
 * 判断一个数是否是2的n次方
 * 
 * @author xiaoGd
 *
 */

public class NSubSquareOfTwo {
	
	public static boolean isPower(int n)
	{
		if(n<1)return false;//当n不满足条件时返回false
		int i = 1;//设立基准数1
		while(i<=n)//循环位移
		{
			if(i==n)//每次判断i和n是否相等
				return true;
			i=i<<1;//向左位移一位
		}
		return false;//条件不满足返回false
	}
	
	public static void main(String[] args) {
		
		System.out.println(isPower(36));
		System.out.println(isPower(64));
	}

}

因为是二进制位移,上述办法的时间复杂度为O(logn),还有一种很巧妙的办法,效率也更高,通过观察不难发现,是2的n次方的数转化成二进制之后都只有一位是1,其余各位都是0,若将其减一,则减一之后的数用二进制表示每一位都和原来的数不相同,例如:8的二进制位1000,减一之后7的二进制为0111,其余的数也都符合这个特点,可以利用这个特点结合与运算进行判断:

public class NSubSquareOfTwo {
//通过减一和“与”运算进行判断
	public static boolean isPC(int n)
	{
		if(n<1) return false;
		int m = n&(n-1);
		return m==0;//若每位上的数字都不相同,则该数为2的n次方
	}
        public static void main(String[] args) {
		System.out.println(isPC(1024));
		System.out.println(isPC(1056));
	}

}

3.求二进制数中1的个数

问题描述:给定一个整数,输出这个整数的二进制数中1的个数,例如,给定整数7,其二进制表示为111,一次输出结果为3.

首先想到的是这道题可以通过位移操作来完成,判断该数的二进制数的最后一位是否为1,若为1,计数器加1,向右位移1位,若不为1,计数器不改变,向右位移一位,直到该数小于1为止。

package pp.suanfa;

/**
 * 求二进制数中1的个数
 * 
 * @author xiaoGd
 *
 */

public class NumberOfOne {
	
	public static int isPower(int n)
	{
		int count = 0;//计数器
		while(n>0)
		{
			if((n&1)==1)//判断最后一位是否是1
			{
				count++;
			}
			n>>=1;//向右位移一位
		}
		return count;
	}
	
	public static void main(String[] args) {
		
		System.out.println("7的二进制中有"+isPower(7)+"个1");
		System.out.println("8的二进制中有"+isPower(8)+"个1");
	}

}

以上算法的时间复杂度为O(n),其中n代表二进制数的位数,另一种办法,也和减一有关,因为我们只需要求二进制中1的个数,可以把二进制表示中每个1看作独立的个体。给定一个数n,每进行一次n&(n-1)运算,其结果都会少了一位1,而且是最后一位1,利用这个特点可以编写如下代码:

public class NumberOfOne {
    public static int isNO(int n)
	{
		int count = 0;
		while(n>0)
		{
			if(n!=0)//判断最后一位是否是1
			n = n&(n-1);
			count++;
		}
		return count;
	}
	
	public static void main(String[] args) {
		System.out.println("7的二进制中有"+isNO(7)+"个1");
		System.out.println("8的二进制中有"+isNO(8)+"个1");
	}

}

这种方法的时间复杂度为O(m),m为二进制中1的个数。

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