排序算法之快速排序实现及算法思想

快速排序的思想是基于分治算法。

首先说明:快速排序是不稳定的!!

时间复杂度:O(nlogn)

给定区间[l,r]

算法思想

第一步:确定分界点 可取q[l]、q[r]、q[(l+r)/2]、随机。 假设确定好一个数x

第二步(最难):重新划分区间,通过x将区间分为两部分,使第一个区间所有都小于等于x,第二个区间所有都大于等于x。

第三步:递归处理左右两段,先给左边排序,再给右边排序。

第四步:拼接两段。

我们可以用两个指针一个在区间左端点左侧,一个在区间右端点右侧,分别往中间走,直到i指针指向的数需要放到右区间,j指针指向的数需要放到左区间。

这个时候我们可以调用swap函数,可以手写实现swap。如此往复,直到i和j相遇为止。

代码实现如下:(以j划分!!!)

void quick_sort(int q[], int l, int r)
{
	//如果我们的区间里没有数,或者只有一个数就不用排序了
	if (l >= r)
		return;
	int x = q[l], i = l - 1, j = r + 1;
	while (l < r)
	{
		do i++; while (q[i] < x);
		do i--; while (q[j] > x);
		if (i < j)
		//交换两个数 或c++里直接调用swap(q[i],q[j])
		{
			int temp = q[i];
			q[i] = q[j];
			q[j] = temp;
		}
	}
	quick_sort(q, l, j);
	quick_sort(q, j + 1, r);
}

进一步讨论:

快速排序属于分治算法!

分治算法都有三步:

1.分成子问题。

2.递归处理子问题。

3.子问题合并。

如何证明while循环结束后下面的式子成立?

q[l...j] <= x, q[j + 1...r] >= x

注:q[l..j] <= x意为q[l],q[l+1]...q[j-1],q[j]的所有元素都<= x

证明如下

循环不变式:q[l..i] <= x      q[j..r] >= x

1.初始化

   循环开始之前,两个指针i,j均被初始化,均指向了边界的两侧。

   其中i=l-1       j=r+1

2.保持

    执行循环体,所以i和j更新之后,下一次循环开始之前,循环不变式依然成立!

		do i++; while (q[i] < x);
        //会使得q[l...i-1]<=x,q[i]>=x
		do i--; while (q[j] > x);
        //会使得q[j+1...r]>=x,q[j]<=x;
		if (i < j)
		//交换两个数 或c++里直接调用swap(q[i],q[j])
		{
			int temp = q[i];
			q[i] = q[j];
			q[j] = temp;
		}
        //会使得q[l...i]<=x,q[j...r]>=x

注:由于使用的是do-while循环,i和j一定会自增一次,使循环继续下去。如果使用while循环,会出现死循环。

3.终止

循环结束时:i >= j

因为 i >= j ,q[l....j]<=x q[j...r]>=x

所以按j来划分 一定有q[l..j] <= x  q[j+1..r] >= x

最后一轮循环的if语句一定不会执行

下面附一份用i划分的代码实现

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 >> 1];//注意是向上取整,因为向下取整可能使得x取到q[l]
    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, i - 1), quick_sort(q, i, r);
}

完整代码:

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

int n;
int q[N];
void quick_sort(int q[], int l, int r)
{
	//如果我们的区间里没有数,或者只有一个数就不用排序了
	if (l >= r)
		return;
	int x = q[l], i = l - 1, j = r + 1;
	while (l < r)
	{
		do i++; while (q[i] < x);
		do i--; while (q[j] > x);
		if (i < j)
		//交换两个数 或c++里直接调用swap(q[i],q[j])
		{
			int temp = q[i];
			q[i] = q[j];
			q[j] = temp;
		}
	}
	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;
}

猜你喜欢

转载自blog.csdn.net/JixTlhh/article/details/115186398