算法随笔 — 排序算法 — 快速排序

快速排序实现原理

在不同的实现方法中,按照交换值的方法可以分为 赋值两数值交换,这个现在理解不了没关系,先带着这个观点继续往后看

普通快排

以升序为例,实现步骤如下图所示
算法随笔 — 排序算法 — 快速排序_第1张图片
算法随笔 — 排序算法 — 快速排序_第2张图片

function quick_sort_v1(arr: number[], l: number, r: number) {
   
  if (l >= r) return
  let x = l, y = r, base = arr[l] // 选择操作区间第一位作为基准值
  while(x < y) {
   
    while(x < y && arr[y] > base) y--
    if (x < y) arr[x++] = arr[y]
	while(x < y && arr[x] <= base) x++
	if (x < y) arr[y--] = arr[x]
  }
  arr[x] = base
  // 此时数组已被基准值分为大小两部分,接着对其进行递归操作
  quick_sort_v1(arr, l, x - 1)
  quick_sort_v1(arr, x + 1, r)
}

单边递归快排

从上面的实现方法可以看到,每次操作需要进行两次递归操作,通过单边递归我们可以将递归操作减少至1次,从而减少空间的使用

算法随笔 — 排序算法 — 快速排序_第3张图片

function quick_sort_v2(arr: number[], l: number, r: number) {
   
  let x: number, y: number, base: number
  while(l < r) {
   
	x = l
	y = r
	base = arr[l]
	while(x < y) {
   
	  while(x < y && arr[y] > base) y--
	  if (x < y) arr[x++] = arr[y]
	  while(x < y && arr[x] <= base) x++
	  if (x < y) arr[y--] = arr[x]
	}
	arr[x] = base
	quick_sort_v2(arr, x + 1, r)
	r = x - 1
  }
}

从以上代码可以看出,原来需要的两次递归操作现在只要一次就可以了

总结一下,以上两种方法,在交换值时是直接赋值的,这意味着在程序运行时,数组是缺了一个元素的,这就意味着阈值(或者说基准值)不能随便选,只能取操作区间的头部或者尾部

以上两段代码的基准值选择都是选择了操作空间的第一个

如果随机选阈值,最后极可能会出现“吞数字”的情况,如下图所示
算法随笔 — 排序算法 — 快速排序_第4张图片

分区快排

分区快排结合了快排和插入排序的优点

从上面介绍的两种快排方法来看,最终运行的效率取决于中间值选得好不好(看脸)
快 排 时 间 复 杂 度 = { O ( n l o g n ) 一般 O ( l o g n ) 理想 O ( n 2 ) 最差 快排时间复杂度=\begin{cases}O(nlogn) & \text{一般} \\ O(logn) & \text{理想}\\ O(n^2) & \text{最差} \end{cases} =O(nlogn)O(logn)O(n2)一般理想最差
而插入排序的时间复杂度如下
插 入 排 序 时 间 复 杂 度 = { O ( n 2 ) 一般 O ( n ) 相对有序 插入排序时间复杂度=\begin{cases} O(n^2) & \text{一般} \\ O(n) & \text{相对有序} \end{cases} ={ O(n2)O(n)一般相对有序

你可能感兴趣的:(算法,算法,前端,快速排序,typescript,javascript)