Javascript中 Array.sort 原理學習

2021-03-02 大前端百科
介紹

sort()是JS中用來排序的一個方法,在我們學習各種經典排序算法的時候, 發現都「白學」了。其實在代碼中一個sort()就可以解決,並且時間複雜度和空間複雜度相對都不會過高。其實sort()不光可以對數組進行排序, 基本數據類型的數組都可以, 並且可以實現對對象數組的排序。


這個sort其實遠比我們想像的更加智能,它會基於要排序的數據量選擇性能更加優秀的排序算法來實現排序。


原理

為什麼sort()都可以排序呢? 而且時間和空間複雜度都還比較優良, 有沒有人想過sort()裡面是怎麼實現的呢?


sort根據數組的長度進行區分的

當你的數組長度是小於一個定值的, 它會直接進行一個插入排序。

當長度大於定值時,有可能會merge排序或者是quick排序, merge和quick會將整個數組進行劃分,進行遞歸,一旦劃分的子數組長度小於定值時, 將不再遞歸劃分,直接進行插入排序。為什麼會這麼排序呢?


原因是,在數據量小的時候,插入排序的常數代價非常低,雖然時間複雜度是O(n平方),但是常數項比較低,此時, 在數據量比較小的時候,優勢就展現出來了。


這個定值是多少?有些人說是60,但是我覺得值得去研究。

數據量大的時候用merge或quick排序

那麼問題又來而來,當數據量比較大需要進行劃分的時候,什麼時候用merge,什麼時候用quick呢?


這就要取決數組的類型了,當是基本數據類型的時候,會用quick, 當是對象類型的時候會用merge。

因為當是基本數據類型的時候不需要考慮穩定性的因素,但是對象類型就要考慮了, 因為對象不止用來排序的這一個屬性, 可能已經在其他屬性已經排好序了, 在此番排序之後還需要保證數組的穩定性。


排序算法對比圖標


插入排序思路

代碼實現

function swap(arr, i, j){
let temp = arr[i];
arr[i] = arr[j];
arr[j] = temp;
}
function insertSort(arr){
if(!arr || arr.length <=1) {
return;
}
for(let i=1; i< arr.length;i++) {
for(let j=i-1; j >= 0; j--) {
if(arr[j] > arr[j+1]) {
swap(arr, j, j+1);
}
else {
break;
}
}
}
}
// let arr = [2,5,3,1,4];
let arr = [8, 3, 4, 5, 11, 6, 7, 9, 10];
insertSort(arr);
console.log(arr);

快速排序思路

快速排序是對冒泡排序的一種改進,採用遞歸分治的方法進行求解。而快排相比冒泡是一種不穩定排序,時間複雜度最壞是O(n^2),平均時間複雜度為O(nlogn),最好情況的時間複雜度為O(nlogn)。


對於快排來說,「基本思想」是這樣的



代碼實現

function swap(arr, i, j){
let temp = arr[i];
arr[i] = arr[j];
arr[j] = temp;
}
function quickSort(arr, from, to) {
// 遞歸出口
if(from > to) {
return;
}
// 設置基準元素
let flag = arr[from];
// 設置兩個哨兵
let left = from;
let right = to;
while(left < right) {
// 1.必須先移動右側哨兵
while(left < right && arr[right] <= flag){
right--;
}
// 2. 移動左側哨兵
while(left < right && arr[left] >= flag){
left++;
}
if(left < right) {
swap(arr, left, right);
}
}
arr[from] = arr[left];
arr[left] = flag;
// 遞歸
quickSort(arr, from, left-1);
quickSort(arr, left+1, to);
}
let arr = [8, 3, 4, 5, 11, 6, 7, 9, 10];
quickSort(arr, 0, arr.length-1);
console.log(arr);

歸併排序原理

歸併和快排都是「基於分治算法」的,分治算法其實應用挺多的,很多分治會用到遞歸,但事實上「分治和遞歸是兩把事」。分治就是分而治之,可以採用遞歸實現,也可以自己遍歷實現非遞歸方式。而歸併排序就是先將問題分解成代價較小的子問題,子問題再採取代價較小的合併方式完成一個排序。

至於歸併的思想是這樣的:

第一次:整串先進行劃分成一個一個單獨,第一次是將序列中(1 2 3 4 5 6---)兩兩歸併成有序,歸併完(xx xx xx xx----)這樣局部有序的序列。

第二次就是兩兩歸併成若干四個(1 2 3 4 5 6 7 8 ----)「每個小局部是有序的」

就這樣一直到最後這個串串只剩一個,然而這個耗費的總次數logn。每次操作的時間複雜的又是O(n)。所以總共的時間複雜度為O(nlogn).



代碼實現

private static void mergesort(int[] array, int left, int right) {
int mid=(left+right)/2;
if(left<right)
{
mergesort(array, left, mid);
mergesort(array, mid+1, right);
merge(array, left,mid, right);
}
}
private static void merge(int[] array, int l, int mid, int r) {
int lindex=l;int rindex=mid+1;
int team[]=new int[r-l+1];
int teamindex=0;

while (lindex<=mid&&rindex<=r) {//先左右比較合併
if(array[lindex]<=array[rindex])
{
team[teamindex++]=array[lindex++];
}
else {
team[teamindex++]=array[rindex++];
}
}
while(lindex<=mid)//當一個越界後剩餘按序列添加即可
{
team[teamindex++]=array[lindex++];
}
while(rindex<=r)
{
team[teamindex++]=array[rindex++];
}
for(int i=0;i<teamindex;i++)
{
array[l+i]=team[i];
}
}


相關焦點

  • JavaScript Array對象
    array.filter(function(currentValue,index,arr), thisValue)indexOf()搜索數組中的元素,並返回它所在的位置。array.indexOf(item,start)join()把數組的所有元素放入一個字符串。
  • JavaScript函數補完:sort()排序
    JavaScript實現多維數組、對象數組排序,其實用的就是原生的sort()方法,用於對數組的元素進行排序。
  • Sort an Array 數組排序
    Given an array of integers nums, sort the array in ascending order.
  • JavaScript實現九種排序算法
    原理圖:代碼:// 先在有序區通過二分查找的方法找到移動元素的起始位置,// 然後通過這個起始位置將後面所有的元素後移function sort2(array) { var len = array.length
  • Graph 新題型 Min Swaps to Sort Array
    後來經人提示才發現實際上這是一道披著 sort 外衣的 graph 題目。」最近我的小夥伴問了一道題非常有趣。題目不難,但是我之前從來沒有遇到過,所以好好研究了一下。現在分享給大家,有更好的解法的同學可以指點我,如果沒見過這題的我們可以一起探討。
  • 12 個非常有用的 JavaScript 技巧
    作者: Caio Ribeiro Pereira轉載自:W3CPlus http://www.w3cplus.com/javascript/12-extremely-useful-hacks-for-javascript.html 譯者: 大漠在這篇文章中將給大家分享12個有關於JavaScript的小技巧。
  • JavaScript中原生Array數組方法詳解
    JS中,數組可以通過陣列構造函數或[]字面量的方式創建。數組是一個特殊的對象,繼承自對象原型,但用typeof運算判斷時,並沒有一個特定的值,仍然返回'對象'。但使用[] instanceof Array返回true。這說明,js中存在一個類數組的對象,就像字符串對象或arguments對象。
  • 每日一課 | JavaScript中的數組
    array.length);在此示例中,我們僅初始化數組,並且未在數組中添加任何元素。如何檢索數組中的第一個和最後一個元素? [array.length - 1] + "<br/>");在JavaScript中聲明數組的不同方法?
  • LeetCode | 實現排序比較函數 | Relative Sort Array
    https://leetcode.com/problems/relative-sort-array/
  • js中的Array對象屬性和方法整理
    javascript中無法通過一個索引去移除一個無素.通過對ARRAY的擴展.實現了對javascript Array對象通過索引移除數組中的一個元素.valueOf()返回數組對象的原始值 1.4 concat()語法: array.concat(value, ...)其中value, ... 要添加到array中的值,可以是任意多個。返回值: 一個新數組,是把指定的所有參數添加到array中構成的。
  • JavaScript 面試中常見算法問題詳解
    JavaScript 面試中常見算法問題詳解,翻譯自 https://github.com/kennymkchan/interview-questions-in-javascript
  • JavaScript實現的9大排序算法
    它的工作原理是通過構建有序序列,對於未排序數據,在已排序序列中從後向前掃描,找到相應位置並插入。插入排序在實現上,通常採用in-place排序(即只需用到O(1)的額外空間的排序),因而在從後向前掃描過程中,需要反覆把已排序元素逐步向後挪位,為最新元素提供插入空間。2)算法描述和實現一般來說,插入排序都採用in-place在數組上實現。
  • Sort題型總結
    Sort題型總結1.Selection Sort 選擇排序Given an array of integers, sort the elements in the array in ascending order.
  • JavaScript中的「黑話」
    true:false;const enable3 =Boolean(id);~ 與 ~~~表示按位取反,~5的運行步驟為:轉為一個字節的二進位表示:00000101,按位取反:11111010取其反碼:10000101取其補碼:10000110轉化為十進位:-6至於原碼、反碼、補碼原理請看原理篇。
  • Javascript數組系列四之數組的轉換與排序Sort方法
    Javascirpt 數組中的方法,數組的轉換是我們在項目的開發過程中,數據類型之間的轉換有著非常重要的作用,而數組轉換成其他數據類型是我們常見的一種。toString該方法是對數組轉換成字符串,數組的每一個元素都會調用 「toString」方法 ,返回一個新字符串。
  • 淺談JavaScript 中 sort( ) 排序的坑
    最近我在項目中就遇到了一個數組排序問題,數組中的項沒有按我預想的被排序,導致界面上無法正常顯示。我花了很長的時間才明白問題究竟出在哪裡,所以想在這裡和大家分享一下。基本排序JS 中的 Array 對象有一個排序方法 sort( ),調用它的運行結果一般來說是這樣的:甚至當數組中出現未定義值的元素時 sort( ) 也同樣好用。
  • Excel – 多條件排序就用 sortby 函數
    O365 這次出了兩個排序函數,除了前段時間給大家講解過的 sort 以外,還有一個 sortby 函數。,用 sort 函數排序。, by_array1, [sort_order1], [by_array2, sort_order2],…) 參數:array:必需,要篩選的區域或數組。
  • 常用排序算法之JavaScript實現
    它的工作原理是通過構建有序序列,對於未排序數據,在已排序序列中從後向前掃描,找到相應位置並插入。插入排序在實現上,通常採用in-place排序(即只需用到O(1)的額外空間的排序),因而在從後向前掃描過程中,需要反覆把已排序元素逐步向後挪位,為最新元素提供插入空間。一般來說,插入排序都採用in-place在數組上實現。
  • javascript 定時器工作原理
    說到 javascript 中的定時器,我們肯定會想到 setTimeout() 和 setInterval() 這兩個函數。
  • 走近 (javascript, 函數式)
    命令式編程:var array = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9];var result = [];for(let i = 0; i < array.length; i++) {array[i] = Math.pow(array[i], 2);if(array[i]%2 !