zoukankan      html  css  js  c++  java
  • [数据结构]快速排序

    算法思想

      快速排序是对冒泡排序的一种改进。其基本思想是基于分治法的;在待排序表L[1….n]中任取一个元素pivot作为基准,通过一趟排序将待排序表划分为独立的两部分L[1…k-1]和L[k+1…n],使得L[1….k1]中所有元素小于pivot,L[k+1….n]中所有元素大于或等于pivot,则pivot放在了其最终位置L(k)上,这个过程称作一趟快速排序。而后分别递归地对两个子表重复上述过程,直至每部分内只有一个元素或空为止,即所有元素放在了其最终位置上。
      首先假设划分算法已知,记为Partition(),返回的是上述中的k,注意到L(k)已经在最终的位置,所以可以先对表进行划分,而后对两个表调用同样的排序操作。因此可以递归地调用快速排序算法进行排序,具体的程序结构如下介绍。

    算法代码

    void QuickSort(ElemTpye A[],int low,int high){
        if(low<high){
        //Partition()就是划分操作,将表A[low...high]划分为满足上述条件的两个子表
        int pivotpos=Partition(A,low,high);//划分
        QuickSort(A,low,pivotpos-1);//依次对两个子表进行递归排序
        QuickSort(A,pivotpos+1,high);
        }
    }

      从上面的代码也不难看出快速排序算法的关键在于划分操作,同时快速排序算法的性能也主要取决于划分操作的好坏。假设每次总是以当前表中第一个元素作为枢轴值(基准)对表进行划分,则必须将表中比枢轴值大的元素向右移动,比枢轴值小的元素向左移动,使得每一趟Partition()操作后,表中的元素被枢轴值一分为二。
      

    int Partition(Elemtype A[],int low,int high){
        while (low<high)
        {
            while (low<high && A[low] < A[high])
                --high;
                std::swap(A[low], A[high]);
                //将右侧比A[low]小的数交换
            while (low < high&&A[low] < A[high])
                ++low;
                std::swap(A[low], A[high]);
                //将左侧比A[low]小的数交换
        }
        return low;//最后A[low]的左侧keys都比它小,右侧keys都比它大
    }

    算法复杂度

      空间复杂度:由于快速排序是递归的,需要借助一个递归工作栈来保存每一层递归调用的必要信息,其容量应该与递归调用的最大深度一致。最好情况下为log₂(n+1);最坏情况下,因为要进行n-1次调用,所以栈的深度为O(n);平均情况下,栈的深度为O(log₂n)。因而空间复杂度在最坏的情况下为O(n),平均情况下为O(log₂n)
      时间复杂度:快速排序的运行时间与划分是否堆成有关,而后者又与具体使用的划分算法有关,快速排序的最坏情况下发生在两个区域分别包含n-1个元素和0哥元素时,这种最大程度的不对称性若发生在每一层递归上,即对应于初始排序表基本有序或者基本逆序时,就得到最坏情况下的时间复杂度为O(n²)(改进后为O(nlog₂n))。
      稳定性:在划分算法中,若右端区间存在两个关键字相同,且均小玉基准值的记录,则在交换到左端区间后,它们的相对位置会发生变化,即快速排序是一个不稳定的排序方法。例如表L={3,2,2},经过一趟排序后,L={2,2,3},最终序列也是{2,2,3},相对次序已经发生了改变。

    算法效率的改进

      有很多种方法可以提高算法的效率,一种方法是递归过程中划分得到的子序列的规模较小时不要再继续递归调用快速排序,可以直接采用直接插入排序算法进行后续的排序工作。另一种方法就是尽量选择一个可以将数据中分的枢轴值元素。如从序列的头尾以及中间选择三个元素,再取这三个元素的中间值作为最终的枢轴元素;或者随机从当前表中选取枢轴元素,这样做使得最坏的情况在实际排序中几乎不会发生。
      在最理想的情况下,也就是Partition()可能做到最平衡的划分中,得到的两个子问题的大校都不可能大于n/2,在这种情况下,快速排序的运行速度将大大提升,此时,时间复杂度为O(nlog₂n)。好在快速排序平均情况下运行时间与其最佳情况下的运行时间很接近,而不是接近其最坏情况下的运行时间。快速排序是所有内部排序算法中平均性能最优的排序算法。

    https://github.com/li-zheng-hao
  • 相关阅读:
    HelloWorld
    CSS盒子模型
    CSS选择器
    Win右键管理员权限的获取
    本地存储
    python模块以及导入出现ImportError: No module named 'xxx'问题
    python pexpect 学习与探索
    VI查找与替换
    python 中__name__ = '__main__' 的作用
    python 脚本传递参数
  • 原文地址:https://www.cnblogs.com/lizhenghao126/p/11053728.html
Copyright © 2011-2022 走看看