快排分为两种:
1.lomuto分区算法 (快慢指针)(单边)
2.Hoare分区算法 (前后指针)(双边)
快排主要思想:选一个基准元素分为两部分,先让左边排一下序再让右边排序
默认:最右边的元素作为基准点
1.设置两个指针(dest , cur),通过使用dest找比基准点大的,cur找比基准点小的
2.当同时停下并且不相等进行交换,这样会达到一种dest是比基准点小的分界点,左边全是比基准点小的,走到最后一步只需要与基准点交换即可。遍历序列并交换元素:从序列的第一个元素开始,逐个与基准元素进行比较,将小于等于基准元素的元素交换到序列的左侧。
3.更新基准元素位置:遍历完成后,将基准元素交换到正确的位置上,使得基准元素左侧的元素都小于等于它,右侧的元素都大于它。
4.分治递归:对基准元素左右两侧的子序列分别重复以上步骤,直到每个子序列只剩下一个元素或为空。
平均复杂度:O(nlogn)
最坏情况:O(n^2)
1.在最坏情况下,即每次划分都导致一个子序列为空
我们可以通过随机基准点进行优化,以防止出现这种情况
2.数据量很少的时候,快排并不有优势,反倒不如插入排序,所以我对其进行了当元素小于10时候,我就使用插入排序。
默认: 最左边的元素为基准点
注意点:一定要先移动右指针,在移动左指针,因为右指针找是比基准点小的,谁先走就意味着最后一轮谁过后谁先移动去找另一个,而右指针最后一次交换存的是比基准点大的,左指针是比基准点小的,要是先移动左指针就会使一个比基准点大的元素放在基准点前面
-
- /*
- *实现快速排序(单边循环)
- *
- * lomuto快速排序
- * */
-
- public class sortTest9 {
- private int[] data;
- public void sort(int[] data){
- this.data = data;
- dfs(0,data.length - 1);
- }
-
- private void dfs(int start, int end) {
- //分区的时候只有一个元素结束递归
- if (start == end) return;
- //分区(已基准点分区)
- int j = partition(start,end);
-
- //左分区
- dfs(j - 1, end);
- //右分区
- dfs(start, j + 1);
- }
-
- private int partition(int start, int end) {
- //定义基准数
- int prev = data[end];
- int less = start;//慢指针
- int great = start;//快指针
- for (; great < end - 1; great++) {
- if (data[great] < prev){
- //防止无意义的空交换
- if (great != less) swap(data,less,great);
- less++;
- }
- }
- //到最后交换基准数(也就是end的值)和慢指针less的值
- swap(data,less,end);
-
- //慢指针所在的位置就是分区的位置
- return less;
- }
-
- private void swap(int[] data, int less, int great) {
- int temp = data[less];
- data[less] = data[great];
- data[great] = temp;
- }
- }
-
-
- /*
- *实现快速排序(双边循环)
- *
- * */
-
- public class sortTest10 {
- private int[] data;
- public void sort(int[] data){
- this.data = data;
- dfs(0,data.length - 1);
- }
-
- private void dfs(int start, int end) {
- int i = start;
- int j = end;
- //定义基准数
- int prev = data[start];
- if (i > j){
- return;
- }
-
- //处理重复元素(相等的也交换)并且双指针都移动
- while(i != j){
- //后指针找比基准数小的
- while(true) {
- //等于不等于都一样(基准数左边可以含有等于基准点的数右边也可以)
- if (i < j && data[j] < prev) {
- break;
- }
- j--;
- }
-
- //前指针找比基准数大的
- while(true){
- if (i < j && data[i] > prev) break;
- i++;
- }
- swap(i,j);
- j--;
- i++;
- }
- //确定了两指针指向头一个与基准数交换
- swap(j,start);
-
- //左分区
- swap(start,j - 1);
- //右分区
- swap(j + 1,end);
- }
- //用来交换元素
- private void swap(int less, int great) {
- int temp = data[less];
- data[less] = data[great];
- data[great] = temp;
- }
- }
1.随机基准点
2.处理重复元素
3.当递归到元素小于10的时候转为插入排序
- import java.util.Arrays;
- import java.util.Random;
-
- public class sortTest11 {
- private static final int INSERTION_SORT_THRESHOLD = 10;
-
- public static void quickSort(int[] array) {
- quickSort(array, 0, array.length - 1);
- }
-
- private static void quickSort(int[] array, int start, int end) {
- if (start < end) {
- // 当元素个数小于等于阈值时,使用插入排序
- if (end - start + 1 <= INSERTION_SORT_THRESHOLD) {
- insertionSort(array, start, end);
- } else {
- // 随机选择基准值,并进行划分
- int pivotIndex = randomPartition(array, start, end);
-
- // 对基准值左侧的子数组递归排序
- quickSort(array, start, pivotIndex - 1);
-
- // 对基准值右侧的子数组递归排序
- quickSort(array, pivotIndex + 1, end);
- }
- }
- }
-
- private static int randomPartition(int[] array, int start, int end) {
- int randomIndex = new Random().nextInt(end - start) + start;
- swap(array, randomIndex, start);
- return partition(array, start, end);
- }
-
- private static int partition(int[] array, int start, int end) {
- int pivot = array[start];
- int left = start + 1;
- int right = end;
-
- while (left <= right) {
- while (left <= right && array[left] <= pivot) {
- left++;
- }
-
- while (left <= right && array[right] > pivot) {
- right--;
- }
-
- if (left < right) {
- swap(array, left, right);
- left++;
- right--;
- }
- }
-
- swap(array, start, right);
- return right;
- }
-
- private static void insertionSort(int[] array, int start, int end) {
- for (int i = start + 1; i <= end; i++) {
- int key = array[i];
- int j = i - 1;
-
- while (j >= start && array[j] > key) {
- array[j + 1] = array[j];
- j--;
- }
-
- array[j + 1] = key;
- }
- }
-
- private static void swap(int[] array, int i, int j) {
- int temp = array[i];
- array[i] = array[j];
- array[j] = temp;
- }
- }