面試官讓你手寫進制轉換?看看JDK的大神是怎麼寫的!

想起前段時間在做算法題的時候,評論區裏看到一條有趣的評論,原文是這樣的:“別看現在討論區裏各種秀優化,等到真正面試的時候,面試官讓你手寫個進制轉換你都得慌張

哈哈,確實,平時做算法,考慮各種方法,想辦法提高效率,降低空間的消耗,但實際真正面試的時候,可能情急之下還是隻會拿出自己最熟悉的做法。

看到進制轉換,我不禁也驚了一下,要我短時間內寫出非常完美的代碼,肯定也是爲難的,而且一不留神,就會降低效率,增加空間的消耗,所以,我發現,這確實是個值得好好探究的問題。

談到進制轉換,第一印象是什麼,反正我當時腦子裏第一想的是棧,而且也只是一個模模糊糊的思路,感覺很急的情況下,難免會出現一些錯誤。

先不慌,我們看下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程序員的字典,確實,裏面有很多東西值得我們去思考!

  • 以後面試官再讓你手寫進制轉換,直接默寫源碼!
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章