1. 程式人生 > >java使用移位運算進行進位制轉化

java使用移位運算進行進位制轉化

最近在練習進位制轉換演算法,學習了一種使用移位運算進行進位制的方法分享給大家。

  • 16進位制轉換8進位制
        問題描述:
        輸入格式
            輸入的第一行為一個正整數n (1<=n<=10)。
            接下來n行,每行一個由0~9、大寫字母A~F組成的字串,
            表示要轉換的十六進位制正整數,每個十六進位制數長度不超過100000。
        輸出格式
            輸出n行,每行為輸入對應的八進位制正整數。
        注意
            輸入的十六進位制數不會有前導0,比如012
A。輸出的八進位制數也不能有前導0。 樣例輸入 239123ABC 樣例 71 4435274

我一開始的解法,1個16進位制數可以轉化為4個2進位制數,再通過每3個二進位制數可以轉化為1個8進位制數。不過有一點需要注意轉化成8進位制數要從2進位制字串後面開始,到最前面時需要判斷還剩下幾位,不夠3位要補0。

package 十六進位制轉八進位制;

import java.text.DecimalFormat;
import java.util.Scanner;
import java.util.Stack;
public
class Main { static Scanner scan = new Scanner(System.in); static DecimalFormat decimalFormat=new DecimalFormat("0000"); static DecimalFormat d2=new DecimalFormat("000"); public static void change(String str){ String s = ""; int top = 0; char[] c = str.toCharArray(); for
(int k = 0; k < c.length; k++) { if (c[k] >= '0' && c[k] <= '9') { s+=decimalFormat.format(Integer.parseInt(Integer.toBinaryString(c[k]-48))); }else if(c[k] >= 'A' && c[k] <= 'F'){ s+=decimalFormat.format(Integer.parseInt(Integer.toBinaryString(c[k]-55))); } } int num = s.length(); if(num%3==1) s="00"+s; else if(num%3==2) s="0"+s; if(s.substring(0, 3).equals("000")){ s=s.substring(3); } for (int i = 0; i < s.length(); i=i+3) { String xStr = s.substring(i,i+3); System.out.print(Integer.parseInt(xStr.substring(0,1))*4+ Integer.parseInt(xStr.substring(1,2))*2+ Integer.parseInt(xStr.substring(2,3))*1); } } public static void main(String[] args) { int n = Integer.parseInt(scan.nextLine()); String[] strs = new String[n]; for (int i = 0; i < strs.length; i++) { strs[i] = scan.nextLine(); } for (int i = 0; i < strs.length; i++) { change(strs[i]); System.out.println(); } } }

使用題目給的測試可以通過,我自己設定的測試資料也可以通過,然後去藍橋杯測試平臺上跑結果炸了!去看測試資料,10個16進位制數,最長的10萬位,估計是溢位了。去除錯發現是在2進位制轉化為8進位制的時候出錯了,for迴圈次數太多了。for裡還有數值運算比較費時,改了好久測試總是通不過。去百度發現一種運用java移位運算進行轉化的,寫了試了一下發現可以通過了。

使用java移位運算子進行轉化
import java.util.Scanner;
public class Main {
 public static void main(String[] args) {
     new Main().systemScanner();
 }
 public void systemScanner() {
     Scanner jin = new Scanner(System.in);
     while (jin.hasNext()) {
         int length = jin.nextInt();
         for (int i = 0; i < length; i++){
             String strTmp=jin.next();
             tranform(strTmp.toCharArray(), strTmp.length());
         }
     }
 }
 /*
  * 3位16進位制等價於4位8進位制
  */
 int[] stack=new int[40000];
 public void tranform(char[] str, int length) {
     char[] buff = new char[4];
     int top = -1;
     for (int i = length - 1; i >= 0; i -= 3) {
         int sum = 0;
         for (int j = 0; j < 3 && i - j >= 0; j++) {// i-j>=0防止不夠三個的情況
             int tmp = str[i - j] >= '0' && str[i - j] <= '9' ? str[i - j] - '0': str[i - j] - 'A' + 10;//區分是數字,還是字元,進行對應轉換
             sum+=(tmp<<(4*j));//這句很重要,通過這句就可以從16變成10進位制了。
         }
         stack[++top]=sum;//sum的結果是16進位制轉化10進位制的結果,每3個16進制變成10進位制,再變8進位制
     }
     while(stack[top]==0){//排除前導為0的判斷
         top--;
     }
     for(int i=top;i>=0;i--){
         String str1=Integer.toOctalString(stack[i]);//從10進位制轉化成8進位制
         if(i!=top&&str1.length()<4){
             //不是最左邊的一個,就不用去掉前導0,而預設是去掉0的,所以要進行補會
             for(int y=0;y<4-str1.length();y++)
                 System.out.print("0");
         }
         System.out.print(str1);
     }
     System.out.println();
     }
}

這種解法的思路是:1位16進位制可以代表4位2進位制, 1位8進位制可以代表3位二進位制,得出3位16進位制求和入棧輸出表示4位8進位制,然後出棧輸出。由16進位制轉化為10進位制的時候,使用 << 使16進位制數轉化為8進位制。

例子:

0x11 << 4 => 17;

/*
11的二進位制編碼是 1011,個位是1 編碼是0001,十位是1 編碼也是0001。
根據位數進行移位運算,個位左移(4*0)位還是0001,十位左移(4*1)位變成00010000
*/

0001 << 4*1 = 00010000; 0001 << 4*0 = 0001;

/*
整個數就變成了00010001 也就是10001 轉換為10進位制是為17。這裡可以看到一個16進
制數通過按位數分別左移4*(n-1)位就可以轉化為10進位制數了。具體的原因是每一個整
數左移4位等於這數的二進位制表示後面多了4個0,相當於2進位制乘法乘了一個二進位制10000()。
*/
1*16^1+1*16^0 = 17;
/*
10000轉化為10進製為16也就是每位乘了16^(n-1)進而把一個16進位制數轉化為10進位制數。
*/

這種演算法的效率非常高,運算十分較少。可以通過藍橋杯測試系統的變態資料。