排序中快速排序和归并排序的平均时间复杂度的nlogn,所以是比较常用的两种排序。
快速排序的主要思想是递归的“切分”一串儿数字,切分就是选取一个数组中的数字,把数组中比这个数字小的放左边,大的放右边,这就完成了一次切分。然后再将切分点左边的和右边的子数组切分,如此反复,直到要切分的数组长度为1,整个数组就排好序了。
看代码。
先写个AbstractSort,实现一些基本通用的功能,在归并排序中就不用重复写了。
package sort;
public abstract class AbstractSort
{
public abstract void sort(Comparable[] a);
public void randomArray(Comparable[] a)
{
int len = a.length;
for(int i = 0;i < len;i++)
{
exch(a,i,(int)Math.random()*len);
}
}
public boolean less(Comparable v, Comparable w)
{
return v.compareTo(w) < 0;
}
public void exch(Comparable[] array, int index1, int index2)
{
Comparable temp = array[index1];
array[index1] = array[index2];
array[index2] = temp;
}
public void show(Comparable[] a)
{
for (Comparable i : a)
System.out.println(i);
}
public boolean isSorted(Comparable[] a)
{
for (int i = 1; i < a.length; i++)
if (less(a[i], a[i - 1]))
return false;
return true;
}
}
package sort;
public class QuickSort extends AbstractSort
{
int len;
@Override
public void sort(Comparable[] a)
{
len = a.length;
randomArray(a);
sort(a, 0, len - 1);
}
public void sort3way(Comparable[] a)
{
len = a.length;
randomArray(a);
sort3way(a, 0, len - 1);
}
/**
* 标准快速排序
* @param a
* @param lo
* @param hi
*/
private void sort(Comparable[] a, int lo, int hi)
{
if (lo >= hi)
return;
int j = partition(a, lo, hi);//切分并返回切分的位置
sort(a, lo, j - 1);
sort(a, j + 1, hi);
}
private int partition(Comparable[] a, int lo, int hi)
{
int i = lo;
int j = hi + 1;
Comparable key = a[lo];
while (true)
{
//一定要先走j指针,不然i指针可能走到j指针导致数组溢出
while (!less(a[--j], key))
{
if (j <= i)
break;
}
while (!less(key, a[++i]))
{
if (i >= j)
break;
}
if (i >= j)
break;
exch(a, i, j);
}
exch(a, lo, j);
return j;
}
}
快速排序先要将数组随机乱序,避免最坏情况。
这里的切分点选取的是数组的第一个数。
这里的排序程序并不只是针对数字,而是所有实现了Comparable接口的类都可以排序,包括Integer,String等等。