快速排序
一、快排实现
快排的核心是对split()方法的理解。
split()的作用就是:将数组中比枢纽元素小的的元素排在枢纽元素前面,比枢纽元素大的元素排在枢纽元素后面。
实现split()方法后,下面就是实现快速排序了。
首先就是对递归基础条件的处理,让递归有一个出口。然后将整个数组进行split(),这样就把整个数组分割成了两部分,前半部分比枢纽元素小,后半部分比枢纽元素大,采取分而治之的思想,对两部分数组分别进行快速排序。
最后形成整体有序。
以下是实现过程,写法上比较繁琐,没有为代码好看牺牲必要的思维步骤。
#include <stdio.h>
void my_print(char*, int*, int);
void quick_sort(int*, int, int);
int split(int*, int, int);
int main()
{
int n = 0;
int arr[10] = {12, 2, 45, 22, 13, 1, 3, 5, 16, 20};
my_print("排序前", arr, 10);
quick_sort(arr, 0, 9);
my_print("排序后", arr, 10);
}
/**
* 自定义输出, 忽略这个方法
*/
void my_print(char* msg, int* arr, int length)
{
printf("%s\t", msg);
for (int i = 0; i < length; i ++)
{
printf("%d", arr[i]);
if (length - i - 1)
{
printf(", ");
} else {
printf("\n");
}
}
}
/**
* 快速排序
*/
void quick_sort(int* arr, int l, int r)
{
if (l >= r)
{
return;
}
// 整个数组进行split,
int in = split(arr, l, r);
// 分而治之
quick_sort(arr, l, in - 1);
quick_sort(arr, in + 1, r);
}
/**
* 使key左边元素都比key小, key右边的元素都比key大
* 参数:
* arr : 数组
* l : 左边界
* r : 有边界
* 返回值: 枢纽元素的位置
* ----------------------------------------
* l ---- 左边界
* r ---- 右边界
* i ---- 指向当前正在遍历的元素
* (l, k] ---- 比枢纽元素小的元素
* (k, i) ---- 比枢纽元素大的元素
* [i, r] ---- 还未或正在遍历的元素
*/
int split(int* arr, int l, int r)
{
int k = l, i = l + 1; //初始化
int key = arr[l]; //左边界元素作为枢纽元素
while (i <= r)
{
if (arr[i] <= key)
{
k ++; // 找到一个比key小的元素, 前进一步
if (i == k) //没有遇到key < arr[i]会一直保持 i == k
{
i ++;
} else {
int temp = arr[k]; //交换
arr[k] = arr[i];
arr[i] = temp;
}
} else { // 当前元素比key大, 继续
i ++;
}
}
// 循环过后
// (l, k] ---- 比枢纽元素小的元素
// (k, i] ---- 比枢纽元素大的元素
int temp = arr[l];
arr[l] = arr[k];
arr[k] = temp;
return k; // 返回枢纽元素所在的位置
}
二、JAVA中的快排
JAVA中快排主要是在split()方法上做了文章,普通的split()是选取1个枢纽元素,然后将数组分割成两部分;JAVA中的split()是一次选取2个枢纽元素,将数组分割成了三部分,让人意外的性能竟然比原先要快很多。果然一个小小的想法带来的改变是巨大的!!!!不知道有没有一位狠人在split()上一次选取3个或4个枢纽元素,估计性能还会提升。。。。。。