前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >快速排序法及优化

快速排序法及优化

作者头像
Oceanlong
发布2018-07-03 12:55:38
5300
发布2018-07-03 12:55:38
举报

快速排序

快排是目前平均时间复杂度最小的排序法。体现了分治的思想。算法比较经典,因此在这里记录一下,加深印象。

快速排序中比较核心的是要寻找一个pivot值。即枢轴值。

核心思想就是,将需要排序的数列,以pivot值为中心,以大小左右分开。然后对左右两段数组再重新选取pivot值。以此递归。

下面我们来看一看代码。

public class QuickSortManager {
    int pivotloc;
    public void quickSort(int[] arr , int low , int high){
        if(low < high){
            pivotloc = partition(arr, low, high);
            quickSort(arr , low , pivotloc-1);
            quickSort(arr, pivotloc+1, high);   
        }
        
    }
    
    int partition(int[] arr  , int low , int high){
        int pivot = arr[low];
        while(low < high){
            while(low < high && arr[high] > pivot){
                high--;
            }
            swap(arr, low, high);
            while(low < high && arr[low] <= pivot){
                low++;
            }
            swap(arr, low, high);
        }
        
        return low;
    }
    
    void swap(int[] arr  , int a , int b){
        int temp = arr[a];
        arr[a] = arr[b];
        arr[b] = temp;
    }
}

代码总共30行左右,非常简单。在这个方法中,我们将数组arr的第一个值作为pivot。然后以low,high作为数组开头和结尾的索引。一旦发现arr[high]<pivot或是arr[low]>pivot,即交换它与pivot的值,然后更换遍历方向。最后当low>=high时即完成一次分治。并返回此时pivot的索引值。 然后通过递归,我们再对pivot左边和右边分别进行分治,即可完成排序。

举个小例子

3  5  4  1  2  6 // pivot = 3
2  5  4  1  3  6
2  3  4  1  5  6
2  1  4  3  5  6
2  1  3  4  5  6  // low = 2
第一次排序结束
确定了 pivot 左边的一定比 3 小 ,右边的一定比 3 大 

2 1 // pivot = 2
1 2 // low = 0

4 5 6 // pivot = 4 low = 0
 
排序完成 

优化

简化swap

我们在分治的时候发现,其实pivot的值每次交换并没有太大的意义。每次我们只是需要当前pivot的索引值和大小,pivot本身在一次分治时不会变化。所以我们考虑将其取出。每次交换时,直接覆盖掉,需要交换的值,最后再将pivot值赋进数组。

进入之后的代码入下:

    int partition(int[] arr  , int low , int high){
        int pivot = arr[low];
        while(low < high){
            while(low < high && arr[high] > pivot){
                high--;
                calculationCount++;
            }
            arr[low] = arr[high];
            //swap(arr, low, high);
            while(low < high && arr[low] <= pivot){
                low++;
                calculationCount++;
            }
            arr[high] = arr[low];
            //swap(arr, low, high);
            
        }
        arr[low] = pivot;
        
        return low;
    }
3  5  4  1  2  6 // pivot = 3
2  5  4  1  2  6
2  5  4  1  5  6
2  1  4  1  5  6
2  1  4  4  5  6 
2  1  3  4  5  6 // low = 2
第一次排序结束
确定了 pivot 左边的一定比 3 小 ,右边的一定比 3 大 

2 1 // pivot = 2
1 2 // low = 0

4 5 6 // pivot = 4 low = 0
 
排序完成 

经过这样的简化,我们可以减少大量的赋值操作。

优选pivot值

原先的算法中,我们pivot值在每次分治时,都取的是arr[low]。我们知道,快速排序法中,任意选取pivot值,都能完成排序,但这有可能导致最坏情况。即,选到最大值或最小值,将其余的数据全部分治到了一边。这相当于浪费了一次分治。只是确定了一个值的位置。

所以我们考虑选一个更好的pivot。

为了避免最坏情况的出现。我们每次分治时,不再选择arr[low]作为pivot。而是采用arr[low]、arr[high]、arr[middle]的中位值来作为pivot。这样就避免了会选择最大值或最小值作为pivot的情况。程序比较简单,就不赘述了。

多种排序

并不是所有情况下,快速排序法都是最优选择。由于分治的思想,我们可以在分治后,所需处理的数据较少时。采用插值排序进行排序。 插入排序代码如下:

    void insertSort(int arr[] , int low , int high){
         int i, j;
            int tmp;
            for (i = low + 1; i <= high; i++) { 
                if (arr[i] < arr[i - 1]) {
                    
                    tmp = arr[i]; 
                    for (j = i - 1 ; j >= low && arr[j] > tmp ; j--) {
                        arr[j + 1] = arr[j]; 
                    }
                    arr[j + 1] = tmp; 
                }
            }
    }

在quickSort中进行判断和调用:

    private static final int INSERT_SORT_LENGTH = 7;
    int pivotloc;
    public void quickSort(int[] arr , int low , int high){
        if(low < high){
            if(high - low  + 1 > INSERT_SORT_LENGTH){
                pivotloc = partition(arr, low, high);           
                quickSort(arr , low , pivotloc-1);
                quickSort(arr, pivotloc+1, high);   
            }else{
                insertSort(arr, low, high);
                
            }
            
        }
        
    }

以上。 笔者初学,如有谬误,不吝赐教。

本文参与 腾讯云自媒体分享计划,分享自作者个人站点/博客。
原始发表:2017.02.19 ,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 快速排序
  • 优化
    • 简化swap
      • 优选pivot值
        • 多种排序
        领券
        问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档