算法之快速排序算法的实现

分手后的思念是犯贱 2022-03-01 15:06 230阅读 0赞

快速排序这个算法的鼎鼎大名相信大家都有多耳闻,这个算法被称为20世纪对世界影响最大的之一,它之所以这么出名,可能就是因为像它名字一样,比较快吧。
快速排序是从当前数组中选择一个数为基点,之后根据这个数的大小进行判断比这个数大还是比这个数小,下面我们用三种方法来解决这个快速排序算法。
通过一趟排序将要排序的数据分割成独立的两部分,其中一部分的所有数据都比另外一部分的所有数据都要小,然后再按此方法对这两部分数据分别进行快速排序,整个排序过程可以递归进行,以此达到整个数据变成有序序列。
时间复杂度是O (nlogn);

  1. 基本排序
    看图我们可以知道,最前边一个元素为v,索引定义为l,然后进行比较v和后边元素e的大小,如果比v大就放到arr[J+1…i-1]这个数组中,如果比v小就放到arr[l+1…J]这个数组中,这样的话中间值就作为J这个索引。然后进行递归处理两部分元素。
    在这里插入图片描述代码如下:

    public class quickSort1 {

    1. public static void main(String[] args) {
    2. int n = 1000;
    3. //产生n个[0-n]范围的数组
    4. Comparable[] arr = SortTestHelper.generateRandomArray(n,0,n);
    5. long startTime = System.currentTimeMillis();
    6. quickSort(arr,arr.length);
    7. long endTime = System.currentTimeMillis();
    8. System.out.println("基本排序:"+(endTime-startTime));
    9. }
    10. public static void quickSort(Comparable[] arr , int n){
    11. quickSort(arr, 0 , n-1);
    12. }
    13. // 对arr[l...r]部分进行partition操作
    14. // 返回p, 使得arr[l...p-1] < arr[p] ; arr[p+1...r] > arr[p]
    15. public static int partition(Comparable[] arr , int l,int r){
    16. //针对近乎有序的数组,如果不做这个解决就会出现n^2的复杂度
    17. swap(arr,l,(int)(Math.random()*(r-l+1)+l));
    18. Comparable v = arr[l];
    19. int j = l; // arr[l+1...j] < v ; arr[j+1...i) > v
    20. for( int i = l + 1 ; i <= r ; i ++ )
    21. if( arr[i].compareTo(v) < 0 ){
    22. //j标记着中间的位置,如果arr[i]比v小的话,就把这个小值放到j前边,
    23. // 跟j交换位置,如果比它大,就不需要变化
    24. // 如果元素e和v相等的话就会出现O(n^2)的现象
    25. j ++;
    26. swap(arr, j, i);
    27. }
    28. //把v和j交换位置,这样v就到中间大的位置
    29. swap(arr, l, j);
    30. return j;
    31. }
    32. private static void swap(Object[] arr, int i, int j) {
    33. Object t = arr[i];
    34. arr[i] = arr[j];
    35. arr[j] = t;
    36. }
    37. public static void quickSort(Comparable[] arr, int l , int r){
    38. //如果值比较少的话就用插入排序,处理少量数据插入排序更快一些
    39. if ( r - l <= 15){
    40. insertSort(arr,l,r);
    41. return;
    42. }
    43. //进行快速排序逻辑运算,比v大就到右边,比v小就到左边,最后中间位置和v交换位置
    44. int p = partition(arr, l , r);
    45. quickSort(arr, 0 , p-1);
    46. quickSort(arr, p+1 , r);
    47. }
    48. public static void insertSort(Comparable[] arr,int l,int r){
    49. for (int i=l;i<r+1;i++){
    50. Integer e = Integer.parseInt(String.valueOf(arr[i]));
    51. int j;
    52. for (j = i;j>l;j--){
    53. if (Integer.parseInt(String.valueOf(arr[j-1]))>Integer.parseInt(String.valueOf(e))){
    54. arr[j] = arr[j-1];
    55. }
    56. }
    57. arr[j] = e;
    58. }
    59. }

    }

  2. 双路排序
    如果基本排序处理大量的重复值的时候就会出现两部分的值差距很多,这样就会导致时间复杂度降低,我们就出现两个索引,一个i,一个J,i向右走,如果i的值大于v并且J的值小于v,则让i和J交换。最后让l和中间值J交换。
    在这里插入图片描述代码如下

    public class quickSort2 {

    1. public static void main(String[] args) {
    2. int n = 1000;
    3. Comparable[] arr = SortTestHelper.generateRandomArray(n,0,n);
    4. long startTime = System.currentTimeMillis();
    5. quickSort2(arr,arr.length);
    6. long endTime = System.currentTimeMillis();
    7. System.out.println("双路排序:"+(endTime-startTime)+"ms");
    8. }
    9. public static void quickSort2(Comparable[] arr , int n){
    10. quickSort2(arr, 0 , n-1);
    11. }
    12. //返回p,使得arr[l..p-1]<arr[p] ; arr[p+1..r]>arr[p]
    13. public static int partition(Comparable[] arr, int l , int r){
    14. //针对近乎有序的数组,如果不做这个解决就会出现n^2的复杂度
    15. swap(arr,l,(int)(Math.random()*(r-l+1)+l));
    16. Comparable v = arr[l];
    17. int i=l+1,j=r;
    18. while (true){
    19. //i往后走,遇到比v小的就跳过
    20. while (arr[i].compareTo(v)<0 && i < r)
    21. i++;
    22. //j往前走,遇到比v大的就跳过
    23. while (arr[j].compareTo(v)>0 && j > l+1)
    24. j--;
    25. //如果遍历完就break掉
    26. if (i > j)
    27. break;
    28. //这个就是当i的元素比v大,j的比v小进行交换
    29. swap(arr,i,j);
    30. i++;
    31. j--;
    32. }
    33. //把开始的值和中间值交换
    34. swap(arr,l,j);
    35. return j;
    36. }
  1. private static void swap(Object[] arr, int i, int j) {
  2. Object t = arr[i];
  3. arr[i] = arr[j];
  4. arr[j] = t;
  5. }
  6. public static void quickSort2(Comparable[] arr, int l , int r){
  7. //判断是否到中间那个位置
  8. if ( r - l <= 15){
  9. insertSort(arr,l,r);
  10. return;
  11. }
  12. //进行快速排序逻辑运算,比v大就到右边,比v小就到左边,最后中间位置和v交换位置
  13. int p = partition(arr, l , r);
  14. quickSort2(arr, 0 , p-1);
  15. quickSort2(arr, p+1 , r);
  16. }
  17. public static void insertSort(Comparable[] arr,int l,int r){
  18. for (int i=l;i<r+1;i++){
  19. Integer e = Integer.parseInt(String.valueOf(arr[i]));
  20. int j;
  21. for (j = i;j>l;j--){
  22. if (Integer.parseInt(String.valueOf(arr[j-1]))>Integer.parseInt(String.valueOf(e))){
  23. arr[j] = arr[j-1];
  24. }
  25. }
  26. arr[j] = e;
  27. }
  28. }
  29. }
  1. 三路排序
    在排序中还有一个更经典的处理重复值较多的方法,那就是分为三部分,一部分是大于v的,一部分是大于v的,还有一部分就是等于v的,那么等于v的就不需要进行任何操作。
    在这里插入图片描述代码如下:

    public class quickSort3 {

    1. public static void main(String[] args) {
    2. int n = 1000;
    3. Comparable[] arr = SortTestHelper.generateRandomArray(n,0,n);
    4. long startTime = System.currentTimeMillis();
    5. quickSort3(arr,arr.length);
    6. long endTime = System.currentTimeMillis();
    7. System.out.println("三路排序:"+(endTime-startTime));
    8. }
    9. public static void quickSort3(Comparable[] arr , int n){
    10. quickSort3(arr, 0 , n-1);
    11. }
  1. private static void swap(Object[] arr, int i, int j) {
  2. Object t = arr[i];
  3. arr[i] = arr[j];
  4. arr[j] = t;
  5. }
  6. //针对相同的数较多的
  7. //三路快速排序处理arr[l..r]
  8. //分为<v;=v;>v三部分进行排序
  9. //之后递归会<v;>v两部分进行排序
  10. public static void quickSort3(Comparable[] arr, int l , int r){
  11. //判断是否到中间那个位置
  12. if ( r - l <= 15){
  13. insertSort(arr,l,r);
  14. return;
  15. }
  16. //针对近乎有序的数组,如果不做这个解决就会出现n^2的复杂度
  17. swap(arr,l,(int)(Math.random()*(r-l+1)+l));
  18. Comparable v = arr[l];
  19. int lt = l; //arr[l+1..lt]<v
  20. int gt = r+1;//arr[gt..r]>v
  21. int i = l+1;//arr[lt+1..i]=v
  22. //当i<gt就是还没有碰上的时候
  23. while (i<gt){
  24. //当i位置的值小于v的时候
  25. if (arr[i].compareTo(v)<0){
  26. //让i位置的值放到<v的区域中
  27. swap(arr,i,lt+1);
  28. lt++;
  29. i++;
  30. } else if (arr[i].compareTo(v)>0){
  31. swap(arr,i,gt-1);
  32. gt--;
  33. i++;
  34. } else {
  35. i++;
  36. }
  37. }
  38. //把v和中间的元素交换
  39. swap(arr,l,lt-1);
  40. //进行快速排序逻辑运算,比v大就到右边,比v小就到左边,最后中间位置和v交换位置
  41. quickSort3(arr,l,lt-1);
  42. quickSort3(arr,gt,r);
  43. }
  44. public static void insertSort(Comparable[] arr,int l,int r){
  45. for (int i=l;i<r+1;i++){
  46. Integer e = Integer.parseInt(String.valueOf(arr[i]));
  47. int j;
  48. for (j = i;j>l;j--){
  49. if (Integer.parseInt(String.valueOf(arr[j-1]))>Integer.parseInt(String.valueOf(e))){
  50. arr[j] = arr[j-1];
  51. }
  52. }
  53. arr[j] = e;
  54. }
  55. }
  56. }

大家可以在自己的电脑上运行一下这些代码测试一下,就可以比较出来这个运行时间的差距。祝大家学习算法成功。

发表评论

表情:
评论列表 (有 0 条评论,230人围观)

还没有评论,来说两句吧...

相关阅读

    相关 排序算法快速排序

    > 快速排序。 > 从数组中取出一个基准数,遍历数组中的每个元素,与基准数比较大小,将小于基准数的元素放在其左侧,大于基准数的元素放在其右侧, >

    相关 排序算法快速排序

    同样的先上这张图  ![Center][] 下面分析交换排序之快速排序: 快速排序的思想是先选择一个基准元素(一般取第一个元素),然后对剩下的元素作两端遍历,左边找

    相关 排序算法快速排序

    快速排序的基本思想是:通过一趟排序将要排序的[数据分割][Link 1]成独立的两部分,其中一部分的所有数据都比另外一部分的所有数据都要小,然后再按此方法对这两部分数据分别进行

    相关 排序算法快速排序(Java实现

    快速排序是一种交换排序,这种排序的思想是把数组通过不断的递归,把数组中的数据分成两部分,前半部分小于某一个数,后半部分大于这个数,接着再对这两部分分别使用这种思想进行交换排序。

    相关 排序算法快速排序

    快速排序是一种高效的排序算法,它采用分而治之的思想,把大的拆分成小的,小的再拆分为更小的。 其原理是:对于给定的数组,通过一趟排序之后,将原序列分为两部分,其中前一部分的所