JavaScript實(shí)現(xiàn)in-place思想的快速排序方法
快速排序,又稱劃分交換排序。以分治法為策略實(shí)現(xiàn)的快速排序算法。
本文主要要談的是利用javascript實(shí)現(xiàn)in-place思想的快速排序
分治法:
在計(jì)算機(jī)科學(xué)中,分治法是建基于多項(xiàng)分支遞歸的一種很重要的算法范式。字面上的解釋是“分而治之”,就是把一個(gè)復(fù)雜的問題分成兩個(gè)或更多的相同或相似的子問題,直到最后子問題可以簡(jiǎn)單的直接求解,原問題的解即子問題的解的合并。(摘自維基百科)
快速排序的思想
數(shù)組中指定一個(gè)元素作為標(biāo)尺,比它大的放到該元素后面,比它小的放到該元素前面,如此重復(fù)直至全部正序排列。
快速排序分三步:
選基準(zhǔn):在數(shù)據(jù)結(jié)構(gòu)中選擇一個(gè)元素作為基準(zhǔn)(pivot)
劃分區(qū):參照基準(zhǔn)元素值的大小,劃分無序區(qū),所有小于基準(zhǔn)元素的數(shù)據(jù)放入一個(gè)區(qū)間,所有大于基準(zhǔn)元素的數(shù)據(jù)放入另一區(qū)間,分區(qū)操作結(jié)束后,基準(zhǔn)元素所處的位置就是最終排序后它應(yīng)該所處的位置
遞歸:對(duì)初次劃分出來的兩個(gè)無序區(qū)間,遞歸調(diào)用第 1步和第 2步的算法,直到所有無序區(qū)間都只剩下一個(gè)元素為止。
現(xiàn)在先說說普遍的實(shí)現(xiàn)方法(沒有用到原地算法)
function quickSort(arr) { if (arr.length <= 1) return ; //取數(shù)組最接近中間的數(shù)位基準(zhǔn),奇數(shù)與偶數(shù)取值不同,但不印象,當(dāng)然,你可以選取第一個(gè),或者最后一個(gè)數(shù)為基準(zhǔn),這里不作過多描述 var pivotIndex = Math.floor(arr.length / 2); var pivot = arr.splice(pivotIndex, 1)[0]; //左右區(qū)間,用于存放排序后的數(shù) var left = []; var right = []; console.log('基準(zhǔn)為:' + pivot + ' 時(shí)'); for (var i = 0; i < arr.length; i++) { console.log('分區(qū)操作的第 ' + (i + 1) + ' 次循環(huán):'); //小于基準(zhǔn),放于左區(qū)間,大于基準(zhǔn),放于右區(qū)間 if (arr[i] < pivot) { left.push(arr[i]); console.log('左邊:' + (arr[i])) } else { right.push(arr[i]); console.log('右邊:' + (arr[i])) } } //這里使用concat操作符,將左區(qū)間,基準(zhǔn),右區(qū)間拼接為一個(gè)新數(shù)組 //然后遞歸1,2步驟,直至所有無序區(qū)間都 只剩下一個(gè)元素 ,遞歸結(jié)束 return quickSort(left).concat([pivot], quickSort(right)); } var arr = [14, 3, 15, 7, 2, 76, 11]; console.log(quickSort(arr)); /* * 基準(zhǔn)為7時(shí),第一次分區(qū)得到左右兩個(gè)子集[ 3, 2,] 7 [14, 15, 76, 11]; * 以基準(zhǔn)為2,對(duì)左邊的子集[3,2]進(jìn)行劃分區(qū)排序,得到[2] 3。左子集排序全部結(jié)束 * 以基準(zhǔn)為76,對(duì)右邊的子集進(jìn)行劃分區(qū)排序,得到[14, 15, 11] 76 * 此時(shí)對(duì)上面的[14, 15, 11]以基準(zhǔn)為15再進(jìn)行劃分區(qū)排序, [14, 11] 15 * 此時(shí)對(duì)上面的[14, 11]以基準(zhǔn)為11再進(jìn)行劃分區(qū)排序, 11 [14] * 所有無序區(qū)間都只剩下一個(gè)元素,遞歸結(jié)束 * */
通過斷點(diǎn)調(diào)試,可得出結(jié)果。
弊端:
它需要Ω(n)的額外存儲(chǔ)空間,跟歸并排序一樣不好。在生產(chǎn)環(huán)境中,需要額外的內(nèi)存空間,影響性能。
同時(shí),很多人認(rèn)為上邊的就是真正的快速排序了。 所以,在下面,很有必要的推薦in-place算法的快速排序
有關(guān)于原地算法可參考維基百科,被墻的同學(xué),百度也差不多。
in-place
快速排序一般是用遞歸實(shí)現(xiàn),最關(guān)鍵是partition分割函數(shù),它將數(shù)組劃分為兩部分,一部分小于pivot,另一部分大于pivot。具體原理上邊提過
function quickSort(arr) { // 交換 function swap(arr, a, b) { var temp = arr[a]; arr[a] = arr[b]; arr[b] = temp; } // 分區(qū) function partition(arr, left, right) { /** * 開始時(shí)不知最終pivot的存放位置,可以先將pivot交換到后面去 * 這里直接定義最右邊的元素為基準(zhǔn) */ var pivot = arr[right]; /** * 存放小于pivot的元素時(shí),是緊挨著上一元素的,否則空隙里存放的可能是大于pivot的元素, * 故聲明一個(gè)storeIndex變量,并初始化為left來依次緊挨著存放小于pivot的元素。 */ var storeIndex = left; for (var i = left; i < right; i++) { if (arr[i] < pivot) { /** * 遍歷數(shù)組,找到小于的pivot的元素,(大于pivot的元素會(huì)跳過) * 將循環(huán)i次時(shí)得到的元素,通過swap交換放到storeIndex處, * 并對(duì)storeIndex遞增1,表示下一個(gè)可能要交換的位置 */ swap(arr, storeIndex, i); storeIndex++; } } // 最后: 將pivot交換到storeIndex處,基準(zhǔn)元素放置到最終正確位置上 swap(arr, right, storeIndex); return storeIndex; } function sort(arr, left, right) { if (left > right) return; var storeIndex = partition(arr, left, right); sort(arr, left, storeIndex - 1); sort(arr, storeIndex + 1, right); } sort(arr, 0, arr.length - 1); return arr; } console.log(quickSort([8, 4, 90, 8, 34, 67, 1, 26, 17]));
分區(qū)的優(yōu)化
這里細(xì)心的同學(xué)可能會(huì)提出,選取不同的基準(zhǔn)時(shí),是否會(huì)有不同性能表現(xiàn),答案是肯定的,但,因?yàn)?,我是搞前端的,?duì)算法不是很了解,所以,這個(gè)坑留給厲害的人來填補(bǔ)。
復(fù)雜度
快速排序是排序速度最快的算法,它的時(shí)間復(fù)雜度是O(log n)
在平均狀況下,排序n個(gè)項(xiàng)目要Ο(n log n)次比較。在最壞狀況下則需要Ο(n2)次比較.
以上所述是小編給大家介紹的JavaScript實(shí)現(xiàn)in-place思想的快速排序方法,希望對(duì)大家有所幫助,如果大家有任何疑問歡迎給我留言,小編會(huì)及時(shí)回復(fù)大家的,在此也非常感謝大家對(duì)腳本之家網(wǎng)站的支持!
- JavaScript對(duì)象數(shù)組排序?qū)嵗椒\析
- JavaScript對(duì)象數(shù)組如何按指定屬性和排序方向進(jìn)行排序
- JavaScript sort數(shù)組排序方法和自我實(shí)現(xiàn)排序方法小結(jié)
- 基于JS實(shí)現(xiàn)數(shù)字+字母+中文的混合排序方法
- 分享javascript實(shí)現(xiàn)的冒泡排序代碼并優(yōu)化
- 深入理解js數(shù)組的sort排序
- JS實(shí)現(xiàn)table表格數(shù)據(jù)排序功能(可支持動(dòng)態(tài)數(shù)據(jù)+分頁效果)
- JS學(xué)習(xí)之表格的排序簡(jiǎn)單實(shí)例
相關(guān)文章
8 行 Node.js 代碼實(shí)現(xiàn)代理服務(wù)器
JavaScript 前后端通吃,在全棧開發(fā)領(lǐng)域具有獨(dú)特的優(yōu)勢(shì)。今天就來看看作為服務(wù)端語言的 JavaScript,完成一個(gè)簡(jiǎn)單的代理服務(wù)器功能是多么容易。2016-12-12基于css3新屬性transform及原生js實(shí)現(xiàn)鼠標(biāo)拖動(dòng)3d立方體旋轉(zhuǎn)
這篇文章主要介紹了基于css3新屬性transform及原生js實(shí)現(xiàn)鼠標(biāo)拖動(dòng)3d立方體旋轉(zhuǎn) 的相關(guān)資料,需要的朋友可以參考下2016-06-06基于JavaScript+HTML5 實(shí)現(xiàn)打地鼠小游戲邏輯流程圖文詳解(附完整代碼)
打地鼠小游戲大家都喜歡玩,本文是以html編寫的,并且使用HBulider軟件進(jìn)行編寫的,下面通過本文給大家分享基于JavaScript+HTML5 實(shí)現(xiàn)打地鼠小游戲邏輯流程圖文詳解,需要的朋友參考下吧2017-11-11拖動(dòng)table標(biāo)題實(shí)現(xiàn)改變td的大小(css+js代碼)
拖動(dòng)列寬的表格table標(biāo)題同時(shí)改變td的大小,本文將以實(shí)例演示為大家呈現(xiàn),感興趣的朋友可以參考下哈,希望對(duì)你學(xué)習(xí)js或者css有所幫助2013-04-04js和jQuery以及easyui實(shí)現(xiàn)對(duì)下拉框的指定賦值方法
下面小編就為大家分享一篇js和jQuery以及easyui實(shí)現(xiàn)對(duì)下拉框的指定賦值方法,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過來看看吧2018-01-01JavaScript實(shí)現(xiàn)數(shù)組對(duì)象去重的多種方法
這篇文章主要介紹了JavaScript實(shí)現(xiàn)數(shù)組對(duì)象去重的多種方法,使用set對(duì)象或使用`reduce`方法,本文結(jié)合示例代碼給大家介紹的非常詳細(xì),需要的朋友參考下吧2023-02-02JavaScript時(shí)間與時(shí)間戳的轉(zhuǎn)換操作實(shí)例分析
這篇文章主要介紹了JavaScript時(shí)間與時(shí)間戳的轉(zhuǎn)換操作,結(jié)合實(shí)例形式分析了javascript日期與時(shí)間戳轉(zhuǎn)換相關(guān)函數(shù)與操作技巧,需要的朋友可以參考下2018-12-12