快速排序
引言
孔甲己一到店,跟柜里说,“来一杯茶,要一碟茴香豆。”便排出九文大钱。看没人理自己,便对记账的小童问道,这茴香豆的茴字有四种写法,你知道么?
近期闲来看了看快速排序,核心思想也就在于,找到一个可以作为中间分隔的数字,再将大的放到左边,小的放到右边,重复数次。
在网上查找相关资料,找到了快速排序的3种写法
所使用到的接口和抽象类
注:只是为了练习泛型,并且让测试更加方便。
public interface Sort<T extends Comparable<? super T>> {
void sort();
void sort(int start, int end);
}
public abstract class BaseSort<E extends Comparable<? super E>> implements Sort<E> {
protected E[] arr;
public BaseSort(E[] arr) {
this.arr = arr;
}
public E[] getArr() {
return arr;
}
}
基本思想
选择左边第一个作为中心数pivot
,我们需要将大的数放到右边,小的数放到左边。再以pivot
的左右两边分别进行这个操作,就可以得到一个排序好的数组了。
三种写法
-
我们选择左边的第一个数作为中心数,(先把中心数保存下来,因为该位置的数待会会被替换),所以先从右边开始寻找。简单原因可以查看这篇博客.设置两个索引,一个是
low
,表示左边的索引,一个是high
,表示右边的索引。此时从右往左,如果找到的数比
pivot
大,就一直向左找,直到找到一个比pivot
小的,此时,再将左边的low
指针指向的数赋值为这个数。再从左往右找。
翻译为代码就是
public class MyQuickSort<E extends Comparable<? super E>> extends BaseSort<E> {
public MyQuickSort(E[] arr) {
super(arr);
}
@Override
public void sort() {
sort(0, arr.length - 1);
}
@Override
public void sort(int start, int end) {
if (start < end) {
int partitionIndex = partition(start, end);
sort(start, partitionIndex - 1);
sort(partitionIndex + 1, end);
}
}
private int partition(int start, int end) {
int low = start;
int high = end;
E key = arr[low];
while (inRange(low, high)) {
while (inRange(low, high) && arr[high].compareTo(key) > 0) {
high--;
}
if (inRange(low, high))
arr[low++] = arr[high];
while(inRange(low, high) && arr[low].compareTo(key) < 0) {
low++;
}
if (inRange(low, high))
arr[high--] = arr[low];
}
arr[low] = key;
return low;
}
private boolean inRange(int low, int high) {
return low < high;
}
}
-
我们还是选择第一个作为
pivot
,从后向前找,不过,这一次,我们从后向前找到一个比基准数小的数时,我们再从前向后找,找到比基准数大的值,将二者交换即可。public class MyQuickSort2<E extends Comparable<? super E>> extends BaseSort<E> { public MyQuickSort2(E[] arr) { super(arr); } @Override public void sort() { sort(0, arr.length - 1); } @Override public void sort(int start, int end) { if (start < end) { int partitionIndex = partition(start, end); sort(start, partitionIndex - 1); sort(partitionIndex + 1, end); } } private int partition(int start, int end) { int low = start; int high = end; int keyIndex = low; while (inRange(low, high)) { while (inRange(low, high) && arr[high].compareTo(arr[keyIndex]) > 0) { high--; } while (inRange(low, high) && arr[low].compareTo(arr[keyIndex]) < 0) { low++; } if (inRange(low, high)) { swap(low, high--); } } swap(keyIndex, low); return low; } private void swap(int indexA, int indexB) { E temp = arr[indexA]; arr[indexA] = arr[indexB]; arr[indexB] = temp; } private boolean inRange(int low, int high) { return low < high; } }
-
这种方法来自于geeksforgeeks,这次我们选择右边的作为基准数,从左开始,使用一个临时变量指向比基准值小的数,然后循环遍历所有的数,如果当前遍历到的数比基准数小,则将其和小指针指向的下一个索引进行交换。
public class QuickSort<E extends Comparable<? super E>> extends BaseSort<E> { public QuickSort(E[] arr) { super(arr); } @Override public void sort() { sort(0, arr.length - 1); } private int partition(int low, int high) { final E pivot = arr[high]; int lowPoint = low - 1; for (int j = low; j < high; j++) { if (arr[j].compareTo(pivot) < 0) { lowPoint++; swap(lowPoint, j); } } swap(lowPoint + 1, high); return lowPoint + 1; } private void swap(int indexA, int indexB) { if (indexA == indexB) { return; } E temp = arr[indexA]; arr[indexA] = arr[indexB]; arr[indexB] = temp; } @Override public void sort(int start, int end) { if (start < end) { int partitionIndex = partition(start, end); // lower sort(start, partitionIndex - 1); // higher sort(partitionIndex + 1, end); } } }