快速排序
前言
快速排序是对冒泡排序的一种优化的排序算法
1、什么是快速排序?
快速排序法,是通过把每一个元素的位置确定,从而达到整个数组的排序,即,由内而外,由小及大。
快速排序法号称是目前最优秀的算法之一,实现思路是,将一个数组的排序问题看成是两个小数组的排序问题,而每个小的数组又可以继续看成更小的两个数组,一直递归下去,直到数组长度大小最大为2(如果不能理解为什么,看完这篇你就明白了)。
2、快速排序过程分析
过程分析(以从小到大排序为例):
1.元素交换法
1.过程分析
理解1:我称之为元素交换法
1.先选取数组的一个元素作为参照物(一般选取第一个或者最后一个元素)
2.如果选取第一个元素,那么就从右往左开始找元素。此时的下标记为R。每找一个元素R=R-1,直到找到一个小于参照物的元素。记录此时的R。
3.然后再从左往右开始找元素。此时的下标记为L。每找一个元素L=L+1,直到找到一个大于参照物的元素。记录此时的L,
4.如果L<R,就把下标为L,R的两个元素的位置交换一下。
5.以L,R的位置作为起点重复2和3的步骤。
6.L=R时,把参照物与此时的下标为L(R)的元素交换位置,第一次结束。
7.把L=R这个位置左右两边的元素划分为两个小数组,重复步骤1——6.
步骤7实质上是递归的思想。
过程图示:(动图是找的一个,有很多类似的动图,这个是比较符合我所理解的快速排序。)
2.代码实现
代码如下(示例):
public static void quickSort(int[] arr,int low,int high){
int i,j,temp,t;
if(low>high){
return;
}
i=low;
j=high;
//temp就是基准位
temp = arr[low];
while (i<j) {
//先看右边,依次往左递减
while (temp<=arr[j]&&i<j) {
j--;
}
//再看左边,依次往右递增
while (temp>=arr[i]&&i<j) {
i++;
}
//如果满足条件则交换
if (i<j) {
t = arr[j];
arr[j] = arr[i];
arr[i] = t;
}
}
//最后将基准位与i和j相等位置的数字交换
arr[low] = arr[i];
arr[i] = temp;
//递归调用左半数组
quickSort(arr, low, j-1);
//递归调用右半数组
quickSort(arr, j+1, high);
}
2. 填坑法
1.过程分析
理解2:我称之为“填坑法”。
所谓的“填坑法”,就是一个萝卜一个坑。
过程与上面的元素交换法基本上一样,区别在于,选取参照物的时候,就当做参照物这个位置的元素被“挖空”,这个位置就多出来一个“坑”。然后就按照元素交换法的找元素过程,当找到符合比参照物大(从左往右找)或者小(从右往左找)的时候。把此时的元素“挖”出来,“填”到参照物原本的那个“坑”里。就这样不断的“挖坑”、“填坑”。就可以来确定每一次选取的参照物的位置,再和上面的那个方法一样,划分小数组,进行递归,就完成了对数组的排序。
过程图示:
1.定义一个无序的数组:
2.选取一个参照元素取出来存起来(这里我选取的是第一个元素)
3.假装第一个位置的元素被“挖空”,并从右往左找比参照物(5)小的元素
4.可以发现0<5,于是就把0“填到”第一个的“坑”里。并开始从左往右找比参照物(5)大的值
5.找啊找啊,发现第三个元素8>5,于是就把8“填到”右边的“坑”里。R从8的左边一位继续找,即R=R-1的位置。
6.同样的,每当右边的元素“填”进左边的“坑”里,就从L=L+1的位置往右找比参照物大的元素,过程不再赘述了。
7.重复进行3、4、5的步骤,直到R与L指向同一个位置,这个位置就是参照物最终的位置。
把参照物“填”进这个“坑”里。
不难发现,此时的数组被参照物(5)分成两个小数组(左边一个数组放的是比参照物(5)小的元素,右边数组放的是比参照物(5)大的元素。)
8.分别对左边的数组,右边的数组重复2—7,就确定了每个元素的位置,从而,整个数组就是按照从小到大的顺序排列的了。
2.代码实现
代码如下(示例):
public static void quickSort1(int arr[], int low, int high) {
int l = low;
int r = high;
int key = arr[low];
while (r > l) {
// 从后往前比较
while (r > l && arr[r] >= key)
// 如果没有比关键值小的,比较下一个,直到有比关键值小的交换位置,然后又从前往后比较
r--;
if (arr[r] < key) {
int temp = arr[r];
arr[r] = arr[l];
arr[l] = temp;
}
// 从前往后比较
while (r > l && arr[l] <= key)
// 如果没有比关键值大的,比较下一个,直到有比关键值大的交换位置
l++;
if (arr[l] > key) {
int temp = arr[l];
arr[l] = arr[r];
arr[r] = temp;
}
// 此时第一次循环比较结束,关键值的位置已经确定了。左边的值都比关键值小,右边的值都比关键值大,但是两边的顺序还有可能是不一样的,进行下面的递归调用
}
// 递归
if (l > low)
quickSort1(arr, low, l - 1);// 左边序列。第一个索引位置到关键值索引-1
if (r < high)
quickSort1(arr, r + 1, high);// 右边序列。从关键值索引+1到最后一个
}
总结
快速排序是对冒泡排序算法的优化,主要是通过递归的思想,把每个元素的位置确定下来,由小到大,由内而外地把数组的顺序排好。重点在于参照物的选取,以及元素交换位置或者“填入坑里”的条件。理清楚这些东西,对数组的排序就很简单了。