zoukankan      html  css  js  c++  java
  • Java排序算法之快速排序

    一、算法原理

      基于分治的思想,是冒泡排序的改进型。首先在数组中选择一个基准点(该基准点的选取可能影响快速排序的效率,后面讲解选取的方法),然后分别从数组的两端扫描数组,设两个指示标志(low指向起始位置,high指向末尾),首先从后半部分开始,如果发现有元素比该基准点的值小,就交换low和high位置的值,然后从前半部分开始扫秒,发现有元素大于基准点的值,就交换low和hi位置的值,如此往复循环,直到low>=high,然后把基准点的值放到hi这个位置。一次排序就完成了。以后采用递归的方式分别对前半部分和后半部分排序,当前半部分和后半部分均有序时该数组就自然有序了。

    二、算法举例

    三、算法实现

     

     1 /**
     2      * 查找出中轴(默认是最低位low)的在numbers数组排序后所在位置
     3      *
     4      * @param array 待查找数组
     5      * @param lo   开始位置
     6      * @param hi  结束位置
     7      * @return  中轴所在位置
     8      */
     9     static int getMiddle(int []array,int lo,int hi) {
    10         //固定的切分方式
    11         int key=array[lo];
    12         while(lo<hi){
    13             //从后半部分向前扫描
    14             while(array[hi]>=key&&hi>lo){
    15                 hi--;
    16             }
    17             array[lo]=array[hi];
    18             //从前半部分向后扫描
    19             while(array[lo]<=key&&hi>lo){
    20                 lo++;
    21             }
    22             array[hi]=array[lo];
    23         }
    24         array[hi]=key;
    25         return hi;
    26     }
    27 
    28     /**
    29      *
    30      * @param numbers 带排序数组
    31      * @param low  开始位置
    32      * @param high 结束位置
    33      */
    34     static int[] quickSort(int[] numbers,int low,int high) {
    35         if(low < high) {
    36             int middle = getMiddle(numbers,low,high); //将numbers数组进行一分为二
    37             quickSort(numbers, low, middle-1);   //对低字段表进行递归排序
    38             quickSort(numbers, middle+1, high); //对高字段表进行递归排序
    39         }
    40         return numbers;
    41     }

      快速排序的时间复杂度为O(NlogN)。

    四、算法优化

      对于基准位置的选取一般有三种方法:固定切分,随机切分和三取样切分。固定切分的效率并不是太好,随机切分是常用的一种切分,效率比较高,最坏情况下时间复杂度有可能为O(N2).对于三数取中选择基准点是最理想的一种。

     1 /**
     2      *
     3      * @param array 待排序的数组
     4      * @param lo 开始位置
     5      * @param hi 结束位置
     6      * @return 基准值所在位置
     7      */
     8     static int partition(int []array,int lo,int hi){
     9         //三数取中
    10         int mid=lo+(hi-lo)/2;
    11         if(array[mid]>array[hi]){
    12             swap(array[mid],array[hi]);
    13         }
    14         if(array[lo]>array[hi]){
    15             swap(array[lo],array[hi]);
    16         }
    17         if(array[mid]>array[lo]){
    18             swap(array[mid],array[lo]);
    19         }
    20         int key=array[lo];
    21 
    22         while(lo<hi){
    23             while(array[hi]>=key&&hi>lo){
    24                 hi--;
    25             }
    26             array[lo]=array[hi];
    27             while(array[lo]<=key&&hi>lo){
    28                 lo++;
    29             }
    30             array[hi]=array[lo];
    31         }
    32         array[hi]=key;
    33         return hi;
    34     }
    35 
    36     /**
    37      * 交换a,b的值
    38      * @param a 待交换a
    39      * @param b 待交换b
    40      */
    41     static void swap(int a,int b){
    42         int temp=a;
    43         a=b;
    44         b=temp;
    45     }
    46 
    47     /**
    48      *
    49      * @param array 带排序数组
    50      * @param lo  开始位置
    51      * @param hi 结束位置
    52      */
    53     static int[] sort(int[] array,int lo ,int hi){
    54         if(lo>=hi){
    55             return array;
    56         }
    57         int index=partition(array,lo,hi);
    58         sort(array,lo,index-1);
    59         sort(array,index+1,hi);
    60         return array;
    61     }

      快速排序在序列中元素很少时,效率将比较低,不然插入排序,因此一般在序列中元素很少时使用插入排序,这样可以提高整体效率。

    测试用例:

      1 package recursion;
      2 
      3 import java.util.Arrays;
      4 
      5 /**
      6  * @author zsh
      7  * @company wlgzs
      8  * @create 2019-02-17 15:32
      9  * @Describe 快速排序
     10  */
     11 public class QuickSort {
     12 
     13     /**
     14      * 查找出中轴(默认是最低位low)的在numbers数组排序后所在位置
     15      *
     16      * @param array 待查找数组
     17      * @param lo   开始位置
     18      * @param hi  结束位置
     19      * @return  中轴所在位置
     20      */
     21     static int getMiddle(int []array,int lo,int hi) {
     22         //固定的切分方式
     23         int key=array[lo];
     24         while(lo<hi){
     25             //从后半部分向前扫描
     26             while(array[hi]>=key&&hi>lo){
     27                 hi--;
     28             }
     29             array[lo]=array[hi];
     30             //从前半部分向后扫描
     31             while(array[lo]<=key&&hi>lo){
     32                 lo++;
     33             }
     34             array[hi]=array[lo];
     35         }
     36         array[hi]=key;
     37         return hi;
     38     }
     39 
     40     /**
     41      *
     42      * @param numbers 带排序数组
     43      * @param low  开始位置
     44      * @param high 结束位置
     45      */
     46     static int[] quickSort(int[] numbers,int low,int high) {
     47         if(low < high) {
     48             int middle = getMiddle(numbers,low,high); //将numbers数组进行一分为二
     49             quickSort(numbers, low, middle-1);   //对低字段表进行递归排序
     50             quickSort(numbers, middle+1, high); //对高字段表进行递归排序
     51         }
     52         return numbers;
     53     }
     54 
     55     /**
     56      *
     57      * @param array 待排序的数组
     58      * @param lo 开始位置
     59      * @param hi 结束位置
     60      * @return 基准值所在位置
     61      */
     62     static int partition(int []array,int lo,int hi){
     63         //三数取中
     64         int mid=lo+(hi-lo)/2;
     65         if(array[mid]>array[hi]){
     66             swap(array[mid],array[hi]);
     67         }
     68         if(array[lo]>array[hi]){
     69             swap(array[lo],array[hi]);
     70         }
     71         if(array[mid]>array[lo]){
     72             swap(array[mid],array[lo]);
     73         }
     74         int key=array[lo];
     75 
     76         while(lo<hi){
     77             while(array[hi]>=key&&hi>lo){
     78                 hi--;
     79             }
     80             array[lo]=array[hi];
     81             while(array[lo]<=key&&hi>lo){
     82                 lo++;
     83             }
     84             array[hi]=array[lo];
     85         }
     86         array[hi]=key;
     87         return hi;
     88     }
     89 
     90     /**
     91      * 交换a,b的值
     92      * @param a 待交换a
     93      * @param b 待交换b
     94      */
     95     static void swap(int a,int b){
     96         int temp=a;
     97         a=b;
     98         b=temp;
     99     }
    100 
    101     /**
    102      *
    103      * @param array 带排序数组
    104      * @param lo  开始位置
    105      * @param hi 结束位置
    106      */
    107     static int[] sort(int[] array,int lo ,int hi){
    108         if(lo>=hi){
    109             return array;
    110         }
    111         int index=partition(array,lo,hi);
    112         sort(array,lo,index-1);
    113         sort(array,index+1,hi);
    114         return array;
    115     }
    116 
    117     /**
    118      * insertSort(arr,k) 递归实现插入排序
    119      * 找重复:insertSort(arr,k-1) 将k-1个排序后,把arr[k]插入到前面的数据中 --子问题
    120      * 找变化:变化的量应该作为参数 k。
    121      * 找边界:出口 终止的条件 k == 0
    122      */
    123     static int[] insertSort(int[] arr,int k){
    124         if (k == 0){
    125             return arr;
    126         }
    127         //对前k-1个元素排序
    128         insertSort(arr,k-1);
    129         //把k位置上的元素插入到前面的部分
    130         int x = arr[k];
    131         int index = k -1;
    132         while (index >= 0 && x <arr[index]){
    133             arr[index+1] = arr[index];
    134             index--;
    135         }
    136         arr[index+1] = x;
    137         return arr;
    138     }
    139 
    140     /**
    141      * 优化后的快速排序算法
    142      * @param array 待排序数组
    143      * @param lo 开始位置
    144      * @param hi 结束位置
    145      * @return 已排序的数组
    146      */
    147     static int[] quick(int []array ,int lo,int hi){
    148         if(hi-lo+1<10){
    149             return insertSort(array,array.length-1);
    150         }else{
    151             return sort(array,lo,hi);
    152         }
    153     }
    154 
    155     public static void main(String[] args) {
    156         int[] arr = new int[]{6,3,7,4,1,5,8,9,5,44,6,5};
    157         System.out.println(Arrays.toString(quickSort(arr,0,arr.length-1)));
    158         System.out.println(Arrays.toString(sort(arr,0,arr.length-1)));
    159         System.out.println(Arrays.toString(quick(arr,0,arr.length-1)));
    160     }
    161 }
  • 相关阅读:
    C++数据结构与算法(第4版) 完整版 高清pdf扫描版[193MB] 下载
    Streams AQ: enqueue blocked on low memory等待事件导致expdp导出缓慢问题
    Unity中使用 UGUI Toggle 和 Toggle Group 做单选列表
    unity UGUI动态滑动列表
    在Unity 中调用打印机来打印图片
    Unity3D中读取CSV文件
    unity 获取网络时间和本地时间
    win10右击无法新建文件,只能新建文件夹和快捷方式
    python笔记二、基础知识
    python笔记一、部分插件的作用及安装方法
  • 原文地址:https://www.cnblogs.com/zsh-blogs/p/10391541.html
Copyright © 2011-2022 走看看