快速排序算法(代码实现)
关于快速排序算法我们就不一步一步的进行推导了,而是直接归纳为一个方法(代码如下: 我们还是以方法的形式给出:)
/*
这里我们直接给出我们归纳好的快速排序算法
*/
/*
我们在快速排序中形参位置的变量都是来记录我们的数组中的指定位置的,这个变量的值要起一个记录位置的作用, 也就是形参位置定义的记录位置的left
和right是不能改变的,所以我们就要定义一个l和一个r来先接收left和right的值,然后来代替我们的left和right来移动 ---> 这个其实是一个思
想 : 只要我们使用到递归的时候我们都会使用到这种思想
在使用到递归的时候我们一般都是在方法形参位置定义一些变量专门就是用来记录位置的,这些变量的值不能变化,所以如果需要遍历的时候我们就要重新创建一个变量来帮助我们遍历
*/
public static void quickSort(int [] arr,int left,int right) {
//定义两个变量l和r,用于当做哨兵来进行移动
int l = left; //左下标
int r = right; //右下标
//创建一个临时变量表示中轴值
int pivot = arr[(left + right) / 2];
/*
由于我们的左下标和右下标位置的位置的元素有可能会发生交换,这个时候我们就要先定义一个临时变量temp来为我们两个位置的值的交换做好准备
*/
int temp = 0;
//外层while循环,外层while循环的目的就是为了让比pivot值小的元素放到左边,让比pivot值大的放到pivot的右边
while (l < r) {
/*
在pivot的左边一直找,直到找到大于或者等于pivot的值,才退出
*/
while (arr[l] < pivot) {
l++;
}
/*
在pivot的右边一直找,直到找到小于或者等于pivot的值才退出
*/
while (arr[r] > pivot) {
r--;
}
/*
这里的这个判断就是当我们找到了交换位置的两个元素的时候判断一下有没有必要交换位置,如果两个位置是相同的,那么就不需要交换
这个时候l > r是永远都不会发生的,因为这个时候我们不管怎么样最后l和r都是先指向我们的pivot的值的位置上去,所以这里只是单纯的
提升效率这个判断条件是可以修改 if(l = r)的
*/
if (l >= r) {
break;
}
/*
进行元素的交换
*/
temp = arr[l];
arr[l] = arr[r];
arr[r] = temp;
/*
判断如果l的位置的值如果等于 pivot,这个时候就直接让r--,提高效率,但是注意: 如果下面的arr[r]也等于pivot的时候,这个时候如果这个时
候的l还不等于r,那么这个时候就会出现死循环,而我们的后面这两个判断条件可以帮助我们规避死循环的发生
*/
if (arr[l] == pivot) {
r--;
}
if (arr[r] == pivot) {
l++;
}
}
/*
由于我们为了提升效率,如果上面的判断出来交换的l和r之后如果l == r就会直接退出外层训话,这个时候我们就要做一个判断,只要上面
的外层while循环退出的时候r == l ,这个时候为了避免后面递归调用的时候出现无限递归的问题,这个时候我们就要当r == l的时候让
r++也让l--,其实只要r < l且l != r就可以了,但是这个时候我们还是最好让两个变量都移动一下,从pivot的位置离开,因为pivot的值已经是判断好了
下一次递归的时候就不需要将它也作为待排序序列的一员传入到我们的递归调用方法中去了
*/
if (l == r) {
l++;
r--;
}
//如果我们的left == r的时候这时候就是表示左待排序序列中只有一个元素了,就不用排序了
if(left < r) {
quickSort(arr, left, r);
}
//同理: 如果我们的right == l 的时候这个时候也就是表示右待排序序列中只有一个元素了,就不用排序了
if(right > l) {
quickSort(arr, l, right);
}
}
补充:
我们的快速排序算法中使用的就是双指针,每次遍历的时候两个指针至少要移动一个,否则就可能会出现死循环