这个算法实现中,对小的子数组使用插入排序,借此来提高性能。
Knuth推荐对小数组的切割点为9,正是程序中使用的值。实践中还需要根据测试请看选择更好的切割点。
import java.util.Random; public class QuickSort2 { private long[] theArr; private int nElems; public QuickSort2(int max) { this.theArr = new long[max]; this.nElems = 0; } public void insert(long value) { this.theArr[nElems++] = value; } public void display() { System.out.print("A="); for (int i = 0; i < nElems; i++) { System.out.print(theArr[i] + " "); } System.out.println(); } public void quickSort() { this.recQuickSort(0, nElems - 1); } public void recQuickSort(int left, int right) { int size = right - left + 1; if (size <= 9) { // insert sort or sth. else. insertSort(left, right); } else { // quick sort long median = medianOf3(left, right); int partition = partitionIt(left, right, median); recQuickSort(left, partition - 1); recQuickSort(partition + 1, right); } } public void insertSort(int left, int right) { int in, out; for (out = left + 1; out <= right; out++) { long temp = theArr[out]; in = out; while (in > left && theArr[in - 1] > temp) { theArr[in] = theArr[in - 1]; --in; } theArr[in] = temp; } } /** * 因为使用了取头尾和中间点的中值作为枢纽点,并且在median3方法中 * 已经对三个值进行了正确的排序,左右指针都不会越界,所以这里去除了对leftPtr < right * 和rightPtr > left的检测,稍微提高了性能。 * */ public int partitionIt(int left, int right, long pivot) { int leftPtr = left; int rightPtr = right - 1; while (true) { while (theArr[++leftPtr] < pivot) { // } while (theArr[--rightPtr] > pivot) { // } if (leftPtr >= rightPtr) { break; } else { swap(leftPtr, rightPtr); } } swap(leftPtr, right - 1); return leftPtr; } /** * 取三中值法,分别取头尾和中间的点, * 分别取得正确位置以后,再将中值放到最后一个位置进行快速排序。 */ public long medianOf3(int left, int right) { int center = (left + right) / 2; if (theArr[left] > theArr[center]) { swap(left, center); } if (theArr[left] > theArr[right]) { swap(left, right); } if (theArr[center] > theArr[right]) { swap(center, right); } swap(center, right - 1); return theArr[right - 1]; } public void swap(int dex1, int dex2) { long temp = theArr[dex1]; theArr[dex1] = theArr[dex2]; theArr[dex2] = temp; } public static void main(String... args) { if (args.length < 1) { System.out.println("usage: java QuickSort2 number"); return; } QuickSort2 qs = new QuickSort2(100); int count = Integer.parseInt(args[0]); Random rand = new Random(); for (int i = 0; i < count; i++) { qs.insert(rand.nextInt(count * count)); } qs.display(); qs.quickSort(); qs.display(); } }
选取三中值是为了防止在极端情况下,比如每次选取的中值是所有数据中最大或者最小的情况,快速排序性能急剧下降。