目录
1.快速排序基础思想
快速排序是Hoare于1962年提出的一种二叉树结构的交换排序方法,其基本思想为:任取待排序元素序列中的某元素作为基准值,按照该排序码将待排序集合分割成两子序列,左子序列中所有元素均小于基准值,右子序列中所有元素均大于基准值,然后最左右子序列重复该过程,直到所有元素都排列在相应位置上为止。总而言之就是两点:
1.将位于数组最左侧的值作为key,并将此数放到该放置的位置(排完序后所在的位置)
2.将数组中所有大于key的值放到key的右边,将所有小于key的值放到key左边
这里我们以数组{ 6 , 1 , 2 , 7 , 9 , 3 , 4 , 5 , 10 , 8 };为例,其中 6 为 key,我们用left 和 right 分别表示数组的最左侧下标 0 与数组最右侧下标 9。这里需要让右侧先走,这样才能保证他们相遇的地点即为key排序后应到的位置。
由于 8 大于key(6),因此 right--,同理,因为 10 大于 6 ,不需要换到前面,因此 right--,现在 right 指向 5 ,小于 key ,此时 left 开始动,但是left一定要从最左侧开始动,也就是key的位置开始动,如果 left 从 1 开始动,后面递归到数组仅有两个数时,会因为一开始 left 和 right 就指向同一个位置而导致排序错误。
left指向key 6 因为不大于 key ,所以 left++ ,因为 1 、2 都小于key ,因此left++ 两次,指向 7 ,此时交换 left 与 right 的值,此时数组变成如下:
{ 6 , 1 , 2 , 5 , 9 , 3 , 4 , 7 , 10 , 8 } (红色表示发生交换的两个数)
随后重复上述操作,right 找到小于 key 的 4 ,left 找到大于 key 的 9 ,随后两者交换结果如下
{ 6 , 1 , 2 , 5 , 4 , 3 , 9 , 7 , 10 , 8 } (红色表示发生交换的两个数)
随后 right 走到 3,left 也走到 3 ,此时因为left 与right 相遇,此时交换key与left/right位置的数据即可结束第一趟排序,所得数组如下:
{ 3 , 1 , 2 , 5 , 4 , 6 , 9 , 7 , 10 , 8 } (红色表示发生交换的两个数)
此时,6 已经移动到了最终位置,无需再移动,而左右两侧也分别是小于 6 的数组与大于 6 的数组,此时将数组拆分开来分别进行单趟循环,得到以 3 为key的数组和以 9 为key的数组,然后继续递归,这样将数组不断拆分递归排序,直到拆的只剩一个数时停止递归,这样就能完成整个数组的排序。
1.1快速排序基础实现
基于上述基本思路,单趟排序代码实现如下:
int key = arr[left];//保存key的值,用于比较
int keyi = left;//记录key的下标,便于最后一次交换,将key放到应放位置
while (right > left)
{
while (arr[right] >= tmp && right > left)
{
//右边找小,若没找到小则向左移动继续找小,直到找到小或者与left相遇
right--;
}
while (arr[left] <= tmp && right > left)
{
//左边找大,若未找到大则向右移动,直到找到大或者与right相遇
left++;
}
if (left != right)
{
//交换左右两值,使得小的放到前面,大的放到后面
Swap(&arr[left], &arr[right]);
}
}
//将key放到对应位置,一趟排序确定一个点的位置,并将其他数据根据与key的大小而分成前后两组
Swap(&arr[keyi], &arr[left]);
完成一趟排序后,则需要根据key的位置将数组分成两组再次分别进行单趟排序,此时需要key的下标,根据key的下标keyi的位置,分成的两组范围分别是: [left , keyi - 1] 与 [keyi + 1 , right],但由于之前的单趟排序中ÿ