排序
- 排序:把某个乱序的数组变成升序或降序的数组 (这里用数组来做举例)
快速排序
- 该排序属于 分治 策略
- 将一个问题分解为两个问题来计算,计算完成之后,就会得到子任务的解,这些解不是最终问题的解,还需要merge起来
Typescript 版算法实现
1 ) 简单版本,消耗内存
function quickSort(arr: number[]) {
// 1.核心函数
const qsFn = (arr: number[]) => {
if (arr.length <= 1) return arr;
const pivotIndex: number = Math.floor(arr.length / 2);
const pivot: number = arr.splice(pivotIndex, 1)[0];
const left: number[] = [];
const right: number[] = [];
arr.forEach(item => {
if (item < pivot) left.push(item);
if (item > pivot) right.push(item);
});
return qsFn(left).concat([pivot], qsFn(right));
}
// 2.执行核心函数
const res: number[] = qsFn(arr); // res 用于返回最终结果
arr.splice(0, arr.length, ...res); // 将最终排好序的结果赋值给原数组arr
// 3. 可以有返回值
return arr; // 可以用于返回值
};
const arr = [15, 4, 23, 52, 1];
quickSort(arr);
console.log(arr); // [1, 4, 15, 23, 52]
- 这里是 多开了一些存储空间,而且有递归, 一般生产环境不会使用这类内存占用较大的算法
- 思路
- 分区:从数组中,任意选择一个基准,所有比基准小的元素放在基准前面,比基准大的元素放在基准后面
- 此时,基准已经找到自己合适的位置了
- 递归:递归地对基准前后的子数组进行分区
- 在子数组中找到一个基准,并把它放到合适的位置
- 一直递归下去,基准前后子数组最后的长度都是1,不用再递归了,此时子数组已经排序好了
- 等所有子数组都排序好,我们整个快排结束
- 分区:从数组中,任意选择一个基准,所有比基准小的元素放在基准前面,比基准大的元素放在基准后面
- 时间复杂度: O(nlogn)
- 递归时间: logn, 每次劈成2半
- 分区时间:n,for循环,找出比基准小和大的元素
2 )基于指针版本, 优化内存
function partition(arr: number[], left: number, right: number): number {
// 选择最左边的元素作为基准值
const pivot = arr[left];
let i = left + 1; // 左指针
let j = right; // 右指针
// 当左指针小于等于右指针时循环
while (i <= j) {
// 右边指针向左移动直到找到小于基准值的元素
while (i <= j && arr[j] >= pivot) {
j--;
}
// 左边指针向右移动直到找到大于基准值的元素
while (i <= j && arr[i] <= pivot) {
i++;
}
// 交换左右指针所指向的元素,以确保左侧都小于基准值,右侧都大于基准值
if (i < j) {
[arr[i], arr[j]] = [arr[j], arr[i]];
}
}
// 将基准值放到正确的位置(i 或 j 的位置上)
[arr[left], arr[j]] = [arr[j], arr[left]];
// 返回基准值的索引位置
return j;
}
function quickSortFn(arr: number[], left: number, right: number): void {
if (left < right) {
// 获取分区后的基准值索引
const pivotIndex = partition(arr, left, right);
// 对基准值左侧子数组进行递归排序
quickSortFn(arr, left, pivotIndex - 1);
// 对基准值右侧子数组进行递归排序
quickSortFn(arr, pivotIndex + 1, right);
}
}
// 可以用于返回值,可以不用返回值
function quickSort(array: number[]): number[] {
quickSortFn(array, 0, array.length - 1);
return array;
}
console.log('----- 就地排序 ------');
const arr = [-2, 1, 0, -9, 1, 3, 9, 99, 9, -30, -100, 100, 88, 88, 20, 1, 0, 3, 4, 5, -20];
quickSort(arr);
console.log(arr)
3 )使用 三数取中法选择基准点 继续优化
function swap(array: number[], i: number, j: number) {
[array[i], array[j]] = [array[j], array[i]];
}
function partition(array: number[], low: number, high: number): number {
// 三数取中法选择基准点
const mid = Math.floor((low + high) / 2);
if (array[low] > array[high]) swap(array, low, high);
if (array[mid] > array[high]) swap(array, mid, high);
if (array[mid] > array[low]) swap(array, mid, low);
// 将基准点放到最左边
const pivot = array[low];
let i = low + 1;
for (let j = i; j <= high; j++) {
// 如果当前元素小于或等于基准点
if (array[j] <= pivot) {
// 交换元素
swap(array, i, j);
// 移动 i
i++;
}
}
// 将基准点放到正确的位置
swap(array, low, i - 1);
return i - 1;
}
function quickSort(array: number[], low: number, high: number) {
if (low < high) {
// 获取分区点
const pi = partition(array, low, high);
// 对基准点左右两边的子数组分别进行排序
quickSort(array, low, pi - 1);
quickSort(array, pi + 1, high);
}
}
function quickSortWrapper(array: number[]) {
quickSort(array, 0, array.length - 1);
}
// 示例使用
const unsortedArray: number[] = [9, -20, 99, 3, 6, 8, 10, 1, 2, 1];
quickSortWrapper(unsortedArray);
console.log("Sorted array is:", unsortedArray);
- 这个优化比较好,可用于生产环境
- 思路
- 基于高低指针,不断比较指针,满足条件进行交换
- 也是基于递归实现,但不占用过多内存
总结
- 比冒泡,选择,插入性能都要好, 分而治之
- Chrome 曾经用快排作为sort排序的方法
Python3 版算法实现
1 ) 方案1
def quick_sort_v1(arr: list) -> list:
def qs_fn(arr: list) -> list:
if len(arr) <= 1:
return arr
pivot_index = len(arr) // 2
pivot = arr.pop(pivot_index)
left, right = [], []
for item in arr:
if item < pivot:
left.append(item)
elif item > pivot:
right.append(item)
return qs_fn(left) + [pivot] + qs_fn(right)
res = qs_fn(arr)
arr[:] = res # 将最终排好序的结果赋值给原数组 arr
return arr
# 示例用法
if __name__ == "__main__":
arr = [15, 4, 23, 52, 1]
quick_sort_v1(arr)
print(arr) # 输出: [1, 4, 15, 23, 52]
2 ) 方案2
def partition(arr: list, left: int, right: int) -> int:
pivot = arr[left]
i = left + 1
j = right
while i <= j:
while i <= j and arr[j] >= pivot:
j -= 1
while i <= j and arr[i] <= pivot:
i += 1
if i < j:
arr[i], arr[j] = arr[j], arr[i]
arr[left], arr[j] = arr[j], arr[left]
return j
def quick_sort_fn(arr: list, left: int, right: int) -> None:
if left < right:
pivot_index = partition(arr, left, right)
quick_sort_fn(arr, left, pivot_index - 1)
quick_sort_fn(arr, pivot_index + 1, right)
def quick_sort_v2(arr: list) -> list:
quick_sort_fn(arr, 0, len(arr) - 1)
return arr
# 示例用法
if __name__ == "__main__":
arr = [-2, 1, 0, -9, 1, 3, 9, 99, 9, -30, -100, 100, 88, 88, 20, 1, 0, 3, 4, 5, -20]
quick_sort_v2(arr)
print(arr)
3 ) 方案3
def swap(array: list, i: int, j: int) -> None:
array[i], array[j] = array[j], array[i]
def partition(array: list, low: int, high: int) -> int:
mid = (low + high) // 2
if array[low] > array[high]:
swap(array, low, high)
if array[mid] > array[high]:
swap(array, mid, high)
if array[mid] > array[low]:
swap(array, mid, low)
pivot = array[low]
i = low + 1
for j in range(i, high + 1):
if array[j] <= pivot:
swap(array, i, j)
i += 1
swap(array, low, i - 1)
return i - 1
def quick_sort(array: list, low: int, high: int) -> None:
if low < high:
pi = partition(array, low, high)
quick_sort(array, low, pi - 1)
quick_sort(array, pi + 1, high)
def quick_sort_wrapper(array: list) -> list:
quick_sort(array, 0, len(array) - 1)
return array
# 示例用法
if __name__ == "__main__":
unsorted_array = [9, -20, 99, 3, 6, 8, 10, 1, 2, 1]
sorted_array = quick_sort_wrapper(unsorted_array)
print("Sorted array is:", sorted_array)
Golang 版算法实现
1 ) 方案1
package main
import (
"fmt"
)
func quickSortV1(arr []int) []int {
var qsFn func([]int) []int
qsFn = func(arr []int) []int {
if len(arr) <= 1 {
return arr
}
pivotIndex := len(arr) / 2
pivot := arr[pivotIndex]
arr = append(arr[:pivotIndex], arr[pivotIndex+1:]...)
left, right := make([]int, 0), make([]int, 0)
for _, item := range arr {
if item < pivot {
left = append(left, item)
} else if item > pivot {
right = append(right, item)
}
}
return append(append(qsFn(left), pivot), qsFn(right)...)
}
res := qsFn(arr)
copy(arr, res)
return arr
}
func main() {
arr := []int{15, 4, 23, 52, 1}
quickSortV1(arr)
fmt.Println(arr) // 输出: [1, 4, 15, 23, 52]
}
2 ) 方案2
package main
import (
"fmt"
)
func partition(arr []int, left, right int) int {
pivot := arr[left]
i := left + 1
j := right
for i <= j {
for i <= j && arr[j] >= pivot {
j--
}
for i <= j && arr[i] <= pivot {
i++
}
if i < j {
arr[i], arr[j] = arr[j], arr[i]
}
}
arr[left], arr[j] = arr[j], arr[left]
return j
}
func quickSortFn(arr []int, left, right int) {
if left < right {
pivotIndex := partition(arr, left, right)
quickSortFn(arr, left, pivotIndex-1)
quickSortFn(arr, pivotIndex+1, right)
}
}
func quickSortV2(arr []int) []int {
quickSortFn(arr, 0, len(arr)-1)
return arr
}
func main() {
arr := []int{-2, 1, 0, -9, 1, 3, 9, 99, 9, -30, -100, 100, 88, 88, 20, 1, 0, 3, 4, 5, -20}
quickSortV2(arr)
fmt.Println(arr)
}
3 ) 方案3
package main
import (
"fmt"
)
func swap(arr []int, i, j int) {
arr[i], arr[j] = arr[j], arr[i]
}
func partition(arr []int, low, high int) int {
mid := (low + high) / 2
if arr[low] > arr[high] {
swap(arr, low, high)
}
if arr[mid] > arr[high] {
swap(arr, mid, high)
}
if arr[mid] > arr[low] {
swap(arr, mid, low)
}
pivot := arr[low]
i := low + 1
for j := i; j <= high; j++ {
if arr[j] <= pivot {
swap(arr, i, j)
i++
}
}
swap(arr, low, i-1)
return i - 1
}
func quickSort(arr []int, low, high int) {
if low < high {
pi := partition(arr, low, high)
quickSort(arr, low, pi-1)
quickSort(arr, pi+1, high)
}
}
func quickSortWrapper(arr []int) []int {
quickSort(arr, 0, len(arr)-1)
return arr
}
func main() {
unsortedArray := []int{9, -20, 99, 3, 6, 8, 10, 1, 2, 1}
sortedArray := quickSortWrapper(unsortedArray)
fmt.Println("Sorted array is:", sortedArray)
}
411



被折叠的 条评论
为什么被折叠?



