简单快速排序
选取数组第一个元素为临界值,然后将数组排序,小于临界值得都放在临界值左边,大于临界值的都放在临界值右边,然后递归知道数组完全有序.但是如果数组基本有序或者数组中重复元素较多的情况下,临界值的依然选择第一个就不是很恰当了,所以后续会有快排的优化
/** * 简单快速排序--对于基本有序的数组和重复元素较多的数组时间复杂度较高,存在不足需要改进 */ public class QuickSort { private QuickSort() { } //通过分区,返回两个区的临界值 private static <T extends Comparable<? super T>> int partition(T[] arr, int low, int high) { T temp = arr[low]; int j = low; for (int i = low + 1; i <= high; i++) { if (arr[i].compareTo(temp) < 0) { j++; swap(arr, i, j); } } swap(arr, low, j); return j; } //递归将数组分区 private static <T extends Comparable<? super T>> void sort(T[] arr, int low, int high) { if (low >= high) { return; } int partition = partition(arr, low, high); sort(arr, low, partition - 1); sort(arr, partition + 1, high); } public static <T extends Comparable<? super T>> void sort(T[] arr) { sort(arr, 0, arr.length - 1); } //交换数组中的两个元素 private static <T extends Comparable<? super T>> void swap(T[] arr, int i, int j) { T temp = arr[i]; arr[i] = arr[j]; arr[j] = temp; } //打印数组元素 public static <T extends Comparable<? super T>> void printArray(T[] arr) { for (int i = 0; i < arr.length; i++) { System.out.print(arr[i] + " "); } System.out.println(); } public static void main(String[] args) { Integer[] arr = {9, 5, 1, 3, 7, 2, 8, 4, 6, 10}; sort(arr); printArray(arr); } }
快速排序优化
优化一:如果基本有序数组的第一个元素是临界值,那么临界值很可能是最小的元素,导致分区不均,时间复杂度相当于O(n^2),所以为了尽量消除数组基本有序的情况,在数组中随机选取一个元素,解决了数组基本有序排序效率低的情况,但是若数组中存在大量重复元素,效率低的情况仍未解决.
优化二:对于数组中元素基本有序时,可以更换为直接插入排序,提高排序效率
public class QuickSort { private QuickSort() { } //通过分区,返回两个区的临界值 private static <T extends Comparable<? super T>> int partition(T[] arr, int low, int high) { /*优化一:随机选取数组中的一个元素,将其与数组第一个元素进行交换*/ swap(arr, low, (int) (Math.random() * (high - low + 1) + low)); T temp = arr[low]; int j = low; for (int i = low + 1; i <= high; i++) { if (arr[i].compareTo(temp) < 0) { j++; swap(arr, i, j); } } swap(arr, low, j); return j; } //递归将数组分区 private static <T extends Comparable<? super T>> void sort(T[] arr, int low, int high) { /*优化二:对于基本有序的数组可以使用直接插入排序*/ if (high - low <= 15) { insertionSort(arr, low, high); return; } int partition = partition(arr, low, high); sort(arr, low, partition - 1); sort(arr, partition + 1, high); } public static <T extends Comparable<? super T>> void sort(T[] arr) { sort(arr, 0, arr.length - 1); } // 对arr[l...r]的区间使用InsertionSort排序 public static void insertionSort(Comparable[] arr, int l, int r) { for (int i = l + 1; i <= r; i++) { Comparable temp = arr[i]; int j = i; for (; j > l && arr[j - 1].compareTo(temp) > 0; j--) arr[j] = arr[j - 1]; arr[j] = temp; } } //交换数组中的两个元素 private static <T extends Comparable<? super T>> void swap(T[] arr, int i, int j) { T temp = arr[i]; arr[i] = arr[j]; arr[j] = temp; } //打印数组元素 public static <T extends Comparable<? super T>> void printArray(T[] arr) { for (int i = 0; i < arr.length; i++) { System.out.print(arr[i] + " "); } System.out.println(); } public static void main(String[] args) { Integer[] arr = {9, 5, 1, 3, 7, 2, 8, 4, 6, 10}; sort(arr); printArray(arr); } }
快速排序--优化2
从左向右找比临界值大的,从右向左找比临界值小的,然后将两者交换,这样对于大量相同的元素不用全部交换,解决了数组中存在大量元素的问题
public class QuickSort { private QuickSort() { } //通过分区,返回两个区的临界值 private static <T extends Comparable<? super T>> int partition(T[] arr, int low, int high) { /*优化:随机选取数组中的一个元素,将其与数组第一个元素进行交换*/ swap(arr, low, (int) (Math.random() * (high - low + 1) + low)); T temp = arr[low]; int i = low + 1; int j = high; while (true) { while (i <= high && arr[i].compareTo(temp) < 0) { i++; } while (j >= low + 1 && arr[j].compareTo(temp) > 0) { j--; } if (i > j) { break; } swap(arr,i,j); i++; j--; } swap(arr, low, j); return j; } //递归将数组分区 private static <T extends Comparable<? super T>> void sort(T[] arr, int low, int high) { /*对于基本有序的数组可以使用直接插入排序*/ if (high - low <= 15) { insertionSort(arr, low, high); return; } int partition = partition(arr, low, high); sort(arr, low, partition - 1); sort(arr, partition + 1, high); } public static <T extends Comparable<? super T>> void sort(T[] arr) { sort(arr, 0, arr.length - 1); } // 对arr[l...r]的区间使用InsertionSort排序 public static void insertionSort(Comparable[] arr, int l, int r) { for (int i = l + 1; i <= r; i++) { Comparable temp = arr[i]; int j = i; for (; j > l && arr[j - 1].compareTo(temp) > 0; j--) arr[j] = arr[j - 1]; arr[j] = temp; } } //交换数组中的两个元素 private static <T extends Comparable<? super T>> void swap(T[] arr, int i, int j) { T temp = arr[i]; arr[i] = arr[j]; arr[j] = temp; } //打印数组元素 public static <T extends Comparable<? super T>> void printArray(T[] arr) { for (int i = 0; i < arr.length; i++) { System.out.print(arr[i] + " "); } System.out.println(); } public static void main(String[] args) { Integer[] arr = {9, 5, 1, 3,7, 7, 2, 8, 4, 6, 10}; sort(arr); printArray(arr); } }
两路快排--不交换
public class QuickSort { private QuickSort() { } //通过分区,返回两个区的临界值 private static <T extends Comparable<? super T>> int partition(T[] arr, int low, int high) { /*优化:随机选取数组中的一个元素,将其与数组第一个元素进行交换*/ swap(arr, low, (int) (Math.random() * (high - low + 1) + low)); T temp = arr[low]; int i = low + 1; int j = high; while (i < j) { while (i < j && temp.compareTo(arr[j]) < 0) { j--; } arr[i] = arr[j]; //j停在那里不动 while (i < j && temp.compareTo(arr[j]) > 0) { i++; } arr[j] = arr[i];//i停在那里不动 } arr[j] = temp; return j; } //递归将数组分区 private static <T extends Comparable<? super T>> void sort(T[] arr, int low, int high) { /*对于基本有序的数组可以使用直接插入排序*/ if (high - low <= 15) { insertionSort(arr, low, high); return; } int partition = partition(arr, low, high); sort(arr, low, partition - 1); sort(arr, partition + 1, high); } public static <T extends Comparable<? super T>> void sort(T[] arr) { sort(arr, 0, arr.length - 1); } // 对arr[l...r]的区间使用InsertionSort排序 public static void insertionSort(Comparable[] arr, int l, int r) { for (int i = l + 1; i <= r; i++) { Comparable temp = arr[i]; int j = i; for (; j > l && arr[j - 1].compareTo(temp) > 0; j--) arr[j] = arr[j - 1]; arr[j] = temp; } } //交换数组中的两个元素 private static <T extends Comparable<? super T>> void swap(T[] arr, int i, int j) { T temp = arr[i]; arr[i] = arr[j]; arr[j] = temp; } //打印数组元素 public static <T extends Comparable<? super T>> void printArray(T[] arr) { for (int i = 0; i < arr.length; i++) { System.out.print(arr[i] + " "); } System.out.println(); } public static void main(String[] args) { Integer[] arr = {9, 5, 1, 3, 7, 7, 2, 8, 4, 6, 10}; sort(arr); printArray(arr); } }
三路快排
public class QuickSort { private QuickSort() { } private static <T extends Comparable<? super T>> int[] partition(T[] arr, int low, int high) { swap(arr, low, (int) (Math.random() * (high - low + 1) + low)); T temp = arr[low]; int i = low; int j = high; int cur = i; while (cur <= j) { if (temp.compareTo(arr[cur]) == 0) { cur++; } else if (temp.compareTo(arr[cur]) > 0) { swap(arr, cur++, i++); } else { swap(arr, cur, j--); } } return new int[]{i - 1, j + 1}; } private static <T extends Comparable<? super T>> void sort(T[] arr, int low, int high) { if (high - low <= 15) { insertionSort(arr, low, high); return; } int[] ret = partition(arr, low, high); sort(arr, low, ret[0]); sort(arr, ret[1], high); } public static <T extends Comparable<? super T>> void sort(T[] arr) { sort(arr, 0, arr.length - 1); } // 对arr[l...r]的区间使用InsertionSort排序 private static void insertionSort(Comparable[] arr, int l, int r) { for (int i = l + 1; i <= r; i++) { Comparable temp = arr[i]; int j = i; for (; j > l && arr[j - 1].compareTo(temp) > 0; j--) arr[j] = arr[j - 1]; arr[j] = temp; } } //交换数组中的两个元素 private static <T extends Comparable<? super T>> void swap(T[] arr, int i, int j) { T temp = arr[i]; arr[i] = arr[j]; arr[j] = temp; } //打印数组元素 public static <T extends Comparable<? super T>> void printArray(T[] arr) { for (int i = 0; i < arr.length; i++) { System.out.print(arr[i] + " "); } System.out.println(); } public static void main(String[] args) { Integer[] arr = {9, 5, 1, 3, 7, 7, 2, 8, 4, 6, 10}; sort(arr); printArray(arr); } }