1. Arrays 中的雙軸快排
Jdk 1.7 之後,工具類 Arrays
中的排序方法在排序對象爲基本數據類型的時候會使用雙軸快排
,這種排序方法比經典排序更快
public static void sort(int[] a) {
DualPivotQuicksort.sort(a, 0, a.length - 1, null, 0, 0);
}
如我們所知,經典快排
會挑一個數(Pivot)把數組分成兩份,而 Dual-Pivot
其實就是用兩個Pivot,把整個數組分成三份
經典快排核心思想
接受一個數組,挑一個數(Pivot),把比這個數小的那一攤數放在它的左邊,比它大的那一攤數放在它的右邊,然後再對這個數左右兩攤數遞歸的執行快排過程,直到子數組只剩一個數爲止
我們通常用時間複雜度
來衡量一個算法的性能,對於排序算法,時間複雜度的計算依據的是排序導致的元素比較的次數,主要和 CPU 相關。如果按照元素比較次數
來比較的話,其實雙軸快排
的元素比較次數比經典快排
要多,而雙軸快排
更快的原因如下,它擁有比經典快排更少的元素掃描動作
CPU速度和內存速度的不匹配
CPU速度遠比內存速度更快,因爲CPU會等待內存傳輸數據,內存牆(Memory Wall)的存在限制了程序運行速度。這種情況下,
元素比較次數
的多少已經無法完全反映算法優劣,因爲這種比較的方法只考慮了CPU的因素,沒有考慮內存的因素新的性能衡量標準:掃描元素個數
爲了解決時間複雜度無法反映算法真實性能的問題,雙軸排序的作者提出了新的衡量標準,即
掃描元素個數
。這種標準把對於數組裏面一個元素的訪問array[i]
稱爲一次掃描,對於同一個下標其對應的值不變的話,即使多次讀寫也只算一次掃描。這種標準實際反映的是CPU與內存之間的數據流量的大小,將比較慢的內存的因素也考慮進去了,更能體現算法在當下計算機裏面的性能
參考: https://arxiv.org/pdf/1511.01138.pdf
2. Java 中 switch 支持字符串的原理
一個 switch
的使用示例如下,代碼很簡單,我們無法獲知任何有關於其原理的信息,因爲這些都被隱藏在虛擬機的實現裏
public static void main(String[] args) {
String s = "nathan";
getString(s);
}
public static void getString(String s) {
switch (s) {
case "good":
System.out.println("good");
break;
case "ok":
System.out.println("ok");
break;
default:
System.out.println(s);
break;
}
}
編譯以上代碼,使用 IDEA 查看其 class 文件,立馬在其中發現端倪。從反編譯的文件中很明顯可以看到,switch 支持字符串是通過 equals() 和 hashCode() 方法來實現的
仔細看可以發現,進行 switch 的實際是字符串 hashCode() 方法返回的 int 類型哈希值,case 命中後通過 equals() 方法進一步進行安全檢查,以避免哈希碰撞導致的錯誤命中
其實 switch 底層只支持整型數據,比如 byte、short、char(ackii碼是整型)以及int,其他數據類型都是轉換成整型之後再使用的
public static void main(String[] args) {
String s = "nathan";
getString(s);
}
public static void getString(String s) {
byte var2 = -1;
switch(s.hashCode()) {
case 3548:
if (s.equals("ok")) {
var2 = 1;
}
break;
case 3178685:
if (s.equals("good")) {
var2 = 0;
}
}
switch(var2) {
case 0:
System.out.println("good");
break;
case 1:
System.out.println("ok");
break;
default:
System.out.println(s);
}
}