Arrays.sort() 為什麼可以對 int 等數組進行排序?我跟面試官扯了...

2020-12-12 CSDN

作者 | TrueDei

責編 | 王曉曼

出品 | CSDN博客

前言

排序是在程序開發中最常用到的,最常見的就是針對一些數字進行排序。而現實中像商品的名字,訂單的日期等進行排序。Java的JDK中就自帶了Comparable接口,那麼來看下這個,如何與面試官對答如流。

拋下 Arrays.sort() 中排序的算法,一起來揭開這層面紗吧。

1、猜一猜

猜測以下代碼的執行結果是什麼?

int[] ints = {50,1,4,8,3};String [] strings = {"q","a","c"};Arrays.sort(ints);for (String val: strings) { System.out.print(val + " ");}System.out.println();for (int i = 0; i < ints.length; i++) { System.out.print(ints[i]+" ");}

好了,現在猜測結束。

你會很快猜到一下內容:

q a c 134850

你可真是一個小能能,厲害的不要不要的。

但是,如果面試官問你:

為什麼 int 數組, String 數組等等,這些可以使用 Arrays.sort() 進行排序呢?

咱們慢慢揭曉這個答案。

先看幾個原始碼:

1、Integer的原始碼

publicfinalclassIntegerextendsNumberimplementsComparable<Integer> { ..... ..... .....publicintcompareTo(Integer anotherInteger){return compare(this.value, anotherInteger.value); }}

2、Short的原始碼

publicfinalclassShortextendsNumberimplementsComparable<Short> { ..... ..... .....publicintcompareTo(Short anotherShort){return compare(this.value, anotherShort.value); }}

3、String的原始碼

publicfinalclassStringimplementsjava.io.Serializable, Comparable<String>, CharSequence{ ..... ..... .....publicintcompareTo(String anotherString){int len1 = value.length;int len2 = anotherString.value.length;int lim = Math.min(len1, len2);char v1[] = value;char v2[] = anotherString.value;int k = 0;while (k < lim) {char c1 = v1[k];char c2 = v2[k];if (c1 != c2) {return c1 - c2; } k++; }return len1 - len2; }}

發現了什麼?

是不是發現了都實現了Comparable接口和compareTo方法。

對,你現在也許知道怎麼去回答面試官這個問題了,因為他們都實現了Comparable接口和compareTo方法。

3、試試真是如此嗎?不信測試一下

新建二個實體類和一個測試類,一個是Student實體類,一個是User實體類,一個是測試類Test。

Student類

為了方便演示,這裡的Student類實現Comparable接口。

package ComparableInterface;/** * @Auther: truedei * @Date: 2020 /20-5-7 20:29 * @Description: */publicclassStudentimplementsComparable<Student>{privateint age;private String name;publicStudent(){ }publicStudent(int age, String name){this.age = age;this.name = name; }publicintgetAge(){return age; }publicvoidsetAge(int age){this.age = age; }public String getName(){return name; }publicvoidsetName(String name){this.name = name; }@Overridepublic String toString(){return"Student{" +"age=" + age +", name='" + name + '\'' +'}'; }@OverridepublicintcompareTo(Student o){returnthis.getAge() - o.getAge(); }}

User類

為了方便演示,這裡的User類不實現Comparable接口。

package ComparableInterface;/** * @Auther: truedei * @Date: 2020 /20-5-7 20:29 * @Description: */publicclassUser{privateint age;private String name;publicUser(){ }publicUser(int age, String name){this.age = age;this.name = name; }publicintgetAge(){return age; }publicvoidsetAge(int age){this.age = age; }public String getName(){return name; }publicvoidsetName(String name){this.name = name; }@Overridepublic String toString(){return"User{" +"age=" + age +", name='" + name + '\'' +'}'; }}

測試類

package ComparableInterface;import java.util.ArrayList;import java.util.Arrays;import java.util.List;/** * @Auther: truedei * @Date: 2020 /20-5-7 20:29 * @Description: */publicclassTest{publicstaticvoidmain(String[] args){ }}

測試1、比較Student類

Student s1 = new Student(19,"張三");Student s2 = new Student(18,"李四");int i = s1.compareTo(s2);if(i>=0){ System.out.println(s1.getName()+"年齡大");}else{ System.out.println(s2.getName()+"年齡大");}

測試結果1:

這個結果也是很容易猜到的,因為Student類實現了Comparable接口,並實現了 compareTo方法。並且是以age做比較的。

張三年齡大

測試2、比較User類

User u1 = new User(12,"王五"); User u2 = new User(22,"趙六");int j = u1.compareTo(u2);if(j>=0){ System.out.println(u1.getName()+"年齡大"); }else{ System.out.println(u2.getName()+"年齡大"); }

測試2的結果:

這個是沒有結果的,因為程序是無法執行的,會報出沒有compareTo這個方法。

原因:

原因很簡單,因為沒有實現Comparable接口。

測試3、對Student類的數組排序

隨便添加進去幾個數據,為了方便理解,我就寫的稍微麻煩了一點。

Student s1 = new Student(19,"張三"); Student s2 = new Student(18,"李四"); Student s3 = new Student(2,"王五"); Student[] students = {s1,s2,s3}; System.out.println("排序前:");for (Student st:students) { System.out.println(st.toString()); } System.out.println();//進行排序 Arrays.sort(students); System.out.println("排序後:");for (Student st:students) { System.out.println(st.toString()); }

測試結果:

是不是有點小驚喜?為什麼可以進行直接排序呢?

沒錯,就是因為實現了那個Comparable接口,而且是根據年齡的大小來排序的。

排序前:Student{age=19, name='張三'}Student{age=18, name='李四'}Student{age=2, name='王五'}排序後:Student{age=2, name='王五'}Student{age=18, name='李四'}Student{age=19, name='張三'}

如果你想從大到小排序怎麼辦?

也很簡單,只需要改變一下compareTo中的方法即可。

修改如下:

@OverridepublicintcompareTo(Student o){// return this.getAge() - o.getAge();return o.getAge()- this.getAge(); }

為了好看,我把三個Student類的數據,修改了一下:

Student s1 = new Student(7,"張三");Student s2 = new Student(18,"李四");Student s3 = new Student(2,"王五");

測試結果:

排序前:Student{age=7, name='張三'}Student{age=18, name='李四'}Student{age=2, name='王五'}排序後:Student{age=18, name='李四'}Student{age=7, name='張三'}Student{age=2, name='王五'}Process finished with exit code 0

測試4、對User類的數組排序

可以先猜測一下,可能排序嗎?

User u1 = new User(12,"王五"); User u2 = new User(22,"趙六"); User u3 = new User(15,"雜七"); User[] users = {u1,u2,u3}; System.out.println("排序前:");for (User user:users) { System.out.println(user.toString()); } System.out.println();//進行排序 Arrays.sort(users); System.out.println("排序後:");for (User user:users) { System.out.println(user.toString()); }

測試結果:

排序前:User{age=12, name='王五'}User{age=22, name='趙六'}User{age=15, name='雜七'}Exception in thread "main" java.lang.ClassCastException: ComparableInterface.User cannot be cast to java.lang.Comparable at java.util.ComparableTimSort.countRunAndMakeAscending(ComparableTimSort.java:320) at java.util.ComparableTimSort.sort(ComparableTimSort.java:188) at java.util.Arrays.sort(Arrays.java:1246) at ComparableInterface.Test.main(Test.java:54)

提示你:

cannot be cast to java.lang.Comparable

說明:無法轉換成Comparable

那麼就得出結論:

沒有實現Comparable接口的類的數組是無法使用Arrays.sort()進行排序的

改造 User類 進一步測試

稍微改造一下:給User類實現Comparable接口。

1、需求如下

因為User類有年齡和姓名,年齡小的優先。

如果年齡相同,那麼比較姓名,按姓名的ascii碼值來排序,例如:a-b-c

2、修改User類

package ComparableInterface;/** * @Auther: truedei * @Date: 2020 /20-5-7 20:29 * @Description: */publicclassUserimplementsComparable<User>{privateint age;private String name;publicUser(){ }publicUser(int age, String name){this.age = age;this.name = name; }publicintgetAge(){return age; }publicvoidsetAge(int age){this.age = age; }public String getName(){return name; }publicvoidsetName(String name){this.name = name; }@Overridepublic String toString(){return"User{" +"age=" + age +", name='" + name + '\'' +'}'; }@OverridepublicintcompareTo(User o){//年齡從小到大if(this.getAge() - o.getAge() > 0){return1; }elseif(this.getAge() - o.getAge() == 0){returnthis.getName().compareTo(o.getName()); }return -1; }}

重點是:

可以看到年齡是從小到大的對比如果this.年齡 - o.年齡 == 0 說明相等,那麼就比較名字@Overridepublic int compareTo(User o) {//年齡從小到大if(this.getAge() - o.getAge() > 0){return1; }elseif(this.getAge() - o.getAge() == 0){returnthis.getName().compareTo(o.getName()); }return-1;}

3、測試

為了方便理解,我把姓名修改成了a,e,s,q,d,g這些字母

為了比較好說明,我找了一個比較簡潔的ascii碼錶:

我們拿a、b、y做為姓名來測試:

System.out.println("a="+(int)'a');System.out.println("b="+(int)'b');System.out.println("y="+(int)'y');

結果:

97<98<121

a<b<y

a=97b=98y=121

正式代碼:

User u1 = new User(12,"b"); User u2 = new User(22,"y"); User u3 = new User(22,"a"); User[] users = {u1,u2,u3}; System.out.println("排序前:");for (User user:users) { System.out.println(user.toString()); } System.out.println();//進行排序 Arrays.sort(users); System.out.println("排序後:");for (User user:users) { System.out.println(user.toString()); }

測試結果:

排序前:User{age=12, name='b'}User{age=22, name='y'}User{age=22, name='a'}排序後:User{age=12, name='b'}User{age=22, name='a'}User{age=22, name='y'}

版權聲明:本文為CSDN博主「TrueDei」的原創文章,遵循CC 4.0 BY-SA版權協議,轉載請附上原文出處連結及本聲明。

原文連結:

https://truedei.blog.csdn.net/article/details/105981691

相關焦點

  • 「算法」排序02——歸併排序介紹及其在分治算法思想上與快排的...
    )來輔助存儲正在排序數據,當一個新序列排序完成後再把它導入回原來的內存空間(即代碼中arr數組)。1import java.util.Arrays; 2 3publicclass Main { 4 5publicstaticvoid merge_sort(int[] arr){ 6//new 一個等大的臨時空數組,用於排序時緩存數據 7int[] reg = newint[arr.length]; 8 recursive(arr,reg,0,arr.length
  • 基礎不牢地動山搖記住 Java 面試中常用的八種排序算法與代碼實現
    代碼實現如下:public void insertSort(int[] a){int length=a.length;//數組長度,將這個提取出來是為了提高速度。速度僅次於快排,內存少的時候使用,可以進行並行計算的時候使用。
  • 如何讓集合中的元素,按照自己想要的方式排序?
    有,可變參數就可以,直接一個方法就可以了:可變參數格式:數據類型... 變量名。可變參數本質上就是一個數組,可以用增強for循環遍歷。理論上可變參數的個數可以無數個。其中,Collections的sort方法排序是升序排列,如果我們想自定義排序規則該怎麼辦?比較器就可以自定義排序。
  • 10道虐心的Java面試題,被面試官虐哭了,同事一題都沒答對
    有一天,小王告訴我,他去一家公司面試 Java 崗,結果被面試官虐哭了。整整 10 道 Java 面試題,小王一道也沒答正確。  他沮喪地給我說,「哥,說點我的情況,你願意聽嗎?我和一個女孩相處,女孩大我兩歲,我非科班。本來打算國慶換一家薪水高點的,好確認關係。
  • 手敲一遍數據結構和排序算法
    ,這裡的臨時數組是存排序後的元素,排完後再複製到原數組中inttempIndex=left;// 循環比較,直至左邊組或右邊組沒有剩餘元素了才停止while (l<=mid&&r<=right) {// 可以想像最簡單的情況,倒數第二層,有兩個元素,需要對這兩個元素排序
  • js數組常用的幾個函數總結
    javascript中,數組是很常用的。數組的函數很多,下面分享幾個常用的數組函數。每個函數都用瀏覽器測試過。     下面每個測試結果都是在google瀏覽器console上執行的。length屬性。數組的length屬性,返回數組的元素個數.JavaScript使用一個32位整數,保存數組的元素個數。
  • Redis面試:八問字典內部構造與rehash,給我整懵了
    而redis一般是採用hash表的方式進行構建redis字典為啥不用線性表實現字典基於用線性表實現,如果我這個字典有200個鍵值對,那麼我就開闢一個長度為200的數組對這些元素進行放置。基於線性表實現的字典的優缺點很明顯:1、實現簡單,適用於任意關鍵字類型。
  • 面試官:String長度有限制嗎?是多少?
    是的有,而且在JVM編譯中還有規範,而且有的家人們在面試的時候也遇到了。本人就遇到過面試的時候問這個的,而且在之前開發的中也真實地遇到過這個String長度限制的場景(將某固定文件轉碼成Base64的形式用字符串存儲,在運行時需要的時候在轉回來,當時文件比較大),那這個規範限制到底是怎麼樣的,咱們話不多說先瞜瞜去。
  • 二維數組中的查找(劍指 Offer 題解Java版)
    tpId=13&tqId=11154&tPage=1&rp=1&ru=/ta/coding-interviews&qru=/ta/coding-interviews/question-ranking&from=cyc_github題目描述給定一個二維數組,其每一行從左到右遞增排序
  • 5分鐘弄懂的五大常用算法之「分治法」,以C語言歸併排序算法為例
    在處理數組排序時,如果數組中只有 1 個元素,那麼該數組本身就可看作是排好序的數組。如果數組中有 2 個元素,那麼最多只需比較一次就可以得到排好序的數組。這其實是歸併排序法的核心,也即規模越小的數組,對其排序越簡單。下圖是一個長度為 5 的數組,為了排序,先把它拆分到不能繼續拆為止。
  • java之數組長度的獲取與數組的遍歷
    獲取數組長度的格式:數組名稱.length。之後,將會出現一個int數字來代表數組的長度。小編覺得,右邊new double[5]是賦值給左邊的,右邊是一個數組,而左邊只是一個代號array3。大家可以參考小編上面粘的圖片,之前小編有說過new出來的東西實在堆當中,所以這個代碼中有兩個數組,堆當中的數組長度沒有發生改變,只是增加了一個長度為5的數組。
  • 搞定HashMap面試,深入講解HashMap的工作原理
    為什麼HashMap深受面試官青睞,我想有這3個原因:常用、基礎線程不安全,容易出問題大廠都在問,自己不問顯得面試官沒水平Hash虐我千百遍,我視它為初戀,真的是又愛又恨。但是40億的數組內存是放不下的,只能進行壓縮。最簡單的方法就是取模,hash%table.length就能計算出index。我們能想到,大師也想到了。只是大師想的更周全。
  • 面試熱身:5 億整數的大文件,排個序?
    給你1個文件bigdata,大小4663M,5億個數,文件中的數據隨機,如下一行一個整數:61963023557681612158020393452095006174677379343122016371712330287901712966901...7005375現在要對這個文件進行排序
  • 歸併排序——一文吃透歸併和遞歸的思想和完整過程! - 計算機java...
    而遞歸則是一種策略,遞歸可以用於解決這些同類的子問題。歸併排序下面,我將深入詳細的分析歸併遞歸的過程,並講解遞歸的詳細過程,並給出其中的要點:我們以下面的數組為例子,用歸併排序的方法將上述數組排序。答:對數組排序。那么子問題的目標自然也是對數組排序,那麼分治問題的思想是,子問題解決了,原問題就可以解決;那么子問題解決了是指什麼:子問題排好序了!繼續追問:什麼時候子問題排好序了:答案:子問題只剩下一個元素的時候,此時子數組自然就是有序的了。
  • 憑藉清華掃地僧的路線指引,從Java基礎到算法,吊打阿里面試官!
    本文素材來自於一位鐵粉經驗分享上周收到字節跳動的面試邀請,真的又驚又喜。驚得是害怕面試時會被秒殺;喜得是有大廠邀請,是自己能力的一種體現。於是抱著試試看的輕鬆心態,居然一不小心就反殺了面試官(嘻嘻,有點嘚瑟啊)。
  • 面試時,面試官提出跟工作無關的難題,面試官有何意圖?
    某網際網路公司為了充分的迎接公司上市,決定招收一批優秀的人才,培養做公司的儲備幹部,第一天就來了20多位應聘者,經過面試官的篩選過後,第一輪就剩下了四位應聘者,稍作休息後,面試官通知四位應聘者進行「集面」(集體面試)。
  • 面試常問的數據結構十大經典算法
    它的基本思想是:在數據序列中選擇一個元素作為基準值,每次從數據序列的兩端開始交替進行,將小於基準值元素交換到序列前端,將大於基準值的元素交換到序列後端,介於兩者之間的位置則成為基準值的最終位置。同時,序列被劃分成兩個子序列,再分別對兩個子序列進行快速排序,直到子序列長度為1,則完成排序,整個排序過程可以遞歸進行,以此達到整個數據變成有序序列。