• 排序算法之快速排序


     今天开始总结排序算法,面试最常考到的应该就是快速排序,也叫做分划交换排序。

           快速排序最明显的特征就是在待排序序列中选择一个分划元素,也叫做主元(pivot),通过一趟排序就会将排序的数据分割成两个部分,主元的左边都比主元小,主元的右边比主元大,再将分成的两边子序列作相同的处理,当所有的子序列为空或者只有一个元素时被认为有序,完成排序。

          网上的快速排序算法一般有两种,一种是两头交换法,另一种是挖坑填坑法。

          我们先来看两头交换法,以{6,5,9,4,2,7,3,}为例,我们一般把左边第一个元素6作为主元,使用两个下标变量i和j分别指向位置一的元素6和和最后位置3,先移动j。i自左往右移动,将主元与下标为i的元素比较,如果主元大于i所指示的元素,则i右移一位 ,直至遇到一个元素不小于主元的停止右移,此时指针i指向9。j自右往左移动,同样遇到一个元素不大于主元时,停止左移此时指针指向3。然后交换i和j所指示的元素,此时序列交换完成为{6,5,3,4,2,7,9}。下一步继续按照同样的方式移动指针i和j,知道i>=j时结束,最后将主元6和位于i的元素交换,结束第一次分划操作。序列为{2,5,3,4,6,7,9}。继续对主元6两边的子序列作相同的处理。

       我们看一下代码。

    public class quickSort {
       public static void quicksort(int arrays[],int left,int right) {
           int x=arrays[left];//主元设为第一个元素
           int i=left;
           int j=right;
           if(left>=right) {
               return; 
           }
           while(i!=j) {
    //移动指针j寻找不大于主元的元素
    while(i<j&&arrays[j]>=x) { j--; } //移动指针i寻找不大于主元的元素 while(i<j&&arrays[i]<=x) { i++; }
    //交换i和j所指示元素
    if(i<j) { int temp=arrays[i]; arrays[i]=arrays[j]; arrays[j]=temp; } }
    //最后将主元和位于i的元素交换,完成一次划分。 arrays[left]
    =arrays[i]; arrays[i]=x; quicksort(arrays,left,i-1); quicksort(arrays,i+1,right); } public static void main(String args[]) { int nums[]= {6,5,9,4,2,7,3}; quicksort(nums,0,6); for(int i=0;i<nums.length-1;i++) { System.out.print(nums[i]+" "); } } }

     第二种挖坑填坑法也不难理解,还是以{6,5,9,4,2,7,3}为例,我们现在以第一个元素为坑也是主元,同样两个指针i和j分别指向6和3,先左移j,找到一个元素不大于主元,此时j指向3,在此位置挖一个坑,把上一个坑用此时j找到的元素填了,此时序列为{3,5,9,4,2,7,3}.然后右移i,直至找到一个元素不小于主元,此时i指向9,在这里挖一个坑,同样用i指向的元素把上一个坑满填上,此时序列为{3,5,9,4,2,7,9}继续重复移动j和i直至i>=j,最后将主元6和位于i的元素交换,结束第一次分划操作。此时序列为{3,5,2,4,6,7,9}。继续对主元6两边的子序列作相同的处理。

    我们看一下代码:

    public class quickSort {
       public static void quicksort(int arrays[],int left,int right) {
           int x=arrays[left];将第一个元素作为主元,同时也是第一个坑
           int i=left;
           int j=right;
           if(left>=right) {
               return; 
           }   
           while(i!=j) {
    // 左移j,找到一个不大于主元的元素
    while(i<j&&arrays[j]>=x) { j--; }
    //用j指向的元素把坑填了,同时在这里挖一个坑。
    if(i<j) { arrays[i]=arrays[j]; }
    //右移i,找到一个元素不小于主元
    while(i<j&&arrays[i]<=x) { i++; }
    //用i指向的元素把坑填了,同时在这里挖一个坑。
    if(i<j) { arrays[j]=arrays[i]; } }
    //最后一个坑用主元填了。 arrays[i]
    =x; quicksort(arrays,left,i-1); quicksort(arrays,i+1,right); } public static void main(String args[]) { int nums[]= {6,5,9,4,2,7,3}; quicksort(nums,0,6); for(int i=0;i<nums.length-1;i++) { System.out.print(nums[i]+" "); } } }

     我们现在看一下快速排序的时间复杂度。如果每次分划操作,左右两个子序列长度基本相等,则效率最高,其最好的时间复杂度为O(nlogn)。反之如果每次分划操作产生的子序列其中一个为空,则快排效率最低,其最坏情况为O(n2),这种情况发生在原始正向有序和反向有序。平均时间复杂度为O(nlogn)。

  • 相关阅读:
    [笔记]: 树链剖分 2017-06-05 16:57 35人阅读 评论(0) 收藏
    [笔记]: 最小生成树Kruska 2017-06-05 16:52 34人阅读 评论(0) 收藏
    [笔记]: 并查集 2017-06-05 16:49 58人阅读 评论(0) 收藏
    [bzoj2144]: 跳跳棋 2017-06-02 15:53 42人阅读 评论(0) 收藏
    [noip2013] 货车运输(最大生成树+并查集+LCA) 2017-06-02 15:18 56人阅读 评论(0) 收藏
    [练习] LCA练习1(最基础) 2017-06-02 11:54 39人阅读 评论(0) 收藏
    [笔记]: RMQ算法(区间查询) 2017-06-01 18:06 44人阅读 评论(0) 收藏
    [笔记]: LCA最近公共祖先 2017-06-01 11:38 38人阅读 评论(0) 收藏
    [hdu&poj&洛谷] 经典线段树练习题 2017-06-01 08:10 56人阅读 评论(0) 收藏
    保留X位小数(Double) swift
  • 原文地址:https://www.cnblogs.com/fankailei/p/9769519.html
Copyright © 2020-2023  润新知