快速排序思路+代码
快速排序基本原理
可以看出,快排这个算法很狂啊,直接叫自己快速排序。
它的基本思想很简单,被称为分治思想
分治:即分而治之,即把一个问题转化成多个与其相似的小问题,再去研究小问题的解法。实现上,常常使用递归来实现
快速排序的基本思路是:找出一个基准点(称作pivot),通过某种方式的移动,将pivot左面变成都是小于等于pivot的元素,将其右面变成都是大于等于pivot的元素。
这样,就产生了一个以pivot为中心的,更加趋于有序的序列:
再去对pivot的左半部分和右半部分进行相同的操作。
什么时候停止?
一个基本事实:只含有一个元素的序列是有序的序列。那么,如果进入本次递归的时候,序列只有一个元素,即标志元素pivot本身,就可以直接返回。
实现
实际在应用快速排序的时候,一般选取当前序列起始元素为pivot。
实现快速排序的时候有两种方式——交换法和挖坑法,两种方式大同小异。
挖坑法 操作如下:
首先:left=start;right=end;将arr[start]赋值给pivot,我们这里可以视为把arr[start]挖了出去,这个位置视为空的;
然后一个循环,条件为left<right;
循环内:
第一个循环,right从末尾开始往前寻找小于等于pivot的元素,如果找到,循环结束。如果满足left<right,把arr[right]赋值给arr[left](此时arr[left]是“空”的,相当于把arr[right]挖出,填到了arr[left])
此时,arr[right]视为空
第二个循环,left从头往后找大于等于pivot的元素,如果找到,循环结束。如果满足left<right,将arr[left]赋值给arr[right](相当于把arr[left]挖出去,填到了arr[right])
此时,arr[left]视为空
跳出循环后,一定有left==right成立,即二者重合,这个位置是“空”的,把pivot填进去。
递归左右序列
代码如下:
void Qsort(int arr[],int start,int end){
if(start>=end)return;
int left=start;
int right=end;
int pivot=arr[left];
while(left<right){
while (left<right&&arr[right]>=pivot)
right--;
if(left<right)arr[left]=arr[right];
while(left<right&&arr[left]<=pivot)
left++;
if(left<right)arr[right]=arr[left];
}
arr[left]=pivot;
Qsort(arr, start, left-1);
Qsort(arr, left+1, end);
}
交换法
前提条件:有一数组arr[],当前序列起始下标为start,终止下标为end。
步骤 | 具体操作 |
---|---|
第一步: | 选取start位置的元素为pivot;初始化left为start,right为end+1; |
第二步: | 当left<right,就进入循环 |
第二步①: | left++;当 left≤end 并且 arr[left]≤pivot的时候,left++;. |
第二步②: | right–;当arr[right]>pivot的时候,right–; |
第二步③: | 两个循环终止的时候,比较一下left和right,若满足left<right,交换arr[left]和arr[right]; |
第三步: | 交换arr[start]和arr[right]。(将pivot挪到中间) |
第四步: | 递归左右序列 |
Q:第二步中,为什么要先进行对left和right进行加减,而不是后面进行?
A:因为我们想要获得right最后停留的位置,那是pivot要换到的位置。
Q:为什么right不直接赋值end,而是要先+1后-1?
A:因为第二步的时候需要先对left和right进行加减。
代码如下:
void swap(int& a,int& b){
int c=a;
a=b;
b=c;
}
void Qsort(int arr[],int start,int end){
if(start>=end)return;//递归出口
int left=start;
int right=end+1;
int pivot=arr[left];//选取基准
while (left<right)//当left在right前面就进入循环
{
/*left和right不直接赋值start+1和end的原因:对left和right的加减操作需要放在循环之前*/
/*加减操作在前面的原因:要获取right最终停留的位置*/
left++;
while (left<=end && arr[left]<=pivot)
left++;
right--;
while(arr[right]>pivot)
right--;
if(left<right)//如果没有越界,就交换
swap(arr[left],arr[right]);
}
swap(arr[start],arr[right]);//把pivot换到中间去
Qsort(arr, start,right-1);//递归左右序列
Qsort(arr, right+1, end);
}
随便敲点数据进去: