算法学习笔记之快速排序(有图有讲解 小白也能看懂! 看不懂你砍我)

快速排序是一种基于分治思想的排序算法,在代码之前我们先来画图理解这种算法
假设有一组无序数列:(灵魂画图 轻喷。。。)

算法总的思想是:在这组无序序列中,我们要选择一个合适的数字K(代码中选择的是第一个数) 来将这组数分成两部分 假设我们选择第一个数5 然后通过操作 把这组数分成 左边全为小于5的数 右边全为大于5的数 (如果有等于5的数也不影响 )
就如图所示
算法学习笔记之快速排序(有图有讲解 小白也能看懂! 看不懂你砍我)_第1张图片分成了这两部分之后 这里就是分治的思想了 然后我们再分别对左边小于5和 右边大于5的数列 再进行一次相同的”操作“ 即把左边和右边也分别用一个K(代码中默认为第一个数)来分成两部分 (通过递归实现)

右边部分如图所示:

算法学习笔记之快速排序(有图有讲解 小白也能看懂! 看不懂你砍我)_第2张图片
左边同理 然后就这样无限分下去(递归) 就可以把这组数从无序变成相对有序,再到完全有序的序列
这就是快速排序的基本思路 可能看到这里 还是想说你在说XX呢 没关系 我们先大致理解这种思路 下面通过一个具体的例子来说明
算法学习笔记之快速排序(有图有讲解 小白也能看懂! 看不懂你砍我)_第3张图片

在这组序列中 我们选择5作为K
然后通过两个指针来方便我们表示具体的数
接下来就是我们前面讲到的“操作” 来划分这个数列 代码中会先从右边指针位置开始与5比较 如果a[j]大于5 (图中10>5)那么右边指针就继续往前移动一位 继续与5比较如图:
算法学习笔记之快速排序(有图有讲解 小白也能看懂! 看不懂你砍我)_第4张图片然后此时 4是小于5的 那么我们就交换 5和4的位置(因为要保证5右边的数总是大于5的(升序的情况 )) 那么就变成了如下图所示:
算法学习笔记之快速排序(有图有讲解 小白也能看懂! 看不懂你砍我)_第5张图片
此时5和4的位置已经交换了 并且目前5右边的数字 都是大于5的 那么这个时候我们就会操作左边的指针i来与5进行比较 此时a[i]就是刚刚换过去的4 4是小于5的 那么继续让指针i往右移动 此时a[i]变成了6 6>5 需要放到5的右边 那就变成了如图所示:
算法学习笔记之快速排序(有图有讲解 小白也能看懂! 看不懂你砍我)_第6张图片然后现在的情况是5的左边的数都是小于5的 那么我们又需要操作右边的指针来与5进行比较 我们就继续把右边的指针继续左移 变成a[j]=7 >5 继续左移 即a[j]=8 >5
然后再继续移动 a[j]=1 <5 那就又要交换5和1的位置 又变成如图:
算法学习笔记之快速排序(有图有讲解 小白也能看懂! 看不懂你砍我)_第7张图片
此时5右边的数全部都是大于5的 所以我们又要操作左边的指针来与5比较 此时1是小于5的 继续把左边的指针向右移动 即a[i]=2 小于5 继续移动 即a[i]=9 大于5 交换5和9的位置得到如图:
算法学习笔记之快速排序(有图有讲解 小白也能看懂! 看不懂你砍我)_第8张图片
然后此时5左边的数字都是小于5的 那么我们又操作右边的指针 j 左移 得到a[j]=11 是大于5的 然后继续左移 得到a[j]=3 是小于5的 那么我们又要交换5和 3的位置得到如图:
算法学习笔记之快速排序(有图有讲解 小白也能看懂! 看不懂你砍我)_第9张图片
然后此时5右边的数字都是大于5 我们继续操作左边的指针 让指针i 向右移动得到如图:
算法学习笔记之快速排序(有图有讲解 小白也能看懂! 看不懂你砍我)_第10张图片
这个时候 指针i和j都指向了同一个数字5(k) 说明这一次的操作已经结束了(代码中会跳出这次循环) 这个数列已经被5划分为了两个部分 即左边小于5的部分 和右边大于5的部分 然后接着我们又会用这种同样的操作 对左边和右边进行 这样的操作 即选用4和11来分别划分…然后又会选择4和11划分后的每个部分的第一个数来再次划分 然后就这样一直循环下去 把原本的这个序列 划分为了很多个不可再分并且有序的部分 就实现了对原本数列的排序 。。。后面的过程就不演示了 太多了画不完
看到这里相信你已经理解了快速排序这种思想了吧 没看懂的别砍我 已经写的很细了 再看几遍跟着模拟几遍 就能理解了 接下来附上很多注释的代码 帮助理解:

#include
using namespace std;
void swap(int &x,int &y){  //实现两数互换
	int temp=x;
	x=y;
	y=temp;	
}
void quicksort(int a[],int s,int e ){//快速排序 a[]是目标数组 s表示排序的起始位置下标(从0开始) e表示排序的末位位置
if(s>e)   //这里是对传入的s和e进行判断 
return;//如果起始位置大于了末尾位置 那就无法排序 所以return 结束
int k=a[s];  //指定起始位置的那个数字为k  即每个部分的第一个数
int i=s,j=e; //用i指针指向起始位置s  用j指针指向末尾位置e
while(i!=j){  //这里是对i和j指针位置的判断 如果i和j相等了 说明当前排序已经完成 
while(i<j&&k<=a[j])  //操作右边指针与k进行比较 条件是右边的数字比k大才会继续移动指针比较
     j--;//把右边指针左移
     swap(a[i],a[j]);//此处已经跳出循环了因为出现了右边小于k的情况 那么调用交换函数 让两个数字互换
     while(i<j&&k>=a[i])//接着操作左边指针与k进行比较 条件是左边数字小于k才会继续移动
     i++;//把左边指针右移
     swap(a[i],a[j]);//此处已经跳出循环了因为出现了左边大于k的情况 那么调用交换函数 让两个数字互换
	 quicksort(a,s,i-1);//到了这一步就完成了我们前面所画图的情况 序列已经被K即5划分为了左边和右边两个部分  那么接着递归调用快速排序  
	 //这里传的参数是 s和k-1 s是最左边的起始位置 i-1是5左边的那个数字作为这次排序的终点  此处对左边部分又进行了一次排序
	 quicksort(a,i+1,e);//这里又递归调用快速排序函数 对右边进行排列 起始位置是i+1即k右边的第一个数字 终点即e所在的末尾位置
}
}
int main(){
	int a[11]={5,6,2,9,3,11,1,8,7,4,10};//例子中的数列
	quicksort(a,0,10);//调用快速排序函数进行排序
	for(int i=0;i<11;i++){//输出排序后的结果
		cout<<a[i]<<" ";
	}	
} 

排序后的结果如图:
算法学习笔记之快速排序(有图有讲解 小白也能看懂! 看不懂你砍我)_第11张图片
总结:用了分治的思想把数列划分为多个部位 这些部分都是经历了逐渐从无序变为了比较有序再变成完全有序的一个过程 这个过程即实现了对数列的排序。
希望对你有帮助 高手勿喷 菜鸡一个 如果有错请指正。

你可能感兴趣的:(算法,快速排序,数据结构)