./remake 算法 - 手写快排

文章详细阐述了快速排序的原理,这是一种基于分治思想的排序算法。它通过选取分界点,将数组分为小于和大于分界点的两部分,然后对这两部分递归地进行排序。文章讨论了分界点选择为(l+r)/2和(l+r+1)/2时的不同递归处理方式,并强调了避免无限递归的关键在于正确处理递归区间。
摘要由CSDN通过智能技术生成

快速排序本质上是一种分治算法。

  • 不稳定排序:相同元素的相对次序在排序后会发生变化(swap这个动作)

其基本流程如下:

  • 确定分界点:一般是中间点(l + r) / 2、(l + r + 1) / 2,或随机值。
  • 调整区间:小于分界点x的在左边,大于分界点y的在右边。
  • 递归处理左右两段。

整体程序如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
#include <iostream>

using namespace std;

void quick_sort(int *nums, int l, int r) {
if (l >= r) {
return;
}

int i = l - 1, j = r + 1;
int x = nums[(l + r) / 2];
while (i < j) {
do i++; while(nums[i] < x);
do j--; while(nums[j] > x);
if (i < j) swap(nums[i], nums[j]);
}
quick_sort(nums, l, j);
quick_sort(nums, j + 1, r);
}

int main() {
int N;
cin >> N;

int nums[N];
for (int i = 0; i < N; i++) {
cin >> nums[i];
}

quick_sort(nums, 0, N - 1);

for (int i = 0; i < N; i++) {
cout << nums[i] << " ";
}
cout << endl;
}

  • 分界点和递归左右两段的选择
  1. 分界点取中间(l + r) / 2时,递归处理左右两段应该是[l, j]和[j+1, r]

  2. 分界点取中间(l + r + 1) / 2时,递归处理左右两段应该是[l, i-1]和[i, r]

比如一下样例:

1
2
2
1 2

对于第一种情况:

分界点:(l + r) / 2 = (0 + 1) / 2 = 0

第一次调用完 quick_sort 后(调整区间[0, 1]),i = 0,j = 0

若是递归的区间为[l, i-1]和[i, r],则是[0, -1]和[0, 1];此时将永远按[0, 1]递归下去。

若是递归的区间为[l, j]和[j+1, r],则是[0, 0]和[1, 1];此时将碰到递归的终止条件。

对于第二种情况:

分界点:(l + r + 1) / 2 = (0 + 1 + 1) / 2 = 1

第一次调用完 quick_sort 后(调整区间[0, 1]),i = 1,j = 1

若是递归的区间为[l, i-1]和[i, r],则是[0, 0]和[1, 1];此时将碰到递归的终止条件。

若是递归的区间为[l, j]和[j+1, r],则是[0, 1]和[2, 1];此时将永远按[0, 1]递归下去。

综上,快排最难的还是避免无限递归,需要牢牢记住:

  1. 分界点取中间(l + r) / 2时,递归处理左右两段应该是[l, j]和[j+1, r]

  2. 分界点取中间(l + r + 1) / 2时,递归处理左右两段应该是[l, i-1]和[i, r]

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值