終于,我讀懂了所有Java集合——sort

Collections.sort

?

事實上Collections.sort方法底層就是調用的Arrays.sort方法,而Arrays.sort使用了兩種排序方法,快速排序和優化的歸并排序。

? ? 快速排序主要是對那些基本類型數據(int,short,long等)排序, 而歸并排序用于對Object類型進行排序。

使用不同類型的排序算法主要是由于快速排序是不穩定的,而歸并排序是穩定的。這里的穩定是指比較相等的數據在排序之后仍然按照排序之前的前后順序排列。對于基本數據類型,穩定性沒有意義,而對于Object類型,穩定性是比較重要的,因為對象相等的判斷可能只是判斷關鍵屬性,最好保持相等對象的非關鍵屬性的順序與排序前一致;另外一個原因是由于歸并排序相對而言比較次數比快速排序少,移動(對象引用的移動)次數比快速排序多,而對于對象來說,比較一般比移動耗時。

public static <T extends Comparable<? super T>> void sort(List<T> list) {list.sort(null);
}

List#sort

default void sort(Comparator<? super E> c) {Object[] a = this.toArray();Arrays.sort(a, (Comparator) c);ListIterator<E> i = this.listIterator();for (Object e : a) {i.next();i.set((E) e);}
}public static <T> void sort(T[] a, Comparator<? super T> c) {if (c == null) {sort(a);} else {if (LegacyMergeSort.userRequested)legacyMergeSort(a, c);elseTimSort.sort(a, 0, a.length, c, null, 0, 0);}
}public static void sort(Object[] a) {if (LegacyMergeSort.userRequested)legacyMergeSort(a);elseComparableTimSort.sort(a, 0, a.length, null, 0, 0);
}

TimSort

結合了歸并排序和插入排序的混合算法,它基于一個簡單的事實,實際中大部分數據都是部分有序(升序或降序)的。

TimSort 算法為了減少對升序部分的回溯和對降序部分的性能倒退,將輸入按其升序和降序特點進行了分區。排序的輸入的單位不是一個個單獨的數字,而是一個個的塊-分區。其中每一個分區叫一個run。針對這些 run 序列,每次拿一個 run 出來按規則進行合并。每次合并會將兩個 run合并成一個 run。合并的結果保存到棧中。合并直到消耗掉所有的 run,這時將棧上剩余的 run合并到只剩一個 run 為止。這時這個僅剩的 run 便是排好序的結果。

綜上述過程,Timsort算法的過程包括

(0)如果數組長度小于某個值,直接用二分插入排序算法

(1)找到各個run,并入棧

(2)按規則合并run

?


/*** Sorts the given range, using the given workspace array slice* for temp storage when possible. This method is designed to be* invoked from public methods (in class Arrays) after performing* any necessary array bounds checks and expanding parameters into* the required forms.** @param a the array to be sorted* @param lo the index of the first element, inclusive, to be sorted* @param hi the index of the last element, exclusive, to be sorted* @param work a workspace array (slice)* @param workBase origin of usable space in work array* @param workLen usable size of work array* @since 1.8*/
static void sort(Object[] a, int lo, int hi, Object[] work, int workBase, int workLen) {assert a != null && lo >= 0 && lo <= hi && hi <= a.length;int nRemaining  = hi - lo;if (nRemaining < 2)return;  // Arrays of size 0 and 1 are always sorted// If array is small, do a "mini-TimSort" with no mergesif (nRemaining < MIN_MERGE) {int initRunLen = countRunAndMakeAscending(a, lo, hi);binarySort(a, lo, hi, lo + initRunLen);return;}/*** March over the array once, left to right, finding natural runs,* extending short natural runs to minRun elements, and merging runs* to maintain stack invariant.*/ComparableTimSort ts = new ComparableTimSort(a, work, workBase, workLen);int minRun = minRunLength(nRemaining);do {// Identify next runint runLen = countRunAndMakeAscending(a, lo, hi);// If run is short, extend to min(minRun, nRemaining)if (runLen < minRun) {int force = nRemaining <= minRun ? nRemaining : minRun;binarySort(a, lo, lo + force, lo + runLen);runLen = force;}// Push run onto pending-run stack, and maybe mergets.pushRun(lo, runLen);ts.mergeCollapse();// Advance to find next runlo += runLen;nRemaining -= runLen;} while (nRemaining != 0);// Merge all remaining runs to complete sortassert lo == hi;ts.mergeForceCollapse();assert ts.stackSize == 1;
}
/*** Creates a TimSort instance to maintain the state of an ongoing sort.** @param a the array to be sorted* @param work a workspace array (slice)* @param workBase origin of usable space in work array* @param workLen usable size of work array*/
private ComparableTimSort(Object[] a, Object[] work, int workBase, int workLen) {this.a = a;// Allocate temp storage (which may be increased later if necessary)int len = a.length;int tlen = (len < 2 * INITIAL_TMP_STORAGE_LENGTH) ?len >>> 1 : INITIAL_TMP_STORAGE_LENGTH;if (work == null || workLen < tlen || workBase + tlen > work.length) {tmp = new Object[tlen];tmpBase = 0;tmpLen = tlen;}else {tmp = work;tmpBase = workBase;tmpLen = workLen;}/** Allocate runs-to-be-merged stack (which cannot be expanded).  The* stack length requirements are described in listsort.txt.  The C* version always uses the same stack length (85), but this was* measured to be too expensive when sorting "mid-sized" arrays (e.g.,* 100 elements) in Java.  Therefore, we use smaller (but sufficiently* large) stack lengths for smaller arrays.  The "magic numbers" in the* computation below must be changed if MIN_MERGE is decreased.  See* the MIN_MERGE declaration above for more information.* The maximum value of 49 allows for an array up to length* Integer.MAX_VALUE-4, if array is filled by the worst case stack size* increasing scenario. More explanations are given in section 4 of:* http://envisage-project.eu/wp-content/uploads/2015/02/sorting.pdf*/int stackLen = (len <    120  ?  5 :len <   1542  ? 10 :len < 119151  ? 24 : 49);runBase = new int[stackLen];runLen = new int[stackLen];
}

MergeSort

private static void legacyMergeSort(Object[] a) {Object[] aux = a.clone();mergeSort(aux, a, 0, a.length, 0);
}private static void mergeSort(Object[] src,Object[] dest,int low,int high,int off) {int length = high - low;// 7// Insertion sort on smallest arraysif (length < INSERTIONSORT_THRESHOLD) {for (int i=low; i<high; i++)for (int j=i; j>low &&((Comparable) dest[j-1]).compareTo(dest[j])>0; j--)swap(dest, j, j-1);return;}// Recursively sort halves of dest into srcint destLow? = low;int destHigh = high;low? += off;high += off;int mid = (low + high) >>> 1;mergeSort(dest, src, low, mid, -off);mergeSort(dest, src, mid, high, -off);// If list is already sorted, just copy from src to dest.? This is an// optimization that results in faster sorts for nearly ordered lists.if (((Comparable)src[mid-1]).compareTo(src[mid]) <= 0) {System.arraycopy(src, low, dest, destLow, length);return;}// Merge sorted halves (now in src) into destfor(int i = destLow, p = low, q = mid; i < destHigh; i++) {if (q >= high || p < mid && ((Comparable)src[p]).compareTo(src[q])<=0)dest[i] = src[p++];elsedest[i] = src[q++];}
}

總結

小于60:使用插入排序,插入排序是穩定的
????大于60的數據量會根據數據類型選擇排序方式:
?????????基本類型:使用快速排序。因為基本類型。1、2都是指向同一個常量池不需要考慮穩定性。
?????????Object類型:使用歸并排序。因為歸并排序具有穩定性。
????注意:不管是快速排序還是歸并排序。在二分的時候小于60的數據量依舊會使用插入排序

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/444780.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/444780.shtml
英文地址,請注明出處:http://en.pswp.cn/news/444780.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

PRML(1)--緒論(上)多項式曲線擬合、概率論

PRML緒論1.1 多項式曲線擬合1.1.1 問題描述1.1.2 最小化平方和誤差1.1.3 多項式階數確定1.1.4 有趣問題--高階模型為什么效果不好1.1.4 數據集規模對模型的影響1.1.5 參數正則化緩解過擬合問題1.2 概率論1.2.1離散型隨機變量1.2.2 連續型隨機變量1.2.3 期望和方差1.2.4 貝葉斯概…

大數加減乘

如標題&#xff0c;不解釋。 加 #include<stdio.h> #include<string.h> int main() {char a[1000],b[1000];int i,s[1000],len1,len2,len,j;while(scanf("%s%s",a,b)!EOF) //用字符數組來儲存數{for(i0;i<1000;i)s[i]0;len1strlen(a);len2strlen(b…

在GCC和Visual Studio中使用hash_map

熟悉STL或熟悉ACM/ICPC的話&#xff0c;其中的set, map, multiset, multimap一定用過無數次了&#xff0c;它們都是用平衡二叉樹&#xff08;紅黑樹&#xff09;實現的&#xff0c;復雜度為O(lgn)。我們也知道set, map可以通過哈希來實現&#xff0c;復雜度只有O(1)&#xff0c…

C++(21)--Astah uml 畫C++類圖

Astah uml 畫C類圖1.安裝2.使用《老九學堂C課程》《老九學堂C課程》詳情請到B站搜索《老九零基礎學編程C入門》-------------簡單的事情重復做&#xff0c;重復的事情用心做&#xff0c;用心的事情堅持做(老九君)--------------- ASTAH&#xff1a;類圖工具&#xff0c;用于理…

redis3.0.0 集群安裝詳細步驟

Redis集群部署文檔(centos6系統) &#xff08;要讓集群正常工作至少需要3個主節點&#xff0c;在這里我們要創建6個redis節點&#xff0c;其中三個為主節點&#xff0c;三個為從節點&#xff0c;對應的redis節點的ip和端口對應關系如下&#xff09; 127.0.0.1:7000 127.0.0.1:7…

Redis集群添加節點

Redis集群添加節點 1&#xff1a;首先把需要添加的節點啟動 cd /usr/local/cluster/ mkdir 7006 cp /usr/local/cluster/redis.conf /usr/local/cluster/7006/ cd /usr/local/cluster/7006/ vi redis.conf ##修改redis.conf中的port參數的值為7006 redis-server redis.c…

PRML(2)--緒論(下)模型選擇、緯度災難、決策論、信息論

PRML緒論1.3 模型選擇1.4 緯度災難1.5 決策論1.5.1最小錯誤分率1.5.2最小化期望損失1.5.3拒絕選項1.5.4推斷和決策1.5.5 回歸問題的損失函數1.6 信息論1.3 模型選擇 模型過復雜會造成過擬合問題&#xff0c;需要通過一些技術來降低模型的復雜度。 就最大似然而言&#xff0c;可…

leetcode112 路徑總和

給定一個二叉樹和一個目標和&#xff0c;判斷該樹中是否存在根節點到葉子節點的路徑&#xff0c;這條路徑上所有節點值相加等于目標和。 說明: 葉子節點是指沒有子節點的節點。 示例: 給定如下二叉樹&#xff0c;以及目標和 sum 22&#xff0c; 5 / \ …

關于游戲架構設計的一些整理吧

一個大型的網落游戲服務器應該包含幾個模塊:網絡通訊,業務邏輯,數據存儲,守護監控(不是必須),其中業務邏輯可能根據具體需要,又劃分為好幾個子模塊。 這里說的模塊可以指一個進程,或者一個線程方式存在,本質上就是一些類的封裝。

linux時間輪 Timing-Wheel的實現

過一段時間上傳更新自己的心得&#xff0c;以及linux的時間輪實現 現在git上傳自己的C代碼 gitgithub.com:pbymw8iwm/Timing-Wheel.git

leetcode128 最長連續序列

給定一個未排序的整數數組&#xff0c;找出最長連續序列的長度。 要求算法的時間復雜度為 O(n)。 示例: 輸入: [100, 4, 200, 1, 3, 2] 輸出: 4 解釋: 最長連續序列是 [1, 2, 3, 4]。它的長度為4 思路&#xff1a;map記錄某個連續序列端點的最大長度。 對于數字i&#xff…

C++(22)--繼承和派生

繼承和派生1.基本概念2.實現公有繼承3.私有繼承的例子4. 繼承和組合《老九學堂C課程》《C primer》學習筆記。《老九學堂C課程》詳情請到B站搜索《老九零基礎學編程C入門》-------------簡單的事情重復做&#xff0c;重復的事情用心做&#xff0c;用心的事情堅持做(老九君)----…

Python- 解決PIP下載安裝速度慢

對于Python開發用戶來講&#xff0c;PIP安裝軟件包是家常便飯。但國外的源下載速度實在太慢&#xff0c;浪費時間。而且經常出現下載后安裝出錯問題。所以把PIP安裝源替換成國內鏡像&#xff0c;可以大幅提升下載速度&#xff0c;還可以提高安裝成功率。 國內源&#xff1a; …

leetcode102 二叉樹的層次遍歷

給定一個二叉樹&#xff0c;返回其按層次遍歷的節點值。 &#xff08;即逐層地&#xff0c;從左到右訪問所有節點&#xff09;。 例如: 給定二叉樹: [3,9,20,null,null,15,7], 3 / \ 9 20 / \ 15 7 返回其層次遍歷結果&#xff1a; [ [3], [9,20], [15…

Windows Git客戶端搭建

最近開始做Windows 開發&#xff0c;所以找了一些windows下安裝git的教程 本文環境&#xff1a; 操作系統&#xff1a;Windows XP SP3 Git客戶端&#xff1a;TortoiseGit-1.8.16.0-32bit 一、安裝Git客戶端 全部安裝均采用默認&#xff01; 1. 安裝支撐軟件 msysgit: http://ms…

C++(23)--多態性與虛函數

多態性與虛函數1.靜態多態-重載2.動態多態-重寫2.1 向上轉換/向下轉換3.虛函數的工作原理4.純虛函數和抽象類5.補充項目(都市浮生記)-卒《老九學堂C課程》學習筆記。《老九學堂C課程》詳情請到B站搜索《老九零基礎學編程C入門》-------------簡單的事情重復做&#xff0c;重復的…

如何在Appscale下發布自己的應用(一)

本篇文章主要講如何在本地搭建appscale環境。由于國內的信息資源有限&#xff0c;很多重要的論壇被墻了&#xff0c;所以遇到不少麻煩&#xff0c;由于最近一段時間vpn也被封掉了&#xff0c;我只能通過特殊渠道方法來翻墻查閱資料&#xff0c;走了不少彎路。 1.先說系統和環境…

總結了線程安全性的二十四個精華問題

1、對象的狀態&#xff1a;對象的狀態是指存儲在狀態變量中的數據&#xff0c;對象的狀態可能包括其他依賴對象的域。在對象的狀態中包含了任何可能影響其外部可見行為的數據。 2、一個對象是否是線程安全的&#xff0c;取決于它是否被多個線程訪問。這指的是在程序中訪問對象的…

如何在Appscale下發布自己的應用(二)

本文開始講如何發布自己的app應用到appscle上 建好appscle網站后&#xff0c;可以在命令行通過 appscle deploy apppathname 來發布自己應用。 除了用命令行提交應用之外&#xff0c;還可以通過appscale的網站直接提交&#xff0c;選擇 upload application->選擇上傳文件-&g…

Python模塊(7)-SciPy 簡易使用教程

SciPy 簡易使用教程1. 符號計算2. 函數向量化3. 波形處理scipy.signal3.1 濾波器3.2 波峰定位基于numpy的一個高級模塊&#xff0c;為數學&#xff0c;物理&#xff0c;工程等方面的科學計算提供無可替代的支持。 做重要的思想是&#xff1a;符號計算和函數向量化 1. 符號計算…