數(shù)組排序在日常編程中用到的其實(shí)還是比較多的大磺,比如把一組數(shù)據(jù)按時(shí)間排序,按首字母排序滩租,按大小排序等等赋秀,那么就讓我們一起來(lái)了解下常見的數(shù)組排序方法有哪些。
一說(shuō)到數(shù)組排序律想,很多人腦子里第一時(shí)間蹦出來(lái)的可能就是sort()方法沃琅。那我們就從這個(gè)原生的排序方法sort()開始講起。
語(yǔ)法:arrayObject.sort(sortby)
這里的sortby是一個(gè)參數(shù)蜘欲,規(guī)定排序的順序益眉,必須是函數(shù)。
sort()的返回值是對(duì)該數(shù)組的引用姥份,這里要注意的是郭脂,該排序方法會(huì)在原數(shù)組上直接進(jìn)行排序,并不會(huì)生成一個(gè)排好序的新數(shù)組澈歉。
還要注意的是:如果沒(méi)有使用參數(shù)sortby展鸡,那么排序的時(shí)候?qū)?huì)按字母的順序?qū)?shù)組中的元素進(jìn)行排序,說(shuō)精確點(diǎn)是按照字符編碼的順序進(jìn)行排序埃难。如果要實(shí)現(xiàn)這一點(diǎn)莹弊,首先應(yīng)該把數(shù)組的元素都轉(zhuǎn)化成字符串,以便進(jìn)行比較涡尘。
如果想按照其他標(biāo)準(zhǔn)排序忍弛,那么就要傳入?yún)?shù)sortby,即提供比較函數(shù)考抄。該函數(shù)要比較兩個(gè)值细疚,然后返回一個(gè)用于說(shuō)明這兩個(gè)值的相對(duì)順序的數(shù)字。比較參數(shù)應(yīng)該具有兩個(gè)參數(shù)a和b川梅,其返回值如下:
若a小于b疯兼,在排序后的數(shù)組中矛市,a應(yīng)該出現(xiàn)在b之前呼盆,則返回一個(gè)小于0的值
若a=b绢淀,則返回0
若a大于b出刷,則返回一個(gè)大于0的值
我們先來(lái)看兩個(gè)例子,第一個(gè)不傳入?yún)?shù)sortby姨裸,代碼如下:
var arr = ["Zhangsan", "Lisi", "Wangwu", "Hanmei", "Chendu"];
var res = arr.sort();
console.log(res);
// 打印結(jié)果為["Chendu", "Hanmei", "Lisi", "Wangwu", "Zhangsan"]
那么如果數(shù)組元素是數(shù)字呢秧倾?看如下代碼:
var arr = [524, 684, 5, 69, 15];
var res = arr.sort();
console.log(res);
// 打印結(jié)果為[15, 5, 524, 684, 69]
由上面的代碼可以看到,如果數(shù)組元素為數(shù)字的話啦扬,排序并不會(huì)按大小順序排,而是會(huì)按數(shù)字的第一個(gè)字符排序凫碌。
如果我們想要這組數(shù)字按從小到大扑毡,或者從大到小的順序排列的話,那么我們就需要傳入?yún)?shù)sortby盛险,即上文所說(shuō)的比較函數(shù)瞄摊。
function sortNum(a, b) {
return a - b;
}
var arr = [524, 684, 5, 69, 15];
var res = arr.sort(sortNum);
console.log(res);
// 打印結(jié)果為[5, 15, 69, 524, 684]
上面代碼中的sortNum就是一個(gè)比較函數(shù),我們傳入a,b兩個(gè)值苦掘,然后返回a-b的值换帜,跟據(jù)返回值進(jìn)行大小排序,如果想要從大到小排序鹤啡,只需要return b-a即可惯驼。
這里額外提一下reverse()這個(gè)方法,這個(gè)方法用于顛倒數(shù)組中元素的順序递瑰。這里要注意祟牲,只是顛倒,并不是按從大到小的順序抖部,因此我認(rèn)為它算不上是排序方法说贝。
語(yǔ)法:arrayObject.reverse()
demo代碼如下:
var arr = [524, 684, 5, 69, 15];
var res = arr.reverse();
console.log(res);
// 打印結(jié)果為[15, 69, 5, 684, 524]
除了我們常用的sort()方法,其實(shí)還有其他很多方法可以實(shí)現(xiàn)排序:
冒泡排序
快速排序
插入排序
希爾排序
選擇排序(坑未填)
歸并排序(坑未填)
堆排序(坑未填)
一慎颗、冒泡排序
冒泡排序就是遍歷數(shù)組里面的元素乡恕,一次比較兩個(gè)元素,如果它們的順序錯(cuò)誤俯萎,就把它們交換過(guò)來(lái)傲宜,直到?jīng)]有需要交換的兩個(gè)元素為止。它是一種穩(wěn)定排序算法蛋哭。
冒泡排序算法的運(yùn)作如下:(從后往前)
比較相鄰的元素躁愿。如果第一個(gè)比第二個(gè)大跷叉,就交換他們兩個(gè)。
對(duì)每一對(duì)相鄰元素作同樣的工作帖世,從開始第一對(duì)到結(jié)尾的最后一對(duì)。在這一點(diǎn)翔怎,最后的元素應(yīng)該會(huì)是最大的數(shù)。
針對(duì)所有的元素重復(fù)以上的步驟,除了最后一個(gè)。
持續(xù)每次對(duì)越來(lái)越少的元素重復(fù)上面的步驟,直到?jīng)]有任何一對(duì)數(shù)字需要比較。
——引用自百度百科《冒泡排序》
function bubbleSort(arr) {
for(var i = 0; i < arr.length; i++) {
for(var j = 0; j < arr.length; j++) {
if(arr[i] < arr[j]) {
var temp = arr[j];
arr[j] = arr[i];
arr[i] = temp;
}
}
}
return arr;
}
var arr = [524, 684, 5, 69, 15];
bubbleSort(arr);? ? // 結(jié)果為[5, 15, 69, 524, 684]
上面的代碼就是一個(gè)很好理解的冒泡排序?qū)懛ㄕ家#捎脙蓚€(gè)for循環(huán),當(dāng)i=0的時(shí)候搔啊,將arr[0]與數(shù)組里面的每一項(xiàng)比較柬祠,如果arr[0]小于某一項(xiàng),則替換它們的位置负芋,以此類推漫蛔。
二、快速排序
快速排序是對(duì)冒泡排序的一種改進(jìn)示罗。它的基本思想是:通過(guò)一趟排序?qū)⒁判虻臄?shù)據(jù)分割成獨(dú)立的兩部分惩猫,其中一部分的所有數(shù)據(jù)都比另外一部分的所有數(shù)據(jù)都要小芝硬,然后再按此方法對(duì)這兩部分?jǐn)?shù)據(jù)分別進(jìn)行快速排序蚜点,整個(gè)排序過(guò)程可以遞歸進(jìn)行,以此達(dá)到整個(gè)數(shù)據(jù)變成有序序列拌阴。
快速排序的過(guò)程大致分三步:
在數(shù)據(jù)集之中绍绘,選擇一個(gè)元素作為"基準(zhǔn)"(pivot)。
所有小于"基準(zhǔn)"的元素迟赃,都移到"基準(zhǔn)"的左邊陪拘;所有大于"基準(zhǔn)"的元素,都移到"基準(zhǔn)"的右邊纤壁。
對(duì)"基準(zhǔn)"左邊和右邊的兩個(gè)子集左刽,不斷重復(fù)第一步和第二步,直到所有子集只剩下一個(gè)元素為止酌媒。
——引用自阮一峰博客《快速排序的JavaScript實(shí)現(xiàn)》
封裝代碼如下:
function quickSort(arr) {
if(arr.length <= 1) {
return arr;
}
var pivotIndex = Math.floor(arr.length / 2);
var pivot = arr.splice(pivotIndex, 1)[0];
// splice()返回的是被刪除元素組成的數(shù)組
var lef = [];
var rig = [];
for(var i = 0; i < arr.length; i++) {
if(arr[i] < pivot) {
lef.push(arr[i]);
}
else {
rig.push(arr[i]);
}
}
return quickSort(lef).concat(pivot, quickSort(rig)); // 遞歸
}
var arr = [524, 684, 5, 69, 15];
quickSort(arr);? ? // 結(jié)果為[5, 15, 69, 524, 684]
三欠痴、插入排序
已知一個(gè)已有序的數(shù)據(jù)序列,需要插入一個(gè)數(shù)據(jù)秒咨,要求插入數(shù)據(jù)后這個(gè)序列依然有序喇辽,那么這個(gè)時(shí)候就需要使用插入排序。
插入排序把要排序的數(shù)組分成兩部分:第一部分包含了這個(gè)數(shù)組的所有元素雨席,但將最后一個(gè)元素除外(讓數(shù)組多一個(gè)空間才有插入的位置)菩咨,而第二部分就只包含這一個(gè)元素(即待插入元素)。在第一部分排序完成后,再將這個(gè)最后元素插入到已排好序的第一部分中抽米。
用生活中比較好理解的事物就是斗地主特占,你手里的牌已經(jīng)排好序了,摸一張新牌缨硝,要將其插入進(jìn)去摩钙,小的牌會(huì)往前插,大的牌會(huì)往后插查辩。
封裝代碼如下:
function insertSort(arr) {
for(var i = 1; i < arr.length; i++) {
if(arr[i] < arr[i - 1]) {
var temp = arr[i];
var j = i -1;
arr[i] = arr[j];
while(j >= 0 && temp < arr[j]) {
arr[j + 1] = arr[j];
j--;
}
arr[j + 1] = temp;
}
}
}
var arr = [524, 684, 5, 69, 15];
insertSort(arr);
console.log(arr);? ? // 結(jié)果為[5, 15, 69, 92, 524, 684]
如果你是需要在現(xiàn)有的已排好序的數(shù)組中插入新的元素胖笛,并且新數(shù)組也依然排好序,那么上面的代碼就需要修改一下:
function insertSort(arr, a) {
for(var i = 1; i < arr.length; i++) {
if(arr[i] >= a) {
for(var j = arr.length; j > i; j--) {
arr[j] = arr[j - 1];
}
arr[i] = a;
break;
}
}
return arr;
}
var arr = [5, 15, 69, 524, 684];
insertSort(arr, 92);? ? // 結(jié)果為[5, 15, 69, 92, 524, 684]
對(duì)于小型數(shù)組的排列宜岛,插入排序要比前兩種排序方法性能更好长踊。
四、希爾排序
希爾排序是插入排序的一種萍倡,也稱縮小增量排序身弊,是直接插入排序算法的一種更高效的改進(jìn)版本。
希爾排序是把記錄按下標(biāo)的一定增量分組列敲,對(duì)每組使用直接插入排序算法排序阱佛;隨著增量逐漸減少,每組包含的關(guān)鍵詞越來(lái)越多戴而,當(dāng)增量減至1時(shí)凑术,整個(gè)文件恰被分成一組,算法便終止所意。
——引用自百度百科《希爾排序》
封裝代碼如下:
function shellSort(arr) {
var gap = Math.ceil(arr.length / 2);
while(gap > 0) {
for(var k = 0; k < gap; k++) {
var tagArr = [];
tagArr.push(arr[k]);
for(var i = k + gap; i < arr.length; i = i + gap) {
var temp = arr[i];
tagArr.push(temp);
for(var j = i - gap; j > -1; j = j - gap) {
if(arr[j] > temp) {
arr[j + gap] = arr[j];
}
else {
break;
}
}
arr[j + gap] = temp;
}
}
gap = parseInt(gap / 2);
}
return arr;
}
var arr = [524, 684, 5, 69, 15];
shellSort(arr);? ? // 結(jié)果為[5, 15, 69, 92, 524, 684]