想起前段時間在做算法題的時候,評論區裏看到一條有趣的評論,原文是這樣的:“別看現在討論區裏各種秀優化,等到真正面試的時候,面試官讓你手寫個進制轉換你都得慌張”
哈哈,確實,平時做算法,考慮各種方法,想辦法提高效率,降低空間的消耗,但實際真正面試的時候,可能情急之下還是隻會拿出自己最熟悉的做法。
看到進制轉換,我不禁也驚了一下,要我短時間內寫出非常完美的代碼,肯定也是爲難的,而且一不留神,就會降低效率,增加空間的消耗,所以,我發現,這確實是個值得好好探究的問題。
談到進制轉換,第一印象是什麼,反正我當時腦子裏第一想的是棧,而且也只是一個模模糊糊的思路,感覺很急的情況下,難免會出現一些錯誤。
先不慌,我們看下JDK的大神們,是怎樣寫的。
假設進制轉換的原理大家都非常清楚了哦 ~ 不清楚的百度一下啦 ~
JDK11-Integer-toString方法
Integer類中有一個靜態方法:toString,其主要的作用就是進制轉換,看看它到底有何神奇之處~~~
- 註釋爲個人所寫。
/**註釋:ATFWUS
* 說明:返回用第二個參數指定基數表示的第一個參數的字符串表示形式。
* @param i 待轉換的十進制數
* @param radix 基數
* @return String
*/
public static String toString(int i, int radix) {
//如果基數小於 `Character.MIN_RADIX`(2) 或者大於 `Character.MAX_RADIX`(36),則改用基數 10。
**if (radix < 2 || radix > 36) {
radix = 10;
}
//基數等於10直接調用toString方法
if (radix == 10) {
return toString(i);
} else if (!String.COMPACT_STRINGS) {
return toStringUTF16(i, radix);//採用UTF16編碼的轉換
} else {
//buf數組存儲轉換後的結果
byte[] buf = new byte[33];
boolean negative = i < 0;
int charPos = 32;
//如果i大於0,也先轉換成負數,便於後續的轉換
if (!negative) {
i = -i;
}
//進制轉換核心代碼,對進製取餘後存入buf數組
while(i <= -radix) {
buf[charPos--] = (byte)digits[-(i % radix)];
i /= radix;
}
//最後還要進行一次轉換
buf[charPos] = (byte)digits[-i];
//如果i小於0,在結果的最前面加上負號
if (negative) {**
--charPos;
buf[charPos] = 45;
}
//返回buf數組的有效位數的字符串
return StringLatin1.newString(buf, charPos, 33 - charPos);
}
}
- 其中,上面的
digits
是Integer類中的常值數組。
static final char[] digits = new char[]{'0', '1', '2', '3', '4', '5', '6', '7',
'8', '9', 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n',
'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z'};
官方API說明:
-
public static String toString(int i, int radix)
-
參數:
- i - 要轉換成字符串的整數。
- radix - 用於字符串表示形式的基數。
-
返回值:
- String類型,使用指定基數的參數的字符串表示形式。
-
返回用第二個參數指定基數表示的第一個參數的字符串表示形式。
-
如果基數小於
Character.MIN_RADIX
或者大於Character.MAX_RADIX
,則改用基數 10。 -
如果第一個參數爲負,則結果中的第一個元素爲 ASCII 的減號
'-'
('\u002D'
)。如果第一個參數爲非負,則沒有符號字符出現在結果中。
逐行閱讀,欣賞JDK作者的編碼風格!
-
第一個判斷,判斷基數的有效性,如果超過指定的基數範圍,則返回原數字。
- 【數據有效性的判斷】
-
然後,如果基數爲10,直接調用將該數字轉換爲字符串的方法。
- 【特殊情況的考慮】
-
緊接着,就是正文了,若是其它基數,就開始進行轉換。
-
定義一個長度爲33的
buf
字節數組。-
爲什麼是字節數組?
- 因爲字節數組的大小是-128到+127,處理這些單個的數字足矣。
- 【合適數據類型的選取】
-
爲什麼長度是33?
- 因爲一個int類型的數據,轉換成二進制最多也才32位,再加上考慮符號的問題,設成33已經足夠滿足所有有效的轉換了。
- 【對數組大小的合理估計】
-
-
定義了一個
boolean
類型的negtive
,用於判斷i
是否小於0。- 【符號處理一】
-
定義了一個
charPos
,用於控制數組下標。(其實用byte也可以) -
如果
i
是正數,先將正數變成負數,方便後續統一的進行進制轉換。- 【符號處理二】
-
接下來就是進制轉換的核心部分了:
-
循環條件是:
i<=-radix
,這裏的i
始終是負數,radix
始終是正數 -
buf[charPos--] = (byte)digits[-(i % radix)];
- 【巧妙的利用一個靜態數組
digits
,使得任何進制的轉換統一化】。 - 【倒序存儲,模仿進制轉換棧原理】。
- 【巧妙的利用一個靜態數組
-
i /= radix;
,進制轉換的原理。
-
-
退出循環後,
i
的最後部分也需要加入byte數組。 -
如果
i
小於0,在最前面加上負號。(負號的ASCII碼爲45)- 【符號處理三】
-
最後將buf數組有效轉換成字符串輸出。
代碼看完了,怎麼樣?是不是發現JDK作者的這種編碼風格非常的好呀,非常嚴謹,對細節處理的非常到位,難怪說JDK源碼是java程序員的字典,確實,裏面有很多東西值得我們去思考!
- 以後面試官再讓你手寫進制轉換,直接默寫源碼!