생각의 기차
1. 중간 위치 midValue 찾기
2. 배열을 순회하여 midValue보다 작으면 왼쪽에 놓고 midValue보다 크면 오른쪽에 놓습니다.
3. 재귀를 계속하고 마지막으로 연결하고 반환합니다.
midValue를 얻는 방법은 두 가지가 있습니다:
1. splice를 통해 원래 배열이 수정됨
2. 슬라이스를 사용해도 원래 배열이 수정되지 않음 [권장]
2점일 경우 시간 복잡도는 O(logn)이고,
다른 정렬은 일반적으로 O(n^2)이며, 퀵 정렬은 O(n*logn)이 상대적으로 더 좋습니다.
코드
/**
* 快速排序(使用 splice)
* @param arr number arr
*/
export function quickSort1(arr: number[]): number[] {
const length = arr.length
if (length === 0) return arr
const midIndex = Math.floor(length / 2)
const midValue = arr.splice(midIndex, 1)[0]
const left: number[] = []
const right: number[] = []
// 注意:这里不用直接用 length ,而是用 arr.length 。因为 arr 已经被 splice 给修改了
for (let i = 0; i < arr.length; i++) {
const n = arr[i]
if (n < midValue) {
// 小于 midValue ,则放在 left
left.push(n)
} else {
// 大于 midValue ,则放在 right
right.push(n)
}
}
return quickSort1(left).concat(
[midValue],
quickSort1(right)
)
}
/**
* 快速排序(使用 slice)
* @param arr number arr
*/
export function quickSort2(arr: number[]): number[] {
const length = arr.length
if (length === 0) return arr
const midIndex = Math.floor(length / 2)
const midValue = arr.slice(midIndex, midIndex + 1)[0]
const left: number[] = []
const right: number[] = []
for (let i = 0; i < length; i++) {
if (i !== midIndex) {
const n = arr[i]
if (n < midValue) {
// 小于 midValue ,则放在 left
left.push(n)
} else {
// 大于 midValue ,则放在 right
right.push(n)
}
}
}
return quickSort2(left).concat(
[midValue],
quickSort2(right)
)
}
// 功能测试
const arr1 = [1, 6, 2, 7, 3, 8, 4, 9, 5]
console.info(quickSort2(arr1))
스플라이스 및 슬라이스 성능 비교
// 性能测试
const arr1 = []
for (let i = 0; i < 10 * 10000; i++) {
arr1.push(Math.floor(Math.random() * 1000))
}
console.time('quickSort1')
quickSort1(arr1)
console.timeEnd('quickSort1') // 74ms
const arr2 = []
for (let i = 0; i < 10 * 10000; i++) {
arr2.push(Math.floor(Math.random() * 1000))
}
console.time('quickSort2')
quickSort2(arr2)
console.timeEnd('quickSort2') // 82ms
시차는 거의 동일한 것으로 파악되어 그 이유를 다음과 같이 분석한다.
1. 알고리즘 자체의 복잡도는 이미 O(n*logn) 정도로 높다.
규모의 순서를 빠르게 줄일 것입니다.
다음으로 스플라이스와 슬라이스를 개별적으로 비교합니다.
// 单独比较 splice 和 slice
const arr1 = []
for (let i = 0; i < 10 * 10000; i++) {
arr1.push(Math.floor(Math.random() * 1000))
}
console.time('splice')
arr1.splice(5 * 10000, 1)
console.timeEnd('splice') // 0.08ms
const arr2 = []
for (let i = 0; i < 10 * 10000; i++) {
arr2.push(Math.floor(Math.random() * 1000))
}
console.time('slice')
arr2.slice(5 * 10000, 5 * 10000 + 1)
console.timeEnd('slice') // 0.007ms
슬라이스는 스플라이스보다 약 10배 빠르지만 여전히 빠릅니다.