JS家的排序算法

2021-12-29 算法與數學之美
引子

有句話怎麼說來著:

雷鋒推倒雷峰塔,Java implements JavaScript.

當年,想憑藉抱Java大腿火一把而不惜把自己名字給改了的JavaScript(原名LiveScript),如今早已光芒萬丈。node JS的出現更是讓JavaScript可以前後端通吃。雖然Java依然制霸企業級軟體開發領域(C/C + +的大神們不要打我。。。),但在Web的江湖,JavaScript可謂風頭無兩,坐上了頭把交椅。

然而,在傳統的計算機算法和數據結構領域,大多數專業教材和書籍的默認語言都是Java或者C/C+ +。這給最近想惡補算法和數據結構知識的我造成了一定困擾,因為我想尋找一本以JavaScript為默認語言的算法書籍。當我了解到O』REILLY家的動物叢書系列裡有一本叫做《數據結構與算法JavaScript描述》時,便興奮的花了兩天時間把這本書從頭到尾讀了一遍。它是一本很好的針對前端開發者們的入門算法書籍,可是,它有一個很大的缺陷,就是裡面有很多明顯的小錯誤,明顯到就連我這種半路出家的程序猿都能一眼看出來。還有一個問題是,很多重要的算法和數據結構知識並沒有在這本書裡被提到。這些問題對於作為一個晚期強迫症患者的我來說簡直不能忍。於是乎,一言不合我就決定自己找資料總結算法。那麼,我就從算法領域裡最基礎的知識點——排序算法總結起好了。

我相信以下的代碼裡一定會有某些bug或錯誤或語法不規範等問題是我自己無法發現的,所以敬請各位大神能夠指出錯誤,因為只有在不斷改錯的道路上我才能取得長久的進步。

十大經典算法排序總結對比

一張圖概括:


主流排序算法概覽

名詞解釋:

n: 數據規模
k:「桶」的個數
In-place: 佔用常數內存,不佔用額外內存
Out-place: 佔用額外內存
穩定性:排序後2個相等鍵值的順序和排序之前它們的順序相同

冒泡排序(Bubble Sort)冒泡排序須知:

作為最簡單的排序算法之一,冒泡排序給我的感覺就像Abandon在單詞書裡出現的感覺一樣,每次都在第一頁第一位,所以最熟悉。。。冒泡排序還有一種優化算法,就是立一個flag,當在一趟序列遍歷中元素沒有發生交換,則證明該序列已經有序。但這種改進對於提升性能來說並沒有什麼太大作用。。。

什麼時候最快(Best Cases):

當輸入的數據已經是正序時(都已經是正序了,我還要你冒泡排序有何用啊。。。。)

什麼時候最慢(Worst Cases):

當輸入的數據是反序時(寫一個for循環反序輸出數據不就行了,幹嘛要用你冒泡排序呢,我是閒的嗎。。。)

冒泡排序動圖演示:


 

冒泡排序JavaScript代碼實現:

function bubbleSort(arr) {    var len = arr.length;    for (var i = 0; i < len; i++) {        for (var j = 0; j < len - 1 - i; j++) {            if (arr[j] > arr[j+1]) {        

選擇排序(Selection Sort)選擇排序須知:

在時間複雜度上表現最穩定的排序算法之一,因為無論什麼數據進去都是O(n²)的時間複雜度。。。所以用到它的時候,數據規模越小越好。唯一的好處可能就是不佔用額外的內存空間了吧。

選擇排序動圖演示:


Selection Sort 動圖演示 算法可視化來源:http://visualgo.net/

選擇排序JavaScript代碼實現:

function selectionSort(arr) {    var len = arr.length;    var minIndex, temp;    for (var i = 0; i < len - 1; i++) {        minIndex = i;        for (var j = i + 1; j < len; j++) {            if (arr[j] < arr[minIndex]) {    

插入排序(Insertion Sort)插入排序須知:

插入排序的代碼實現雖然沒有冒泡排序和選擇排序那麼簡單粗暴,但它的原理應該是最容易理解的了,因為只要打過撲克牌的人都應該能夠秒懂。當然,如果你說你打撲克牌摸牌的時候從來不按牌的大小整理牌,那估計這輩子你對插入排序的算法都不會產生任何興趣了。。。
插入排序和冒泡排序一樣,也有一種優化算法,叫做拆半插入。對於這種算法,得了懶癌的我就套用教科書上的一句經典的話吧:感興趣的同學可以在課後自行研究。。。

插入排序動圖演示:


Insertion Sort 動圖演示 算法可視化來源:http://visualgo.net/

插入排序JavaScript代碼實現:

function insertionSort(arr) {    var len = arr.length;    var preIndex, current;    for (var i = 1; i < len; i++) {        preIndex = i - 1;        current = arr[i];        while(preIndex >= 0 && arr[preIndex] > current) {            arr[preIndex+1] = arr[preIndex];            preIndex--;        }        arr[preIndex+1] = current;    }    return arr;}

希爾排序(Shell Sort)希爾排序須知:

希爾排序是插入排序的一種更高效率的實現。它與插入排序的不同之處在於,它會優先比較距離較遠的元素。希爾排序的核心在於間隔序列的設定。既可以提前設定好間隔序列,也可以動態的定義間隔序列。動態定義間隔序列的算法是《算法(第4版》的合著者Robert Sedgewick提出的。在這裡,我就使用了這種方法。

希爾排序JavaScript代碼實現:

function shellSort(arr) {    var len = arr.length,        temp,        gap = 1;    while(gap < len/3) {          

歸併排序(Merge Sort)歸併排序須知:

作為一種典型的分而治之思想的算法應用,歸併排序的實現由兩種方法:

自上而下的遞歸(所有遞歸的方法都可以用迭代重寫,所以就有了第2種方法)

自下而上的迭代

在《數據結構與算法JavaScript描述》中,作者給出了自下而上的迭代方法。但是對於遞歸法,作者卻認為:

However, it is not possible to do so in JavaScript, as the recursion goes too deep
for the language to handle.
然而,在 JavaScript 中這種方式不太可行,因為這個算法的遞歸深度對它來講太深了。

說實話,我不太理解這句話。意思是JavaScript編譯器內存太小,遞歸太深容易造成內存溢出嗎?還望有大神能夠指教。
和選擇排序一樣,歸併排序的性能不受輸入數據的影響,但表現比選擇排序好的多,因為始終都是O(n log n)的時間複雜度。代價是需要額外的內存空間。

歸併排序動圖演示:


Merge Sort 動圖演示 算法可視化來源:http://visualgo.net/

歸併排序JavaScript代碼實現:

function mergeSort(arr) {  

快速排序(Quick Sort)快速排序須知:

又是一種分而治之思想在排序算法上的典型應用。本質上來看,快速排序應該算是在冒泡排序基礎上的遞歸分治法。
快速排序的名字起的是簡單粗暴,因為一聽到這個名字你就知道它存在的意義,就是快,而且效率高! 它是處理大數據最快的排序算法之一了。雖然Worst Case的時間複雜度達到了O(n²),但是人家就是優秀,在大多數情況下都比平均時間複雜度為O(n log n) 的排序算法表現要更好,可是這是為什麼呢,我也不知道。。。好在我的強迫症又犯了,查了N多資料終於在《算法藝術與信息學競賽》上找到了滿意的答案:

快速排序的最壞運行情況是O(n²),比如說順序數列的快排。但它的平攤期望時間是O(n log n) ,且O(n log n)記號中隱含的常數因子很小,比複雜度穩定等於O(n log n)的歸併排序要小很多。所以,對絕大多數順序性較弱的隨機數列而言,快速排序總是優於歸併排序。

快速排序動圖演示:


Quick Sort 動圖演示 算法可視化來源:http://visualgo.net/

快速排序JavaScript代碼實現:

function var temp = arr[i];    arr[i] = arr[j];    arr[j] = temp;}

堆排序(Heap Sort)堆排序須知:

堆排序可以說是一種利用堆的概念來排序的選擇排序。分為兩種方法:

大頂堆:每個節點的值都大於或等於其子節點的值,在堆排序算法中用於升序排列

小頂堆:每個節點的值都小於或等於其子節點的值,在堆排序算法中用於降序排列

堆排序動圖演示:


Heap Sort 動圖演示 算法可視化來源:http://www.ee.ryerson.ca/~courses/coe428/sorting/heapsort.html

堆排序JavaScript代碼實現:

return arr;}

計數排序(Counting Sort)計數排序須知:

計數排序的核心在於將輸入的數據值轉化為鍵存儲在額外開闢的數組空間中。
作為一種線性時間複雜度的排序,計數排序要求輸入的數據必須是有確定範圍的整數。

計數排序動圖演示:


Counting Sort 動圖演示 算法可視化來源:http://visualgo.net/

計數排序JavaScript代碼實現:

function countingSort(arr, maxValue) {    var bucket = new Array(maxValue+1),        sortedIndex = 0;        arrLen = arr.length,        bucketLen = maxValue + 1;    for (var i = 0; i < arrLen; i++) {        if (!bucket[arr[i]]) {            bucket[arr[i]] = 0;        }        bucket[arr[i]]++;    }    for (var j = 0; j < bucketLen; j++) {        while(bucket[j] > 0) {            arr[sortedIndex++] = j;            bucket[j]--;        }    }    return arr;}

桶排序(Bucket Sort)桶排序須知:

桶排序是計數排序的升級版。它利用了函數的映射關係,高效與否的關鍵就在於這個映射函數的確定。
為了使桶排序更加高效,我們需要做到這兩點:

在額外空間充足的情況下,儘量增大桶的數量

使用的映射函數能夠將輸入的N個數據均勻的分配到K個桶中

同時,對於桶中元素的排序,選擇何種比較排序算法對於性能的影響至關重要。

什麼時候最快(Best Cases):

當輸入的數據可以均勻的分配到每一個桶中

什麼時候最慢(Worst Cases):

當輸入的數據被分配到了同一個桶中

桶排序JavaScript代碼實現:

return arr;}

基數排序(Radix Sort)基數排序須知:

基數排序有兩種方法:

MSD 從高位開始進行排序

LSD 從低位開始進行排序

基數排序 vs 計數排序 vs 桶排序

這三種排序算法都利用了桶的概念,但對桶的使用方法上有明顯差異:
基數排序:根據鍵值的每位數字來分配桶
計數排序:每個桶只存儲單一鍵值
桶排序:每個桶存儲一定範圍的數值

LSD基數排序動圖演示:


Radix Sort 動圖演示 算法可視化來源:http://visualgo.net/

基數排序JavaScript代碼實現:

∑編輯 | Gemini

來源 | 簡書

算法數學之美微信公眾號歡迎賜稿

稿件涉及數學、物理、算法、計算機、編程等相關領域,經採用我們將奉上稿酬。

投稿郵箱:math_alg@163.com

相關焦點

  • 排序算法:歸併排序
    在日常開發中經常會遇到一類問題,就是對一個集合的數據進行排序掌握一些排序算法,對於日常開發是非常有幫助今天介紹一下歸併排序法01算法邏輯02時間複雜度由上圖邏輯可以得出,歸併排序的循環次數為由算法導論的主定理可以推導出,可見之前的文章(文末有連結)歸併排序的時間複雜度為03空間複雜度由上圖邏輯可以得出,歸併排序每次分解都是要復一份新的數據片段
  • 我把七大JS排序算法做成了可視化!!
    ,從而更加容易理解各種排序的實現過程。前言寫這篇文章是有原因的,偶然我看到了一個Java的50種排序算法的可視化的視頻,但是此視頻卻沒給出具體的實現教程,於是我心裡就想著,我可以用JavaScript + canvas去實現這個酷炫的效果。每種排序算法的動畫效果基本都不一樣哦。
  • 快速掌握Java的希爾排序與快速排序算法
    排序算法,是作為程式設計師的基礎算法,也是一定要具備的,如剛從學校出來或者剛轉行過來的夥伴,筆者的建議是要掌握這些基礎的算法,這一篇講解的是希爾排序和快速排序,後續講解哈希表。從此,希爾排序誕生,它就是解決插入排序的更加高效。希爾排序希爾排序在1959年提出而得名,英文Shell’s Sort,它是一種插入排序,又稱「縮小增量排序」。這種插入排序算法比傳統的插入排序算法更加高效。這種算法是非常的穩定。
  • 【算法知識】詳解直接插入排序算法
    】詳解選擇冒泡算法【算法知識】詳解選擇排序算法在玩撲克牌的時候,我們抽到一張牌的時候,都是將它插入到當前手中牌的合適位置的。如下圖:(上圖來自算法導論)直接插入排序也是這樣的思想。基本思想 插入排序的思想是:將待排序序列分成兩個序列,前面的序列保持有序,依次選取後面的序列的元素,在前面的序列中進行插入。初始時,有序序列的長度為1。
  • 力扣(LeetCode)- 常見的排序算法總結
    如何分析一個排序算法好壞時間複雜度、比較和交換次數、原地排序(空間複雜度為(1))、排序穩定性(相等元素之間的位置先後順序不變)。有序度:是數組中具有有序關係的元素對的個數逆序度:和有序度相反。選擇排序是不穩定排序,所以應用最少。
  • Python中排序算法的重要性,希爾排序 ShellSort,中級python技術
    Python中排序算法的重要性排序是計算機科學中最深入研究的算法之一。有許多不同的排序實現和應用程式,您可以使用它們來提高代碼的效率。55 65 97下面給出嚴格按照定義來寫的希爾排序關於排序算法,我總結了幾篇,大家有興趣可以去瀏覽下:
  • JS數組排序技巧匯總(冒泡、sort、快速、希爾等排序)
    本文實例總結了JS數組排序技巧。分享給大家供大家參考,具體如下:1、冒泡排序var array = [8, 6, 9, 2, 1];var temp = 0;for (var i = 0; i < array.length; i++){for (var j = 0; j < array.length - i; j++){if (array[
  • mysql 002|order by的排序算法竟然是這樣的!
    拋出本文問題order by 的排序流程是什麼?order by 的排序算法是什麼?order by 的優化點在於什麼?了解完了這個參數值,我們可以介紹兩種排序流程:一次排序二次排序一次排序不是一個專業術語,按照我的理解來解讀,排序流程需要一次讀取磁碟
  • 5分鐘弄懂的五大常用算法之「分治法」,以C語言歸併排序算法為例
    分治算法,顧名思義就是「分而治之」,即把規模較大的複雜問題拆分為若干規模較小的類似子問題,並逐個解決,最後再將各個子問題的解決結果合併,得到原始問題的結果的方法。這個技巧是很多高效算法的基礎,例如快速排序算法、歸併排序算法、快速傅立葉變換等等。
  • 手敲一遍數據結構和排序算法
    排序算法 性質記憶 冒泡排序 選擇排序 插入排序 快速排序 歸併排序 希爾排序 堆排序數據結構 數組 堆 棧 隊列 鍊表 二叉樹 二叉搜索樹 圖 哈希表搜索 廣度優先搜索 深度優先搜索附件 排序算法代碼點擊
  • 分享一款帶排序功能的瀑布流插件sortableJs
    它是一款帶排序功能的js masonry瀑布流插件。它能夠使元素以卡片形式顯示,並以masonry瀑布流方式進行布局,通過點擊分類按鈕,可以將卡片按指定的方式動態排序。該插件的github地址為:https://github.com/TristanBlg/sortableJshttps://tc5.us/file/21793581-403218888一、插件使用方法在頁面中引入sortable.min.css和sortable.min.js文件。
  • YouTube調整搜索排序算法:更側重觀看時長
    網易科技訊  10月14日消息,據國外媒體報導,美國視頻網站YouTube最近宣布,將調整其視頻的搜索排序算法根據調整後的算法,如果一個視頻YouTube用戶觀看時間普遍達三分鐘時間,而另一個類似視頻YouTube用戶打開後普遍觀看幾秒鐘後就關閉,那麼前一個視頻將在搜索結果中獲得更高的排名。YouTube 在其官方博客中表示:「今年3月我們對"推薦視頻(Suggested Videos)"功能進行調整,最近對流量分析工具YouTube Analytics進行完善。
  • YouTube:改進排序算法,加大視頻播放時間而非點擊量的權重
    近日YouTube針對這一問題進行了調整,視頻搜索中用到的排序算法將會加大視頻播放時間而非點擊量的權重,如此一來,那些有著優質內容的視頻就會因為觀看時間的優勢而排在搜索結果的前面,而靠標題黨騙點擊量的視頻則會沉下去。此外,YouTube還在自帶的分析工具YouTube Analytics中新增了「播放時間」這一功能,方便用戶查看自己上傳的視頻的播放時間。
  • 每天一道LeetCode算法題——兩數之和
    說來慚愧,算法書看了不止一本,但是看書的時候書裡的練習都沒有怎麼思考,直接看的參考答案,導致了對算法的研究僅僅停留在了解這種程度,缺乏實戰所以在平時coding中也不會將算法知識代入使用。於是開始了LeetCode刷題之旅~題目描述給定一個整數數組 nums 和一個目標值 target,請你在該數組中找出和為目標值的那 兩個 整數,並返回他們的數組下標。
  • web前端開發js數組的sort排序詳解
    1、簡單數組簡單排序<script type="text/javascript">    var
  • 面試常問的數據結構十大經典算法
    ;時間複雜度: 一個算法執行所耗費的時間;空間複雜度:運行完一個程序所需內存的大小;三、時間複雜度四、交換排序1、冒泡排序冒泡排序是一種簡單的排序算法。所以,希爾排序是不穩定的算法。>堆排序(Heapsort)是指利用堆這種數據結構所設計的一種排序算法。
  • 敏哥:深挖亞馬遜A9算法中廣告搜索排序的五大影響因素
    回到今天的寫作主題:今天來給大家繼續深挖亞馬遜的A9算法,之前其實已經寫過好幾篇有關A9算法的乾貨的乾貨文章了,感興趣的老鐵可以看下: 今天主要給大家深挖下亞馬遜A9算法中的廣告搜索排序邏輯,很多的時候大家會覺得一個東西很複雜、很難懂,歸根到底還是沒有學會對事物做拆解,我們想要搞清楚廣告的搜索排序邏輯,首先我們要搞清楚影響廣告搜索排名的主要因素有哪些
  • 基於JAVA實現的史上最好的排序和數據結構入門教程
    前言工作已經有一段時間了,有的時候會跟同事們打趣:「如果你讓我現在去手寫一個快速排序,我怕是真的寫不出來」。如果不接觸一段時間的算法,真的很容易就忘了。不信?你現在想想你自己能不能手寫一個堆排序。經歷過校招的人都知道,算法和數據結構都是不可避免的。在筆試的時候,最主要的就是靠算法題。像拼多多、頭條這種大公司,上來就來幾道算法題,如果你沒AC出來,面試機會都沒有。在面試(現場面或者視頻面)的時候也會問算法題,難度肯定是沒有筆試的時候那麼難的。
  • CatBoost:專治類別型特徵的Boosting算法
    Catboost算法採用的是效率更高的Ordered TS: ,即取在某一給定的樣本排序 中排在樣本 前的樣本 的集合。我們可以看到,這裡第 項的表達為 ,其含義為在某一樣本排序 中的第 項。通過構造樣本的排序, 的估計值 等於:前 個樣本中所有第 個特徵類別為 c 的樣本對應的目標變量的平均值 。
  • 算法是什麼:計算機領域中算法的科普
    偽代碼、流程圖、drakon圖和控制表是表達算法的結構化方法,因為與自然語言相比,它們可以避免許多歧義。程式語言旨在以可由計算機執行的形式表達算法。在計算機系統中,算法是由軟體開發人員以他們選擇的任何程式語言編寫的邏輯。但是,在設計算法時,我們需要記住一些規則。其中包括:輸入:算法至少需要一個或多個輸入值。如果沒有給出輸入,那麼算法將產生什麼輸出呢?