快速排序简介及代码模板

快速排序是对冒泡排序的改进,基本思想是基于分治法来减少交换次数

基本步骤

1、先找一个基准元素,可以是第一个元素(但这样可能造成复杂度提升,在后面基准点的取法会讲到)

2、将小于基准元素的数都移动到它的左边,大于基准元素的数都移动到它的右边。此时,基准元素位于它最终的位置

3、对基准元素左右两个分块重复以上的步骤,直到全部有序。

时间复杂度

如果每次能够将数组划分为两个区间,总共需要进行 logn 趟排序,所以平均复杂度为 O(nlogn)。

极端情况下每次只能将数组划分为一个区间,这样的话就需要进行 n 趟排序,此时最坏的时间复杂度为 O(n^2)。

空间复杂度

因为快速排序是递归的形式,如果每次能够将数组划分为两个区间,会递归 logn 层,此时平均复杂度为 O(logn)。

最坏情况下会递归 n 层,所以最坏复杂度为 O(n)。

基准点的选取

方法1:选取第一个元素作为基准点。

当数组基本有序或基本逆序时,时间复杂度会退化为 O(n^2)

方法2:使用中间点作为基准点

可以每次选取 arr[l + r >> 1] 作为基准点

代码模板

#include <iostream>
#include <cstdlib>
#include <ctime>
using namespace std;

void quick_sort(int q[], int l, int r)
{
    if (l >= r) return;

    int i = l - 1, j = r + 1, x = q[l + 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(void)
{
	int idx = 0;
	int a[15];
	// 用时间作为种子生成随机数 
	srand(time(0));
	
	cout << "随机生成的数字:";
	for (int i = 0; i < 10; i++) {
		a[idx++] = rand();
		cout << a[idx - 1] << " ";
	}
	cout << endl;
	
	quick_sort(a, 0, 9);
	
	cout << "排序后的数字:";
	for (int i = 0; i < 10; i++) {
		cout << a[i] << " ";
	}
	cout << endl;
	
	return 0;
}

P1177 【模板】快速排序

题目链接:https://www.luogu.com.cn/problem/P1177

对于这道题,如果每次取第一个元素(即令 x = q[l]),会有两组数据TLE。因为如果数组是有序或者逆序的,那么复杂度会退化为 O(n^2)

基准点取中间元素 x = q[l + r >> 1] 是一种很好的方法,能过掉所有数据

#include <bits/stdc++.h>
using namespace std;
const int N = 1e5 + 5;

int a[N];

void quick_sort(int q[], int l, int r)
{
    if (l >= r) return;

    int i = l - 1, j = r + 1, x = q[l + 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(void)
{
	int n;
	scanf("%d", &n);
	for (int i = 0; i < n; i++) {
		scanf("%d", &a[i]);
	}
	quick_sort(a, 0, n - 1);
	for (int i = 0; i < n - 1; i++) {
		printf("%d ", a[i]);
	}
	printf("%d\n", a[n - 1]);
	
	return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值