快速排序模板

187 阅读3分钟

一起养成写作习惯!这是我参与「掘金日新计划 · 4 月更文挑战」的第1天,点击查看活动详情

题目

www.acwing.com/problem/con…

给定你一个长度为 n 的整数数列。

请你使用快速排序对这个数列按照从小到大进行排序。

并将排好序的数列按顺序输出。

输入格式

输入共两行,第一行包含整数 n。

第二行包含 n个整数(所有整数均在 1∼10^9 范围内),表示整个数列。

输出格式

输出共一行,包含 n 个整数,表示排好序的数列。

数据范围

1≤n≤100000

输入样例:

5
3 1 2 4 5

输出样例:

1 2 3 4 5

时间复杂度

O(nlogn)

主要思想

基于分治

主要步骤

1. 随便取一个值作为分界点,一般有下面4种分界点 1. 取左边的值作为边界q[l] 1. 取中间的值作为边界q[(l + r) / 2] 1. 取右边的值作为边界q[r] 1. 随便一个值作为边界 2. 调整区间(难点):以自己选取的x作为分界点,划分成两个区间,使得第一个区间的数都小于等于x,第二个区间的数都大于等于x 2. 递归处理左右两段

第二步的做法有以下两种思路

1. 暴力做法

- 额外用到两个数组

2.优美一点的做法(也就是快排模板)

a. 用两个指针,i指向左边,j指向右边 b. 先移动i指针,直到i移动到大于等于x的值的时候就要停下来,接着移动j指针,当j指针移动小于等于x的数的时候就停下来,然后i跟j所指向的值swap一下,无论什么时候i左边的值都是小于等于x的,j右边的值都是大于等于x的 c. 交换完之后,两个指针要往中间移动一位

模板

#include <iostream>
using namespace std;
const int N = 100010;
int n;
int q[N];
void quick_sort(int q[], int l, int r)
{
  if (l >= r) return; // 如果左边大于右边的话我们就不用排序了
  
  int x = q[l + r >> 1], i = l - 1, j = r + 1; // 取左边的值为分界值
  while (i < j)
  {
    do i++; while (q[i] < x);
    do j--; while (q[j] > x);
    if (i < j) swap(q[i], q[j]);
  }
  
  quick_sort(q, l, j);        // 递归处理左边
  quick_sort(q, j + 1, r);    // 递归处理右边
}
int main()
{
  scanf("%d", &n);
  for (int i = 0; i < n; i++) scanf("%d", &q[i]);
  
  quick_sort(q, 0, n - 1);
  
  for (int i = 0; i < n; i++) printf("%d ", q[i]);
  
  return 0;
}

边界问题

1. 当x = q[l]的时候,不能取到quick_sort(q, l, i - 1); quick_sort(q, i, r); ,因为会出现死循环,例子:1,2 1. 当x = q[r]的时候,不能取quick_sort(q, l, j);quick_sort(q, j + 1, r); ,因为会出现死循环,例子:1,2

这篇博客很牛逼,有空的话可以看一下: AcWing 785. 快速排序算法的证明与边界分析 - AcWing

快排什么时候会用到

1. 面试的时候会用到,手写快排 1. 其他时候基本不会用到