const select = (arr) => {
if (!arr || !Array.isArray(arr)) return
const len = arr.length
if (len < 2) return arr
//双循环不重复
//有序区
for (let i = 0; i < len - 1; i++) {
//存放当前循环中最小index,默认循环初始值
//有序区的末尾坐标,此处应放下面找到的无序区的最小值
let lastMinIdx = i
//无序区找最小值
for (let j = i + 1; j < len; j++) {
if (arr[j] < arr[lastMinIdx]) lastMinIdx = j
}
//将最小值放到有序序列的最后(去掉这一行不稳定)
if (lastMinIdx !== i) {
;[arr[i], arr[lastMinIdx]] = [arr[lastMinIdx], arr[i]]
}
}
return arr
}
4 quick
最好 O(nlogn)、最坏 O(n^2)、平均时间复杂度都是 O(nlogn)
空间复杂度为 O(n), ==不稳定==的排序算法
原理:如果要排序数组中下标从 p 到 r 之间的一组数据,我们选择 p 到 r 之间的任意一个数据作为 pivot(分区点)。我们遍历 p 到 r 之间的数据,将小于 pivot 的放到左边,将大于 pivot 的放到右边,将 pivot 放到两边的中间。经过这一步操作之后,数组 p 到 r 之间的数据就被分成了三个部分,前面 p 到 pivot-1 之间都是小于 pivot 的,后面是 pivot,后面的 pivot+1 到 r 之间是大于 pivot 的,根据分治、递归的处理思想,我们可以用递归排序下标从 p 到 q-1 之间的数据和下标从 q+1 到 r 之间的数据,直到区间缩小为 1,所有的数据都有序了
// 大雪菜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)
}