數組的快速排序算法,和並歸排序步驟基本類似。
都是先拆分,后合並。並歸排序是:拆分容易,合並難。 快速排序是:拆分難,合並容易
要理解快速排序,首先要理解拆分邏輯
要素:找一個基准點,通過操作使得數列的左邊全部都是小於他的數,右邊全部都是大於他的數;
1、選中基准點,開始索引 i ,結束索引 j
2、從數列右邊開始往左邊找,找到比基准點小的,交換位置 i++
3、從數列左邊開始往右邊找,找到比基准點大的,交換位置 j--
4、循環執行2、3,直到,i 不是小於 j
例如: 有數組 var arr = [30,24,5,58,18,36,12,42,39];
開始索引 i = 0; 結束索引 j = arr.length-1; 基准點 pivot = arr[i] 即為30
則有如下代碼
var arr = [30,24,5,58,18,36,12,42,39];
var i = 0, j = arr.length-1,pivot = arr[i];
while(i < j ){ //當最后結束時 i = j
//從右往左找,找到比基准點小等的就交換,交換后,基准點的索引變為 j
while(i < j && arr[j] > pivot )
j--; //排除已經滿足條件的點
if(i < j ){
swap(i++,j,arr);
}
//從左往右找,找到比基准點大的就交換,交換后,基准點的索引變為 i
while(i < j && arr[i] <= pivot)
i++; //排除已經滿足條件的點
if(i < j ){
swap(i,j--,arr);
}
}
function swap(a,b,arr){
console.log(a,b,arr[a],arr[b])
var temp = arr[a];
arr[a] = arr[b];
arr[b] = temp;
}
console.log(i,arr); //基准點i,處理好的arr
以上代碼就是快速排序的核心,如果將數列,不斷以上面方式細分,直到分為單個元素。即最后的結果就是一個有序的數列
下面給出完整代碼
var arr = [30,24,5,58,18,36,12,42,39];
function Partition(arr,low,high){
var i = low,j = high,pivot = arr[i];
while(i < j ){
//從右往左找
while(i < j && arr[j] > pivot )
j--;
if(i < j ){
swap(i++,j,arr);
}
//從左往右找
while(i < j && arr[i] <= pivot)
i++;
if(i < j ){
swap(i,j--,arr);
}
}
return i; //返回基准元素位置
}
function swap(a,b,arr){
console.log(a,b,arr[a],arr[b])
var temp = arr[a];
arr[a] = arr[b];
arr[b] = temp;
}
function QuickSort(arr,low,high){
var mid;
if(low < high){
mid = Partition(arr,low,high); //返回基准元素位置
QuickSort(arr,low,mid-1); //左邊快速排序
QuickSort(arr,mid+1,high); //右邊快速排序
}
}
QuickSort(arr,0,arr.length-1);
console.log(arr);
優化擴展:
上面的Partition函數中,不管是從右往左,還是從左往右。都是跟pivot基准元素交換。。實際上,可以先直接左邊和右邊交換,最后再和基准元素交換,減少交換次數。代碼如下
var arr = [30,24,5,58,18,36,12,42,39];
var i = 0, j = arr.length-1,pivot = arr[i];
var mid;
while(i < j ){ //當最后結束時 i = j
//從右往左找
while(i < j && arr[j] > pivot )
j--; //排除已經滿足條件的點
//從左往右找
while(i < j && arr[i] <= pivot)
i++; //排除已經滿足條件的點
//找到兩個點,就相互交換
if(i < j ){
swap(i++,j--,arr);
}
}
//最后將中間點和基准點交換
if(arr[i] > pivot){
mid = i-1;
swap(0,mid,arr);
}else{
mid = i;
swap(0,mid,arr);
}
function swap(a,b,arr){
console.log(a,b,arr[a],arr[b])
var temp = arr[a];
arr[a] = arr[b];
arr[b] = temp;
}
console.log(mid,arr); //基准點mid,處理好的arr
使用js的數組方法 , unshift 和push
使用unshift 和push實現,將數列的基准元素,左邊全部小於他,右邊全部大於他
var arr = [30,24,5,58,18,36,12,42,39];
var i = 0, pivot = arr[0], arr2 = [pivot];
for(var j = 1; j < arr.length; j++ ){
if(arr[j] > pivot){
arr2.push(arr[j]);
}else{
arr2.unshift(arr[j]);
i++;
}
}
console.log(i,arr2);
使用 unshift和push實現的快速排序
var arr = [30,24,5,58,18,36,12,42,39];
function Partition(arr,low,high){
var i = low,pivot = arr[i];
var arr2 = [pivot];
for(var j = low+1; j <= high; j++){
if(arr[j] > pivot){
arr2.push(arr[j]);
}else{
arr2.unshift(arr[j]);
i++;
}
}
j = 0;
for(var k = low ; k <= high ; k++){
arr[k] = arr2[j++];
}
return i; //返回基准元素位置
}
function QuickSort(arr,low,high){
var mid;
if(low < high){
mid = Partition(arr,low,high); //返回基准元素位置
QuickSort(arr,low,mid-1); //左邊快速排序
QuickSort(arr,mid+1,high); //右邊快速排序
}
}
QuickSort(arr,0,arr.length-1);
console.log(arr);
