一.快速排序
1.思想
(1)选取一个数为基准数(一般是数组的第一个元素)
(2)分区:将数组中比基准数大的放到它的后面,小的放在前面,(可以设置两个游标i,j,i,j分别是数组中首尾元素的下标,程序执行一次,i++,j - -)
(3)分好后,然后将这个基准数的左右两个分区再继续执行第二步,直到区内只剩一个元素,可以用递归来解决。
- 举例说明:
a[] ={56, 23, 67, 26, 85, 14, 17, 68, 73, 45, 77}
第一步:
当前基准数=56 i=0,j=10。
(1){45,23,67,26,85,14,17,68,73,56,77}
{45,23,56,26,85,14,17,68,73,67,77}
(2){45,23,17,26,85,14,56,68,73,67,77}
{45,23,17,26,56,14,85,68,73,67,77}
(3){45,23,17,26,14,56,85,68,73,67,77}
第二步:经过上一步后,需要对{45,23,17,26,14}和{85,68,73,67,77}进行第一步的处理,直到分区中只有一个元素时
当前基数=45,i=0;j=i-1(这个i时第一步程序运行完成得到的i)
(1)14,23,26,45
2.算法设计分析(完全个人理解)
设计思路
(1)j变化:先从后往前遍历,直到找到比基准数小的数,将此数赋给a[i](这是开始基准数所在的位置)。然后i变化:从前往后遍历,找到比基准数大的数,将其赋给a[j](前面程序结束时基准数的位置),同时i随着移动。然后重复前面步骤,直到i=j。
(2)一开始找到符合条件的数时,如(1)中所说,我采用的时将基准数与找到的数进行互换,后来发现,不需要这样麻烦,因为看整个过程(不要把i和j分开),可以再每次循环前经基准数提取出来,这样就只需赋值就行了,我觉得每一轮排序就是基准数的归位过程。
关键(自认为)
- 程序一轮排序结束,也就是一个基准数的位置确定,那么接下来就是把原来的数组分成两部分,每部分执行(1)步骤,如何确定左边部分的j的值和右边部分i的值?
- 所以每一轮排序必须要返回每次基准数归为后的i的值,这样下一个基准数归位时左右两边的j和i的值才能确定。
3.代码
package org.wetmo.demo1;
public class Denokuaipai {
public static void main(String[] args) {
int[] arr = {56, 23, 67, 26, 85, 14, 17, 68, 73, 45, 77};
int i = 0, j = arr.length - 1;
show1(arr, i, j);
for (int i1 = 0; i1 < arr.length; i1++) {
System.out.print(arr[i1]+" ");
}
}
public static int show(int[] a, int i, int j) {
int tmp = a[i]; //将基准数提取出来
while (i < j) {
while (i < j && tmp <= a[j]) {
j--;//比较一次,j往前移动一次
}
a[i] = a[j];
while (i < j && tmp >=a[i]) {
i++;//比较一次,i往后移动一下
}
a[j] = a[i];
}
a[i]=tmp;//程序的最后一步,基准数归位
return i;返回这一轮循环结束后基准数成功归位后的元素下标,为下次对
}
public static void show1(int[] a,int s,int t){
if (s<t) {
int i = show(a, s, t);
show1(a, s, i - 1);
show1(a, i + 1, t);
}
}
}