leetcode 912 排序树组 JavaScript
快速排序思路:
首先定义left和right分别指向要遍历数组的头和尾,并设置基数pivot作为参照,把所有比pivot大的数放在pivot的右边,把所有比pivot小的数放pivot左边。
假设基数均为当前遍历数组的最左边left的值(nums[left])
如果想设置其他值为pivot,需要把该值移到最左边。
①首先从right开始向左遍历,当找到比pivot小的数之后,将right的值放到left中,之后right暂停遍历,轮到left
②左边从left+1开始遍历,当找到比pivot大的数之后,将left的值放到right中,之后left暂停遍历,轮到right
③重复 ①②,直到left>=right,本轮遍历结束 之后就会形成左边:比pivot小的数,pivot,右边:比pivot大的数 接下来将左边、右边的数组继续进行相同的操作,直到排序完成。
举例:
5 2 3 1 初始left == 0,right == 3,pivot == 5
从1开始向左遍历,发现1<5,此时将1放到下标left的位置,形成1 2 3 1,right暂停遍历
下一步left++,从2开始遍历,2<5,继续遍历,3<5,继续遍历,此时left和right重合了,将pivot放到重合位置,本次遍历完成,结果为1 2 3 5
之后是对基数位置的左边数组、右边数组分别执行相同的操作,发现右边没数组了,右边完成,左边为1 2 3 ,继续按上述步骤执行…直到左边完成遍历。
代码如下:
var sortArray = function(nums) {
if(nums.length==0||nums.length==1) return nums;
return quickSort(nums,0,nums.length-1);
};
function quickSort(nums,L,R){
if(L>=R) return nums;
let left = L;
let right = R;
let pivot = nums[left];//基准
while(left<right){
while(left<right&&nums[right]>pivot){
right--;
}
if(left<right){
nums[left++]=nums[right];
}
while(left<right&&nums[left]<pivot){
left++;
}
if(left<right){
nums[right--]=nums[left];
}
}
nums[left] = pivot;
quickSort(nums,L,left-1);
quickSort(nums,left+1,R);
return nums;
}
上述代码是完全按照快速排序的图解实现的,也就是当right动的时候,left不动,操作完之后,left才动。left动的时候right不动。
接下来还有一种(partition),left和right分别进行移动直到两边都停住,然后交换left和right的值,同样是直到left和right擦肩而过时遍历结束(耗时较长,不贴了)
还有一种实现思路,就是设基准之后,直接给它进行对应的左右放置,大的丢到基准右边,小的丢到基准左边。然后分别对两边执行相同的操作,详情见阮一峰JavaScript实现快速排序。
归并排序思路:
首先是递归分解,每次拆一半,直到拆分到长度1停止,之后将拆分的元素合并,合并完成后完成排序
var sortArray = function(nums) {
if(nums.length==0||nums.length==1) return nums;
let left = 0;
let right = nums.length-1;
let temp = [];
mergeSort(nums,left,right,temp);
return nums;
};
function mergeSort(nums,left,right,temp){
if(left<right){
let mid = Math.floor(left+(right-left)/2);
mergeSort(nums,left,mid,temp);//左递归分解
mergeSort(nums,mid+1,right,temp);//右递归分解
merge(nums,left,mid,right,temp);//合并
}
}
function merge(nums,left,mid,right,temp){
let i = left;
let j = mid+1;
let t = 0;//temp数组的索引
while(i<=mid&&j<=right){//这里比较两边指针的大小,一个个放入temp中,哪边先遍历完成则结束
if(nums[i]>=nums[j]){
temp[t++] = nums[j++]
}
else temp[t++] = nums[i++]
}
//下面两个while是确保刚刚结束后剩余的另外一个有序数组也遍历完放入temp中
while(i<=mid){
temp[t++] = nums[i++]
}
while(j<=right){
temp[t++] = nums[j++]
}
t = 0;//重新置0
let tempLeft = left;//拷贝left到right的内容到nums
while(tempLeft<=right)//将temp内容拷贝到nums
nums[tempLeft++] = temp[t++]
}