面試題:如何來判斷一個List是否有序?

前語: 不要為了讀文章而讀文章,一定要帶著問題來讀文章,勤思考。

這是一位同學面試的過程中遇到的面試題,我覺得挺有意思,去研究了一下,發現竟然有這麼多方法,在此,與大家分享一下。

關於List這種數據結構,在這裡我就不多說了,很重要,不知道的同學可以翻閱以前的文章。

對於這類問題,你首先要給面試官一個定心丸: List是java.util.Collection 接口的一個子接口,並且是一個有序列表 。 這一步很關鍵,不能錯,一定要記清楚,如果這一步錯,那麼後面說再多,也等於零,請記住下面這張圖。


面試題:如何來判斷一個List是否有序?


我們再來抓這個問題的關鍵點: 如何用程序證明List是有序的?

方法即是迭代List並比較相鄰元素。 如果兩個相鄰元素中的任何一個未排序,我們可以說List未排序。

下面我就來列舉幾種方法。

1、迭代器

其實Java的遍歷有三種方式: for、foreach、Iterator; 關於這三種的區別,你也可以在面試中延伸一下(比如說 為什麼在Iterator能夠修改集合內部的元素,而foreach不行? 會拋什麼異常? )。

既然提到遍歷,那麼這裡有有兩個東東需要提一下Comparator與Comparable,它們的區別是什麼?

Comparable : 如果一個類實現了該接口,那麼該類默認支持排序,相當於“ 內部比較器 ”。

Comparator : 如果一個類型實現該接口,那麼該類自身不支持排序,它只是充當一個“ 外部比較器 ”的角色。

以String為例,它自身實現了 Comparable接口,那麼我可以用下面這種方式來驗證:

public static boolean isSorted(List<string> listOfStrings) {/<string>

if (isEmpty(listOfStrings) || listOfStrings.size() == 1) {

return true;

}

Iterator<string> iter = listOfStrings.iterator();/<string>

String current, previous = iter.next();

while (iter.hasNext()) {

current = iter.next();

if (previous.compareTo(current) > 0) {

return false;

}

previous = current;

}

return true;

}

我們自己建的類一般不會自動實現 Comparable接口,那麼我們可以嘗試用 Comparator來進行比較,如:

public static boolean isSorted(List<employee> employees, Comparator<employee> employeeComparator) {/<employee>/<employee>

if (isEmpty(employees) || employees.size() == 1) {

return true;

}

Iterator<employee> iter = employees.iterator();/<employee>

Employee current, previous = iter.next();

while (iter.hasNext()) {

current = iter.next();

if (employeeComparator.compare(previous, current) > 0) {

return false;

}

previous = current;

}

return true;

}

通過上面的例子,我們可以發現不同之處: 在於前後兩個元素的比較方式上。 總得來說,如果你建的類默認有排序功能,那麼建議用Comparable; 但是,我們可以使用Comparator進行精確控制排序。

到這裡,看出來沒,一個迭代器咱們就可以吹這麼多牛皮出來^_^

2、遞歸

遞歸這種方式只是一種思路,我覺得用的比較巧妙,啥都不說了,直接上代碼。

public static boolean isSorted(List<string> listOfStrings) {/<string>

return isSorted(listOfStrings, listOfStrings.size());

}

public static boolean isSorted(List<string> listOfStrings, int index) {/<string>

if (index < 2) {

return true;

} else if (listOfStrings.get(index - 2).compareTo(listOfStrings.get(index - 1)) > 0) {

return false;

} else {

return isSorted(listOfStrings, index - 1);

}

}

說實話,這種證明操作我剛開始是沒有想到的,很巧妙的玩法。

3、第三方組件

這裡就不得不提谷歌開源的 Guava ,這個組件基本上包含了我們常用的所有工具類,也包括檢驗排序。

比如,利用Guava的Ordering類檢查List是否有序,同樣它也提供了兩種方式,一種是針對於實現了Comparable接口的類型,比如:

public static boolean isSorted(List<string> listOfStrings) {/<string>

return Ordering.<string> natural().isOrdered(listOfStrings);/<string>

}

另一種是使用 Comparator進行排序的類,比如:

public static boolean isSorted(List<employee> employees, Comparator<employee> employeeComparator) {/<employee>/<employee>

return Ordering.from(employeeComparator).isOrdered(employees);

}

它內部還有很多方法,比如natural().reverseOrder():來檢查列表是否按相反的順序排序; 再比如我們可以使用natural().nullFirst()和natural().nullLast()來檢查null是否出現在排序列表的第一個或最後一個。

如果我們使用Java 8及以上的版本,Guava在Comparators類方面提供了更好的選擇,比如以下示例:

public static boolean isSorted(List<string> listOfStrings) {/<string>

return Comparators.isInOrder(listOfStrings, Comparator.<string> naturalOrder());/<string>

}

從上面的示例中,使用默認順序來檢查排序列表,但我們也可以使用Comparator來自定義排序檢查。

小結

從本文,我們可以看出,面試的過程中,首先要抓住問題的關鍵點,然後把自己知道的知識點一點點延展開來,讓面試官知道你的深度與廣度,就比如我昨天發的這篇關於浮點數科學計數法的文章《 Stackoverflow: 為什麼將0.1f改為0會使性能降低10倍? 》,浮點數這個知識點基礎嗎? 確實基礎,基礎到大多數程序員而不屑一看! 重要嗎? 真重要,稍不注意就會出錯,比如下面這種寫法:

if(0.9f-0.8f == 0.1f){

System.err.println("equal");

}else {

System.err.println("no equal");

}

特別像我們做金融的,線上出現這種問題就有可能是致命的; 比如我們公司金額全部都用整數,不做浮點數計算,容易損失精度,要麼用BigDecimal。 所以,我也一直強調基礎很重要,比如算法,雖然你工作中用到的很少,但你得知道那幾種基本算法,什麼樣的數據量該選誰最優,正如孤盡大佬所說的“ 一個方法看起來數據量沒多少,沒必要進行算法優化,但是乘以一個訪問量級,那麼它對服務器的性能損耗將是巨大的! ”等等。 。 。

還有我每次分享給大家的文章,真值得你仔細去研究,每篇文章的內容不能保證百分之百的不出錯,但每篇文章引申出來的知識點,就值得你去延伸,自己不動手,又想成為大牛,別做夢了!

真的,編程這條道路上,只能靠自己,誰也幫不了你!


分享到:


相關文章: