Copy // 大雪菜version 双指针
// 1 确定分界点 可以arr[l]、arr[r]、arr[(l + r) / 2]
// 2 调整该区间
// 3 递归处理左右子区间
const quick = (arr) => {
if (!arr || !Array.isArray(arr)) return
const len = arr.length
if (len < 2) return arr
const helper = (arr, l, r) => {
if (l >= r) return
//x = arr[r] or arr[(l + r) / 2]
//使得 nums[l..p-1] <= nums[p] < nums[p+1..r]
const pivot = arr[l]
let i = l - 1,
j = r + 1
while (i < j) {
//上面外扩,这里直接先移动
while (arr[++i] < pivot);
while (arr[--j] > pivot);
if (i < j) [arr[i], arr[j]] = [arr[j], arr[i]]
}
//两边对称的
//helper(arr, l, i - 1)
//helper(arr, i, r)
helper(arr, l, j)
helper(arr, j + 1, r)
return arr
}
return helper(arr, 0, len - 1)
}
const quick = (arr) => {
if (!arr || !Array.isArray(arr)) return
const len = arr.length
if (len < 2) return arr
const partition = (arr, l, r) => {
//设最右边为pivot
const pivot = r
let index = l
for (let i = index; i < r; i++) {
if (arr[i] < arr[pivot]) {
//大的放pivot后,小的放pivot前,不稳定
;[arr[i], arr[index]] = [arr[index], arr[i]]
//记录有多少个比pivot小的
index++
}
}
//pivot放左右已排好序列中间
;[arr[index], arr[pivot]] = [arr[pivot], arr[index]]
return index
}
const helper = (arr, l, r) => {
if (l >= r) return
//取得pivot坐标
const pos = partition(arr, l, r)
helper(arr, l, pos - 1)
helper(arr, pos + 1, r)
//返回排序好的当前区
return arr
}
return helper(arr, 0, arr.length - 1)
}
//快选
const quickChoose = (arr, n, k) => {
const helper = (arr, l, r, k) => {
if (l === r) return arr[l]
const x = arr[l]
let i = l - 1,
j = r + 1
while (i < j) {
while (arr[++i] < x);
while (arr[--j] > x);
if (i < j) [arr[i], arr[j]] = [arr[j], arr[i]]
}
//排完后看左边的数字个数
const sl = j - l + 1
if (k <= sl) return helper(arr, l, j, k)
return helper(arr, j + 1, r, k - sl)
}
return helper(arr, 0, n - 1, k)
}