经典算法(六)----快速排序----图解法让你快速入门

引言

     只要设计到数据,就会涉及到数据的排序问题,比如给你随机给你五个整数  3,1,5,2,4 。让你从小到大进行排序,那我们该怎样才是实现对这些整数的排序呢 ?

    答案是多种多样的,比如用插入排序、希尔排序、堆排序、归并排序、快速排序等等,这些排序方法都可以实现对整数排序,而这篇文章要讲的就是快速排序

本文将从以下几个问题对快速排序进行分析和讲解:

  1. 什么是快速排序?
  2. 快速排序的大概过程是什么?
  3. 怎样用代码实现快速排序?
  4. 快速排序的代码详解。

什么是快速排序?

下面看百度百科对快速排序的定义:

快速排序由C. A. R. Hoare在1960年提出。它的基本思想是:通过一趟排序将要排序的数据分割成独立的两部分,其中一部分的所有数据都比另外一部分的所有数据都要小,然后再按此方法对这两部分数据分别进行快速排序,整个排序过程可以递归进行,以此达到整个数据变成有序序列。 

简单理解:还记得归并排序的思想吗,归并排序就是先分再合。而快速排序(下面简称快排)有一个分的过程(不是归并排序里的一个数组分成两部分),快排的分一共分两大步。

  1. 首先找一个基准数(可以选数组的任意一个位置,这篇文章选的是数组的第一个数)。第一步就是把基准数变换位置,这个位置是前面的数都比基准数小,后面的数都比基准数大(这里排序是从小到大排序)。
  2. 开始分,以基准数为界限,分成两部分(两部分都不包含基准数)。再对上面的两部分都执行上面的1过程即可。

截止到现在为止,只需要知道快排的两大步是什么就可以了,下面看一个动图:

快速排序的大概过程是什么?

我们用快速排序讲一个例子来说明,要排序的数组为3,1,5,2,4.

第一步:找基准数,并把基准数移动到合适的位置。

一般来说,基准数最终的位置(在这个位置前面的数都比基准数小,后面的数都比基准数大)都在基准数起始位置的后面(我选的基准数的数组的第一个元素),那应该让基准数移动大哪个位置呢?

我们要设置两个哨兵 i 和 j ,第一个哨兵 i 的位置是数组第一个元素的位置,哨兵 j 的位置数数组的最后一个元素的位置

首先哨兵 j 往前移动,在不和哨兵 i 碰头的情况下,如果发现了一个比基准数小的数,那就暂停移动,这时候轮到了哨兵 i 往后移动,在不和哨兵 j  碰头的情况下,如果发现了一个比基准数小的数,那就停止移动,然后哨兵 i 和 哨兵 j 交换他俩的元素,下面看图理解。

首先发现哨兵 j 比 基准数大,所以前移,移动到一个比基准数小的位置,哨兵 i 后移,移动到一个比基准数大的位置

这时候交换哨兵 i 和 j 的值。

下面继续哨兵j前移,哨兵i后移操作,但是哨兵 j 前移发现和 i 碰头了,那就结束哨兵的移动,把哨兵 i 和基准数的值互换

经过上面的操作,就完成了基准数的移动,达到了基准数前面的数都比基准数小,基准数后面的数都比基准数大的目的

下面看用代码怎么实现上面图片的一系列操作

void QuickSort(int arr[],int first,int last)
{
	if(first>last)//控制递归结束 
		return ;
	int i=first,j=last;
	int temp=arr[first];//基准数
	while(i!=j)//i和j不碰头 
	{
		//顺序很重要,要先从右往左找 
		while(arr[j]>=temp&&i<j) 
			j--;
		//上面循环结束的条件有两种,
		//一是查到了比基准数小的,
		//二是 i与j碰头了
		while(arr[i]<=temp && i<j)
			i++; 
		//循环结束条件同上
		
		//下面交换两个数在数组中的位置
		if(i<j) //两个循环结束的条件都不是i和j碰头
		{
			int t=arr[i];
			arr[i]=arr[j];
			arr[j]=t;
		} 
	} 
	//最终一定会碰头,交换基准数和碰头那个位置的数 
	arr[first]=arr[i];
	arr[i]=temp; 
		 
	//QuickSort(arr,first,i-1);分的前一部分 
	//QuickSort(arr,i+1,last); 分的后一部分 
}

我相信只要上面的图片过程看懂了,那么看懂这段代码基本没啥问题了。

第二步就是分了,也就是上面函数的后两行,分成两部分,递归调用

怎样用代码实现快速排序?

下面看完整的代码

#include<iostream>
using namespace std;
//快速排序函数    不稳定 
void QuickSort(int arr[],int first,int last)
{
	if(first>last)//控制递归结束 
		return ;
	int i=first,j=last;
	int temp=arr[first];//基准数
	while(i!=j)//i和j不碰头 
	{
		//顺序很重要,要先从右往左找 
		while(arr[j]>=temp&&i<j) 
			j--;
		//上面循环结束的条件有两种,
		//一是查到了比基准数小的,
		//二是 i与j碰头了
		while(arr[i]<=temp && i<j)
			i++; 
		//循环结束条件同上
		
		//下面交换两个数在数组中的位置
		if(i<j) //两个循环结束的条件都不是i和j碰头
		{
			int t=arr[i];
			arr[i]=arr[j];
			arr[j]=t;
		} 
	} 
	//最终一定会碰头,交换基准数和碰头那个位置的数 
	arr[first]=arr[i];
	arr[i]=temp; 
		 
	QuickSort(arr,first,i-1);//分的前一部分 
	QuickSort(arr,i+1,last); //分的后一部分 
}
//输出数组的值
void printf(int arr[],int len)
{
	for(int i=0;i<len;i++)
		cout<<arr[i]<<" ";
	cout<<endl;
}
int main()
{
	//要排序的数组 
	int arr[]={3, 44,38, 5,47,15,36,26,27,2 ,46,4 ,19,50,48};
	int len=15;//要排序的数组长度 
	
	//排序 
	QuickSort(arr,0,len-1);
	
	//输出 
	printf(arr,len);
	return 0;
}

运行结果:

快速排序代码详解

  1. 实现基准数的移动,注意两个哨兵移动时,移动要哨兵 j 先移动,然后再哨兵 i 移动
  2. 实现分的过程,注意以什么为分割线进行分

本文参考以及引用:

啊哈算法!

百度百科

创作不易,如果本文对你起到了一些帮助,何不点个赞再走呢!!!

猜你喜欢

转载自blog.csdn.net/weixin_44820625/article/details/106786122