zoukankan      html  css  js  c++  java
  • 快速排序

    1、快速排序思想:

      快速排序主要利用分治和递归的思想,例如,将一个数组{2,5,10,1,0,7}排序。首先选取其第一个元素2作为基准,将<2的元素移动到其左边,将>=2的元素移动到其右边(其中等于2放左放右都可以),此过程称为一次分区,可以得到{0,1,2,10,5,7}。经过一次分区后,数组就分成了两个部分,左边小于2,右边大于等于2,并且局部有序了一点。因此可以继续分别对其左右分区{0,1}和{10,5,7}再分别进行快排,不断的迭代,直至完全有序。

      过程解析:写两个quickSort方法,一个是主程序调用入口,另一个是重载方法,重载的参数是迭代排序的范围。主要需要实现的partition分区方法,改方法主要利用头尾指针交替寻找比基准节点大或者小的数,并交换两个指针的值,以达到分区的目的。

    2、代码实现

    import java.util.Arrays;
    
    public class QuickSort {
        public static void main(String[] args) {
            int[] arr = {2, 5, 10, 1, 0, 7};
            System.out.println(Arrays.toString(arr));
            QuickSort quickSort = new QuickSort();
            quickSort.quickSort(arr);
            System.out.println(Arrays.toString(arr));
        }
    
        public void quickSort(int[] arr) {
            int start = 0;
            int end = arr.length - 1;
            quickSort(start, end, arr);
        }
    
        public void quickSort(int start, int end, int[] arr) {
            if (start < end) {
                int index = partition(start, end, arr);
                quickSort(start, index - 1, arr);
                quickSort(index + 1, end, arr);
            }
        }
    
        public int partition(int start, int end, int[] arr) {
            int k = arr[start];
            while (start < end) {
                while (arr[end] >= k && start < end) {
                    end--;
                }
                if (start < end) {
                    arr[start] = arr[end];
                    start++;
                }
                while (arr[start] < k && start < end) {
                    start++;
                }
                if (start < end) {
                    arr[end] = arr[start];
                    end--;
                }
            }
            arr[start] = k;
            int index = start;
            return index;
        }
    }
    import java.util.Arrays;
    
    public class QuickSort {
        public static void main(String[] args) {
            int[] arr = {2, 5, 10, 1, 0, 7};
            System.out.println(Arrays.toString(arr));
            QuickSort quickSort = new QuickSort();
            quickSort.quickSort(arr);
            System.out.println(Arrays.toString(arr));
        }
    
        //快排方法
        public void quickSort(int[] arr) {
            int start = 0;
            int end = arr.length - 1;
            quickSort(start, end, arr);
        }
    
        //快排方法重载,带上数组应该排序部分的首尾指针,每次分区完成,都要缩小范围
        public void quickSort(int start, int end, int[] arr) {
            //递归,递归的终止条件,不断的分区排序,知道不能再分区为止
            if (start < end) {
                //将数组继续拆分成两个分区,继续进行分区
                int index = partition(start, end, arr);
                //将数组继续拆分成两个分区,继续进行分区
                quickSort(start, index - 1, arr);
                quickSort(index + 1, end, arr);
            }
        }
    
        //分区方法,局部排序
        public int partition(int start, int end, int[] arr) {
            //选择数组的第一个元素为基准点,并将基准点值保存到k中
            int k = arr[start];
            //将小于基准点的元素移动至数组的左边,大于的移动至右边
            //循环终止条件,只要有头尾指针的,一般都是这个,其实遍历完了整个数组就终止了
            while (start < end) {
                //从数组的右边开始,找比基准点小的数,将指针指向该数
                //右边开始遍历,找到第一个即停止
                while (arr[end] >= k && start < end) {
                    end--;
                }
                //上面指针指向了比基准点小的元素,接下来就将该元素移动到基准点的左侧
                //放置的位置是头指针指向的位置,头指针向后移动一位
                if (start < end) {
                    arr[start] = arr[end];
                    start++;
                }
    
                //同理,从左至右找比基准点大的元素,找到了循环就先暂停
                while (arr[start] < k && start < end) {
                    start++;
                }
                //交换位置,将该值交换到尾指针指向的位置,因为尾指针的值已经赋给了之前的头指针
                //尾指针向前移位
                if (start < end) {
                    arr[end] = arr[start];
                    end--;
                }
    
                //如此反复循环,不断将遇到的第一个符合条件的元素交换至对应侧
            }
            //记得将基准点元素的值还回去,循环结束指针指向的位置就是基准点的最终位置
            arr[start] = k;
            //记录循环结束后头尾指针的位置,头尾指针肯定在一个位置上,因为循环结束了start=end
            int index = start;
            //返回该位置
            return index;
        }
    }

    3、时间空间复杂度

    时间复杂度:平均时间复杂度为O(nlogn),最坏时间复杂度O(n^2)。

    空间复杂度:每次递归传参left,和right,平均递归次数是log(n)次,所以平均空间复杂度是O(log(n))。最坏的情况是O(n)(初始是逆序的情况)。

  • 相关阅读:
    Merge Two Sorted Lists
    4Sum
    Letter Combinations of a Phone Number
    3Sum Closest
    3Sum
    Longest Common Prefix
    Roman to Integer
    Integer to Roman
    Container With Most Water
    Regular Expression Matching
  • 原文地址:https://www.cnblogs.com/guoyu1/p/11871740.html
Copyright © 2011-2022 走看看