成人免费xxxxx在线视频软件_久久精品久久久_亚洲国产精品久久久_天天色天天色_亚洲人成一区_欧美一级欧美三级在线观看

第一次面試,我差點被面試官打,就因為Collections.sort

開發 前端
該篇文章主要分享隱藏在Collections.sort()中的坑,有興趣的看看,已經知道的可以無視。

[[409387]]

本文轉載自微信公眾號「稀飯下雪」,作者帥氣的小飯飯。轉載本文請聯系稀飯下雪公眾號。

該篇文章主要分享隱藏在Collections.sort()中的坑,有興趣的看看,已經知道的可以無視。

是這樣的,今天在review鄧老弟的代碼的時候,看到一段這樣的實現

大家先看看這種寫法有沒有問題?

覺得沒有問題的hxd們就要好好看這篇文章了。

我記得那是三年前的一個下雨天,那雨下的比依萍回陸家拿生活費那天還大

[[409388]]

依萍

我顫顫巍巍的走進了一家辦公室,腳步沉重,畢竟這是我第一次面試

「底氣不足的小飯飯:」 你好,我是小飯飯,我是來面試的

[[409389]]

瘦小的我

「彪形大漢:」 小李是吧,坐

[[409390]]

一面面試官

我是xxx公司的面試官斯坦森,看你簡歷還不錯,很少會有實習生敢寫精通java的,來,我考考你

這么寫有什么問題嗎?

「底氣不足的小飯飯:」 臥槽,竟然還有姓斯的,不過還好,這道題不難 (⊙o⊙)…

這很簡單,updateTime1和updateTime2都是long類型,用int強轉有可能導致溢出

「彪形大漢:」 嗯,對,還有呢

繼續說下去

「底氣不足的小飯飯:」 還有?我想想看

還有就是這樣會導致排序出現混亂,可能導致大的在前面

「彪形大漢:」 嗯,對,還有呢

「底氣不足的小飯飯:」 還有?沒有了啊,其他的我不知道了

「彪形大漢:」 嗯,你能答出前兩個,對Java的了解算是熟悉了,不過還沒達到精通的程度

還有一個問題,當溢出的時候被int強轉會變成負數,從而導致這個函數被調用的時候極有可能會觸發以下異常

「已經丟了offer的小飯飯:」 為什么會出發異常?

「彪形大漢:」 你可能不知道,

Collections.sort()在JDK6和JDK7中實現的底層排序算法是不一樣的在JDK6中使用的是MergeSort排序,而在JDK7中使用的是TimSort,

使用TimSort排序算法對比較大小的要求更高

問題原因是,對某些數據來說,上述代碼會導致compare(a,b)<0并且compare(b,a)<0,也就是a

當這類數據遇到某些特殊情況時,就會發生這個異常。

給你貼一波大家都看不懂的源碼占占字數

  1. private void mergeHi(int base1, int len1, int base2, int len2) { 
  2.         assert len1 > 0 && len2 > 0 && base1 + len1 == base2; 
  3.  
  4.         // Copy second run into temp array 
  5.         T[] a = this.a; // For performance 
  6.         T[] tmp = ensureCapacity(len2); 
  7.         int tmpBase = this.tmpBase; 
  8.         System.arraycopy(a, base2, tmp, tmpBase, len2); 
  9.  
  10.         int cursor1 = base1 + len1 - 1;  // Indexes into a 
  11.         int cursor2 = tmpBase + len2 - 1; // Indexes into tmp array 
  12.         int dest = base2 + len2 - 1;     // Indexes into a 
  13.  
  14.         // Move last element of first run and deal with degenerate cases 
  15.         a[dest--] = a[cursor1--]; 
  16.         if (--len1 == 0) { 
  17.             System.arraycopy(tmp, tmpBase, a, dest - (len2 - 1), len2); 
  18.             return
  19.         } 
  20.         if (len2 == 1) { 
  21.             dest -= len1; 
  22.             cursor1 -= len1; 
  23.             System.arraycopy(a, cursor1 + 1, a, dest + 1, len1); 
  24.             a[dest] = tmp[cursor2]; 
  25.             return
  26.         } 
  27.  
  28.         Comparator<? super T> c = this.c;  // Use local variable for performance 
  29.         int minGallop = this.minGallop;    //  "    "       "     "      " 
  30.     outer
  31.         while (true) { 
  32.             int count1 = 0; // Number of times in a row that first run won 
  33.             int count2 = 0; // Number of times in a row that second run won 
  34.  
  35.             /* 
  36.              * Do the straightforward thing until (if ever) one run 
  37.              * appears to win consistently. 
  38.              */ 
  39.             do { 
  40.                 assert len1 > 0 && len2 > 1; 
  41.                 if (c.compare(tmp[cursor2], a[cursor1]) < 0) { 
  42.                     a[dest--] = a[cursor1--]; 
  43.                     count1++; 
  44.                     count2 = 0; 
  45.                     if (--len1 == 0) 
  46.                         break outer
  47.                 } else { 
  48.                     a[dest--] = tmp[cursor2--]; 
  49.                     count2++; 
  50.                     count1 = 0; 
  51.                     if (--len2 == 1) 
  52.                         break outer
  53.                 } 
  54.             } while ((count1 | count2) < minGallop); 
  55.  
  56.             /* 
  57.              * One run is winning so consistently that galloping may be a 
  58.              * huge win. So try that, and continue galloping until (if ever) 
  59.              * neither run appears to be winning consistently anymore. 
  60.              */ 
  61.             do { 
  62.                 assert len1 > 0 && len2 > 1; 
  63.                 count1 = len1 - gallopRight(tmp[cursor2], a, base1, len1, len1 - 1, c); 
  64.                 if (count1 != 0) { 
  65.                     dest -= count1; 
  66.                     cursor1 -= count1; 
  67.                     len1 -= count1; 
  68.                     System.arraycopy(a, cursor1 + 1, a, dest + 1, count1); 
  69.                     if (len1 == 0) 
  70.                         break outer
  71.                 } 
  72.                 a[dest--] = tmp[cursor2--]; 
  73.                 if (--len2 == 1) 
  74.                     break outer
  75.  
  76.                 count2 = len2 - gallopLeft(a[cursor1], tmp, tmpBase, len2, len2 - 1, c); 
  77.                 if (count2 != 0) { 
  78.                     dest -= count2; 
  79.                     cursor2 -= count2; 
  80.                     len2 -= count2; 
  81.                     System.arraycopy(tmp, cursor2 + 1, a, dest + 1, count2); 
  82.                     if (len2 <= 1)  // len2 == 1 || len2 == 0 
  83.                         break outer
  84.                 } 
  85.                 a[dest--] = a[cursor1--]; 
  86.                 if (--len1 == 0) 
  87.                     break outer
  88.                 minGallop--; 
  89.             } while (count1 >= MIN_GALLOP | count2 >= MIN_GALLOP); 
  90.             if (minGallop < 0) 
  91.                 minGallop = 0; 
  92.             minGallop += 2;  // Penalize for leaving gallop mode 
  93.         }  // End of "outer" loop 
  94.         this.minGallop = minGallop < 1 ? 1 : minGallop;  // Write back to field 
  95.  
  96.         if (len2 == 1) { 
  97.             assert len1 > 0; 
  98.             dest -= len1; 
  99.             cursor1 -= len1; 
  100.             System.arraycopy(a, cursor1 + 1, a, dest + 1, len1); 
  101.             a[dest] = tmp[cursor2];  // Move first elt of run2 to front of merge 
  102.         } else if (len2 == 0) { 
  103.             throw new IllegalArgumentException( 
  104.                 "Comparison method violates its general contract!"); 
  105.         } else { 
  106.             assert len1 == 0; 
  107.             assert len2 > 0; 
  108.             System.arraycopy(tmp, tmpBase, a, dest - (len2 - 1), len2); 
  109.         } 
  110.     } 

看不懂沒關系,我也看不懂,不過原理大概是這樣的,我們假定:

a<b && b<a,也就是代碼中出現的bug

假定輸入數組a[] = {5,a,7,12,4,b,8,8},其中待歸并的兩個有序數組分別是{5,a,7,12}和{4,b,8,8}

假定b<7&&7>b。這樣可以觸發“特殊情況”,即:a和b在某一次歸并操作后,會同時成為“是否移動元素”的臨界條件。

首先,我們有兩個有序數組A和B,如下圖所示。

找到待歸并區間、做好準備操作:

這樣,在劃分完待歸并區間后,得到的結果是這樣的:

第一次歸并操作:C2落在了元素b上;

然后,開始第一次歸并操作。由于B'[C2]>A'[C1],我們需要從C2開始,在數組B'中找到一個下標n,使得B'[n]

這里需要注意兩點:首先,臨界點的比較條件是B'[n]

這樣,第一輪歸并完成后的結果是這樣的:

第二次歸并操作:C1落在了元素a上:

接下來做第二次歸并操作。由于A'[C1]>B'[C2](這是先決條件里的第三點:b<7&&7>b),我們需要從C1開始,從A'中找到一個下標m,使得A'[m]

這里需要注意比較的順序性和區間半包性。

這一輪操作完,得到的結果是:

第三、四步操作:出現空集、死循環

可以看到,由于此時A'[C1]

然后,由于B'[C2]

如果不加干預,排序操作會在這里無限循環下去。TimSort中的干預方式就是當檢測到空集時,拋出異常。

「沒看懂沒關系,總歸就是能答出以下三個,其實就算你滿分了:」

  • updateTime1和updateTime2都是long類型,用int強轉有可能導致溢出
  • 導致排序出現混亂
  • 因為溢出變成負數,導致排序出現空集、死循環,而TimSort中的干預方式就是當檢測到空集時,拋出異常

「彪形大漢:」 雖然你這道題答的一半,但是我給你個補救的機會,怎么解決這個問題

「恢復斗志的小飯飯:」 確保compare(a,b)操作中,如果a>b,那么b

也就是說需要滿足以下條件

  • (x op y)的結果必須與(y op x)的結果相反。即,如果a>b,那么b
  • 傳遞性。即,如果a>b, b>c,那么a>c。
  • x==y時,(x op z) = ( y op z )

其實最好是將答案委托給Java基礎類,也就是

「彪形大漢:」 嗯,不錯,算是達到及格線了,你再坐會,我去叫下二面的面試官。

這個時候另一個彪形大漢走了進來

[[409395]]

二面面試官

面試流程未完,待續...........

原文鏈接:https://mp.weixin.qq.com/s/wPIKqEUgP2mTqFvUAv84Uw

 

責任編輯:武曉燕 來源: 稀飯下雪
相關推薦

2020-05-12 11:05:54

MySQL索引數據庫

2020-06-22 07:47:46

提交面試官訂單

2021-12-17 07:30:42

排序算法效率

2015-07-14 09:40:57

攜程面試前端面試官

2020-08-03 07:04:54

測試面試官應用程序

2020-07-13 08:40:48

同事代碼

2025-07-02 02:45:00

2024-08-08 08:50:21

標簽頁portTab

2020-05-22 08:11:48

線程池JVM面試

2024-01-03 21:50:32

緩存機制請求

2024-04-17 08:18:22

MyBatis批量插入SQL

2024-02-26 08:37:02

Feign項目接口

2021-12-02 08:19:06

MVCC面試數據庫

2021-02-05 08:35:21

私活程序員

2011-07-21 21:01:37

諾基亞塞班蘋果

2015-04-13 10:32:32

2023-12-25 09:03:33

MySQL索引數據庫

2021-03-17 08:39:24

作用域作用域鏈JavaScript

2017-03-22 15:38:28

代碼架構Java

2015-08-13 10:29:12

面試面試官
點贊
收藏

51CTO技術棧公眾號

主站蜘蛛池模板: 91在线精品视频 | 国产婷婷精品 | 欧美a级成人淫片免费看 | 欧美一级欧美三级在线观看 | 国产精品爱久久久久久久 | 天天天天操 | 一级毛片大全免费播放 | 精品一区二区三区在线观看国产 | 欧美一区二区三区日韩 | 青青草av在线播放 | 国产成人精品免高潮在线观看 | 91麻豆精品国产91久久久久久久久 | 久久午夜精品 | 天天干天天爱天天爽 | 99色播| 一级h片| 成人一区二区三区在线观看 | 国产免费拔擦拔擦8x高清 | 日韩欧美高清 | 日韩精品视频在线观看一区二区三区 | 在线播放一区二区三区 | 国产成人精品免费 | 少妇诱惑av | 国产精品免费看 | 亚洲 欧美 日韩在线 | 久久噜噜噜精品国产亚洲综合 | 日韩精品免费在线观看 | 亚洲网站在线观看 | 国产精品大片在线观看 | 中文字幕日韩在线观看 | 久久免费精彩视频 | 日韩资源| 2022精品国偷自产免费观看 | 亚洲人成免费 | 日韩一区在线观看视频 | 亚洲精品1| 久久久综合色 | 热re99久久精品国99热观看 | 国产美女在线播放 | 国产视频一区二区三区四区五区 | 国产成人a亚洲精品 |