偶然看到阮一峰老师博客中几年前的一个快速排序算法,每次循环一次都要创建两个额外数组,如果数据量大的话要占用不少额外内存。但是数组是引用类型,是可修改的,可以直接操作原数组本身来节约内存。
下面自己写了一个,当做练手。(除去标准的双向分类外,还稍稍优化了代码,也加了单项优化方法,使其更加简洁)
快速排序方法的关键在于选取一个值,将整个数组分为两部分,小的在左,大的在右,下面就是这个函数的写法:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43
| function swap(arr, index1, index2) { let data = arr[index1]; arr[index1] = arr[index2]; arr[index2] = arr[index1]; } function partition(arr, start, end) { let keyIndex = end, key = arr[keyIndex]; let i = start, j = end, order = true; while(i != j) { if(order) { if (arr[i]>key) { swap(arr, i, j); order = false; } else { i++; } } else { if(arr[j]<key) { swap(arr, i, j); order = true; } else { j--; } } } return i; }
|
观察分组算法partition不难发现,其实i和j位置上始终有一个存着key值,然后和比它大或者比它小的值进行交换。那么我们也可以将其写成一个单向的分组方法:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
| function partition2(arr, start, end) { let keyIndex = end, key = arr[end]; let i = start -1, j = start; for (;j<end;j++) { if (arr[j]< key) { i++; if (i != j) { swap(arr, i, j); } } } ++i; swap(arr, i, end); return i; }
|
接下来递归调用分组函数,将整个数组排序:
1 2 3 4 5 6 7 8 9 10
| function quickSort(arr, start, end) { if (start == end) return; let index = partition(arr, start, end); if (index > start){ quickSort(arr, start, index-1); } if (index<end) { quickSort(arr, index+1, end); } }
|
代码请见: Github