Algorithm QuickSort快速排序

Reference

快速排序(过程图解)

快排其实比归并写起来要容易一些。
核心原理就是选取一个基准数,然后把比他小的放到左边,比他大的放到右边,然后再同样处理两边,递归,最终排好序。
实际操作时并没有这么做,我们忽略基准数,从两边开始检查,把左边较大的和右边较小的交换,最后两者相遇时再把基准数交换过来。这样相对位置关系可以保证。
核心代码:
swap函数不是必需的,图个省事,C++中可以方便地使用Reference来交换内存中的两个元素,C的话用指针也可以做到,不过看起来没这么自然。

inline void swap(int &a,int &b)
{
	int tmp=a;
	a=b;
	b=tmp;
}

void quickSort(int arr[],int L,int R)
{
	if(L>=R) return;//由于递归调用自己,出口要写在最开始
	int s=arr[L];//假定基准数是数列最左边的数
	int i=L;//左右的两个哨兵
	int j=R;
	while(i!=j)//注意最外层的while检查只会在内层循环都走完后才会检查
	//实际上内层的两个while跳出时可以统一写成i!=j,因递归出口保证了i一定比j小,j减小时一定会遇到i
	{
	//右边的哨兵必须先出发,这样才能保证最后如果两者相遇在中间,脚下的元素一定是比基准数小的
	//因为右哨兵只会在比基准数小的元素处停下
	//保证最后把基准数和相遇点的数交换时,大小关系正确
		while(arr[j]>=s&&i<j)//右边的哨兵开始,遇到大的元素就跳过,在小的元素处停下来。
		//i<j(或i!=j)是防止整个都比基准数大导致循环无法跳出以及访问越界的
			j--;
		while(arr[i]<=s&&i<j)//右边的哨兵找到了,左边的哨兵就出发,如果没找到,会使i=j=L。
			i++;
		if(i<j)//两者没有相遇时才交换
			swap(arr[i],arr[j]);
	}
	swap(arr[i],arr[L]);//交换相遇点的元素和基准数
	/*有两种情况:
	1.两者在中间相遇,由于是右边的哨兵先出发,相遇点一定比基准数小,正常交换。
	2.右边的哨兵跑完了整个数组都没找到比基准数小的,此时i=j=L,由于基准数也是左边界,交换自己,没问题。
		例子:6,7,8,9
	由于右边的哨兵的位置限制了左边的哨兵的行动,不存在左边的哨兵跑过界的情况。*/
	quickSort(arr,L,i-1);//再分别处理左右边
	quickSort(arr,i+1,R);
}

测试代码:

#include <iostream>
using namespace std;

void printArray(int a[],int L,int R)
{
	while(L<=R)
		cout<<a[L++]<<' ';
	cout<<endl;
}

inline void swap(int &a,int &b)
{
	int tmp=a;
	a=b;
	b=tmp;
}
void quickSort(int arr[],int L,int R)
{
	if(L>=R) return;
	int s=arr[L];
	int i=L;
	int j=R;
	int tmp;
	while(i!=j)
	{
		while(arr[j]>=s&&i<j)
			j--;
		while(arr[i]<=s&&i<j)
			i++;
		if(i<j)
			swap(arr[i],arr[j]);
	}
	swap(arr[i],arr[L]);
	quickSort(arr,L,i-1);
	quickSort(arr,i+1,R);
}

int main(int argc, char const *argv[])
{
	int arr[]={12,11,10,9,8,7,6,5,4,3,2,1,0};
	quickSort(arr,0,12);
	printArray(arr,0,12);
	return 0;
}

结果:0 1 2 3 4 5 6 7 8 9 10 11 12

猜你喜欢

转载自blog.csdn.net/weixin_43873801/article/details/87075796