快速排序
- 创建用于交换数组两个值的函数
swap
- 创建
quick
快速排序函数,入参i
为起始下标,j
为末尾下标 - 我们将起始下标
i
对应的arr[i]
值作为基准
,声明两个哨兵
,l
与r
分别代表左侧哨兵和右侧哨兵,初始位于起始下标和末尾下标。 r
向左侧移动,寻找到第一个小于(若降序则相反
)基准
的值;l
向右侧移动,寻找到第一个大于(若降序则相反
)基准
的值,找到后交换,并继续找下一对值交换,寻找条件要确保左侧哨兵和右侧哨兵没有相遇:l<r
。- 当哨兵相遇时,将
相遇点的值
与基准值
交换,得到的相遇点的值为基准中心
,左侧的值一定小于它,右侧的一定大于它。 - 将相遇点左侧与右侧继续递归,递归条件为
基准中心
左侧l-1
下标值大于起始下标i
,也就是相遇点左侧至少存在两个数
,右侧同理,递归完毕,值从小到大进行排序。
const swap=(arr,a,b)=>{
[arr[a],arr[b]]=[arr[b],arr[a]]
}
const quick=(arr,i,j)=>{
let l=i,r=j
while(l<r){
while(l<r&&arr[r]>=arr[i]) r--
while(l<r&&arr[l]<=arr[i]) l++
swap(arr,l,r)
}
swap(arr,i,l)
if(l-1>i){
quick(arr,i,l-1)
}
if(l+1<j){
quick(arr,l+1,j)
}
}
quick(arr,0,arr.length-1)
快速选择
- 例如寻找前k个最小的数,快速排序时左侧值会小于
基准中心
,因此每次找到基准中心
如果基准中心:
若等于k
则已经找到前k个最小值了,返回前k个即可;
若大于k
,则右侧数排除,继续排序左侧即可;
若小于k
,则左侧数已经在前k个最小值的范围内了,顺序无所谓,继续排序右侧。
const swap=(arr,a,b)=>{
[arr[a],arr[b]]=[arr[b],arr[a]]
}
const quick=(arr,i,j)=>{
let l=i,r=j
while(l<r){
while(l<r&&arr[r]>=arr[i]) r--
while(l<r&&arr[l]<=arr[i]) l++
swap(arr,l,r)
}
swap(arr,i,l)
if(l===k){
return arr.slice(0,k)
}else if(l>k){
return quick(arr,i,l-1)
}else {
return quick(arr,l+1,j)
}
}
const res= quick(arr,0,arr.length-1)
- 例如寻找第k个大的数,降序排序的话快速排序时左侧值会大于
基准中心
,因此每次找到基准中心
如果基准中心:
若等于k-1
则已经找到那个第k个(arr[k-1]
)大的数了,返回即可;
若大于k-1
,则第k大的数必定在左侧,右侧数全排除,继续排序左侧即可;
若小于k-1
,则左侧数(不超过k个)是都大于第k大的数,顺序无所谓直接排除,继续排序右侧。
const swap=(arr,a,b)=>{
[arr[a],arr[b]]=[arr[b],arr[a]]
}
const quick=(arr,i,j)=>{
let l=i,r=j
while(l<r){
while(l<r&&arr[r]>=arr[i]) r--
while(l<r&&arr[l]<=arr[i]) l++
swap(arr,l,r)
}
swap(arr,i,l)
if(l===k-1){
return arr[k-1]
}else if(l>k-1){
return quick(arr,i,l-1)
}else {
return quick(arr,l+1,j)
}
}
const res= quick(arr,0,arr.length-1)