快速排序
快速排序算是冒泡排序的一个升级版,更高效快捷,常出现在各大面试中。
时间复杂度为O (nlogn)【不用太纠结复杂度】。
非稳定性
注意的是:快速排序不是一种稳定的排序算法,如果遇到相同的值,位置也许会在结束时产生变动。
例如数组:[1,2,8,3,5,8`];排序后结果也许是[1,2,3,5,8,8·]也可能是[1,2,3,5,8·,8]
原理
用数组的一个数值当做关键数据(基数),把比他小的数放到左边,比他大的数放到右边。
指针交换法
在开始交换之前需要知道三个数值
1.定义基数(基数可为数组中的任意一个数,现在拿数组第一个数当做基数)
2.定义数组的头部位置,i=0.
3.定义数组的尾部位置,j=N-1.(N为数组长度)
排序如下数组:
排序步骤
一开始我们先从j往后进行比较( j-1)
1).当 j > index, j--
2).当 i < index, i++
3).当 i 和 j的值相同时,i++然后重复执行第一和二的步骤,条件不满足则将j和i的值交换. 设数组变量名为:A
对应代码:
//1).当 j > index, j--
for(;(i < j) && (a[j] > index);)
--j;
//2).当 i < index, i++
for(;(i < j) && (a[i] < index);)
++i;
//).当 i 和 j的值相同时,i++然后重复执行第一和二的步骤,条件不满足则将j和i的值交换.
if ((a[i]==a[j])&&(i<j)) {
++i;
else{
//利用第三方交换数据
int temp = A[i];
A[i] = A[j];
A[j] = temp;
}
排序演示
此时,index = 5,i = 0.j = 7.
步骤
1.从后面开始找,当j–到 j=2时,找到第一个小于index的数
2.从i位置找,目前这个数组中A[i] = 5,index 也为 5,不满足 i < index 所以也算比index大
3.A[i]不等于a[j],交换数据.重复执行1,2个步骤
当第一二步重复执行完后i = 2,j = 2,当i = j时结束本轮排序.
从上图来看,可以直观的看到,基数左边的数比他小,右边的数比他大.
第二轮排序
1)将数组A划分成两部分
对于刚刚分割的前后两部分数,可以采用上面同样的方法来排序。
我再演示一遍a2的排序,a1就不演示了.
现在102对应i的位置应该是4,j位置为N-1,基数设置为102吧 当前变量为 index = 102,i = 4,j=8;
走完步骤第一二步,数值交换.重复执行第一二步
结果如下,本轮分割结束
当排序完后的分割,如果基数旁边没有数值了,就不用分割另个数组了。 这是分割后的数组,只切割出了一个数组.
完整代码如下:
import java.util.Random;
public class FastSort2 {
static int count = 1;
public static void main(String[] args) {
int a[] = new int[] {5,3,4,102,7,6,8,13};
/*int a[] = new int[10000000];
Random rm = new Random();
for(int i=0;i<a.length;i++) {
a[i] = rm.nextInt(10000);
}*/
long Strat = System.currentTimeMillis();
method(a,0,a.length - 1);
long j = System.currentTimeMillis();
System.out.println(j - Strat);
for(int c: a) {
System.out.print(c + " ");
}
}
//交换数据
public static void exchange(int[] a,int i,int j) {
int temp = a[i];
a[i] = a[j];
a[j] = temp;
}
public static void method(int[] a, int low, int right) {
if(right < low) {
return;
}
//定义基数,数组头部和数组尾部
int i = low, j = right,index = a[low];
while (i < j) {
//从后面开始找,直到找到第一个小于index的数
for(;(i < j) && (a[j] > index);)
--j;
//前面找,直到找到第一个大于index的数
for(;(i < j) && (a[i] < index);)
++i;
if ((a[i]==a[j])&&(i<j)) {
++i;
} else {
//交换两个数值的值
exchange(a,i,j);
}
System.out.format("第%d次分割,基数 = %d,当前i=%d,j=%d\n", count++,index,i,j);
for(int c: a) {
System.out.print(c + " ");
}
System.out.println();
//当排序完后的分割,如果基数旁边没有数值了,就不用分割另个数组了。
//i - 1 和 j + 1这两个条件,就是为了确认是否有超出数组的边界范围。
if(i - 1 > low) {
method(a,low,i - 1);
}
if(j + 1 < right) {
method(a,j+1,right);
}
}
}
}
小结
希望通过本文,能理解快速排序~~~~~~~~~~