1. 程式人生 > >使用二進位制和位移運算實現簡單的演算法

使用二進位制和位移運算實現簡單的演算法

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的個數。