1.
快速排序,是一种高效排序算法,就如它的名字一样。它才用分治的思想,每排一次序列,首先会把第一个数排好位置,同时把这个位置后面所有比这个数小的都挪到前面去,这个位置前面所有比这个数大的数都挪到后面。这样会把第一个数放到最终的位置(即排完序后的位置),因为这个位置之前的数即使没有排序好,但是都比这个位置的数小,而这个位置之后的数都比这个位置的数大。
比如原始数据: [6, 2, 7, 3, 9, 8]
排完一次序后, [3, 2,] 6, [7, 9, 8]
然后我们来详细解释一下这一次的排序过程。
首先一开始,我们要排序的数据有6个,从第0个到第5个。
下标:[0, 1, 2, 3, 4, 5]
数据:[6, 2, 7, 3, 9, 8]
定义数据int[] arr,记录起始位置int i=0, j=5, 记录要排的数(通常第一个数),int k = 6。
第一步,我们根据 j 的定位从后往前找比 k 小的数,当找到j=3时,arr[j]<k,我们把这个数挪到前面去,就是arr[i]的位置,因为arr[i]原来的值已经被 k 记录下来了,所以可以直接覆盖。然后arr[]变成
下标:[0, 1, 2, 3, 4, 5]
数据:[3, 2, 7, 3, 9, 8]
第二步,我们根据 i 的定位从前往后找比 k 大的数,当找到i=2时,arr[i]>k,我们把这个数挪到后面去,就是arr[j]的位置,因为arr[j]原来的值已经挪到原来arr[i]的位置,即第一个位置去了。
所以可以直接覆盖,然后arr[]变成
下标:[0, 1, 2, 3, 4, 5]
数据:[3, 2, 7, 7, 9, 8]
此时i=2, j=3
然后我们从第一步开始重复,继续根据 j 的定位从后往前找比 k 小的数,当j递减到等于2的时候,发现从两头过来的定位符 i 和 j 已经碰头了。此时这一次排序就结束了。
我们可以看到k=arr[0],
第一步是把arr[3]的数挪到arr[0]的位置,就是把3放到了arr[0],
第二步是把arr[2]的数挪到arr[3]的位置,就是把7放到了arr[3],
第二次第一步没有挪动数据,所以arr[2]的位置就是空出来的,我们把k的值挪到这个位置去,就是arr[i]的位置。其实然后arr[]变成
下标:[0, 1, 2, 3, 4, 5]
数据:[3, 2, 6, 7, 9, 8]
完成这一次排序后,可以看到第一个位置的数6,已经来到它最终的位置,前面的数都比它小,后面的数都比它大。
下标:[0, 1, 2, 3, 4, 5]
数据:[3, 2] 6 [7, 9, 8]
完成一次排序后,我们把数据分为了两份,根据数据6所在位置分隔。此时这两部分就相当于新的要排序的数组了。所以根据上面的排序规则,继续把这两个部分排序完就可以了。
我们拿出[3, 2]继续排序,i=0, j=1, k=arr[0]=3.
然后arr[1]<k, arr[0] = arr[1], arr变成[2, 2]。
然后arr[1]<k, i++, i=1, j=1, i和j 碰头了。完成排序,arr[1] = k.
arr变成[2, 3, 6, 7, 9, 8]
我们再拿出[7, 9, 8]排序,i=3, j=5, k=arr[3]=7.
然后arr[5]>k, arr[4]>k, arr[3]==k,发现i=3, j=3,i和j 已经碰头了。完成排序。arr[3]=k.
这一次完成排序。
然后只剩下[9, 8],没有排序完了。然后继续。
i=4, j=5, k=arr[4]=9.
然后arr[5]<k, arr[4]=arr[5], arr变成[8, 8]
然后arr[4]==k, i++,发现i=5, j=5,i和j 已经碰头了。完成排序。arr[5]=k.
变成[8, 9]。
至此所有分段都完成排序。
比如原始数据: [6, 2, 7, 3, 9, 8]
排完一次序后, [3, 2,] 6, [7, 9, 8]
然后我们来详细解释一下这一次的排序过程。
首先一开始,我们要排序的数据有6个,从第0个到第5个。
下标:[0, 1, 2, 3, 4, 5]
数据:[6, 2, 7, 3, 9, 8]
定义数据int[] arr,记录起始位置int i=0, j=5, 记录要排的数(通常第一个数),int k = 6。
第一步,我们根据 j 的定位从后往前找比 k 小的数,当找到j=3时,arr[j]<k,我们把这个数挪到前面去,就是arr[i]的位置,因为arr[i]原来的值已经被 k 记录下来了,所以可以直接覆盖。然后arr[]变成
下标:[0, 1, 2, 3, 4, 5]
数据:[3, 2, 7, 3, 9, 8]
第二步,我们根据 i 的定位从前往后找比 k 大的数,当找到i=2时,arr[i]>k,我们把这个数挪到后面去,就是arr[j]的位置,因为arr[j]原来的值已经挪到原来arr[i]的位置,即第一个位置去了。
所以可以直接覆盖,然后arr[]变成
下标:[0, 1, 2, 3, 4, 5]
数据:[3, 2, 7, 7, 9, 8]
此时i=2, j=3
然后我们从第一步开始重复,继续根据 j 的定位从后往前找比 k 小的数,当j递减到等于2的时候,发现从两头过来的定位符 i 和 j 已经碰头了。此时这一次排序就结束了。
我们可以看到k=arr[0],
第一步是把arr[3]的数挪到arr[0]的位置,就是把3放到了arr[0],
第二步是把arr[2]的数挪到arr[3]的位置,就是把7放到了arr[3],
第二次第一步没有挪动数据,所以arr[2]的位置就是空出来的,我们把k的值挪到这个位置去,就是arr[i]的位置。其实然后arr[]变成
下标:[0, 1, 2, 3, 4, 5]
数据:[3, 2, 6, 7, 9, 8]
完成这一次排序后,可以看到第一个位置的数6,已经来到它最终的位置,前面的数都比它小,后面的数都比它大。
下标:[0, 1, 2, 3, 4, 5]
数据:[3, 2] 6 [7, 9, 8]
完成一次排序后,我们把数据分为了两份,根据数据6所在位置分隔。此时这两部分就相当于新的要排序的数组了。所以根据上面的排序规则,继续把这两个部分排序完就可以了。
我们拿出[3, 2]继续排序,i=0, j=1, k=arr[0]=3.
然后arr[1]<k, arr[0] = arr[1], arr变成[2, 2]。
然后arr[1]<k, i++, i=1, j=1, i和j 碰头了。完成排序,arr[1] = k.
arr变成[2, 3, 6, 7, 9, 8]
我们再拿出[7, 9, 8]排序,i=3, j=5, k=arr[3]=7.
然后arr[5]>k, arr[4]>k, arr[3]==k,发现i=3, j=3,i和j 已经碰头了。完成排序。arr[3]=k.
这一次完成排序。
然后只剩下[9, 8],没有排序完了。然后继续。
i=4, j=5, k=arr[4]=9.
然后arr[5]<k, arr[4]=arr[5], arr变成[8, 8]
然后arr[4]==k, i++,发现i=5, j=5,i和j 已经碰头了。完成排序。arr[5]=k.
变成[8, 9]。
至此所有分段都完成排序。
[2, 3, 6, 7, 8, 9]
/**
*
* Quick Sort[6, 2, 7, 3, 9, 8]
*
* @param arr 要排序的数组
* @param left 要排序数组的起点位置
* @param right 要排序数组的终点位置
*/
public static void quickSort(int[] arr, int left, int right)
{
//如果起点小于等于终点了,就没必要排序了。因为没有要排序的数了。
if (left >= right)
return;
int i = left;//起点定位坐标
int j = right;//终点定位坐标
int k = arr[i];//要被排序的数字
while (i < j)//起点坐标始终小于终点坐标
{
//从右到左找出比k小的数据,同时起点坐标始终小于终点坐标
while (i < j && arr[j] >= k)
{
j--;
}
//此时只有两种情况
//1. i==j,i和j已经碰头,a[i] = a[j]就是同一个值赋值
//2. arr[j]<k了,找到比k小的数据arr[j]了
//所以这里可以直接赋值,把arr[j]的数据放到arr[i]的位置去
arr[i] = arr[j];
//从左到右找出比k大的数据,同时起点坐标始终小于终点坐标
//因为上面不是i==j,就是找到了比k小的数据
//所以下面不是i==j,的话i的值肯定要变化
//所以下面的arr[j]=arr[i],要不就是同一个数,要不就是比k大的数放到j的位置,就是k的右边了
while (i < j && arr[i] <= k)
{
i++;
}
//此时只有两种情况
//1. i==j,i和j已经碰头
//2. arr[i]>k了,找到比k大的数据arr[i]了
//所以这里可以直接赋值,把arr[i]的数据放到arr[j]的位置去
arr[j] = arr[i];
}
//根据上面循环最后得到arr[j] = arr[i],所以arr[i]的值已经赋值给别人了,肯定是空出来
//所以这里把k的值放到arr[i]的位置,而且这个位置就是k排完序后的最终位置
arr[i] = k;
//既然arr[i]的数据已经确定位置了,然后我们只要把arr[i]前面的数据和后面的数据
//分别按照上的步骤再排序即可
//这里用递归实现再恰当不过了,而这个递归的出口就是要排序的起点已经大于等于终点了
quickSort(arr, left, i - 1);
quickSort(arr, i + 1, right);
}