排序算法系列-交换之快速排序

前言

快速排序和冒泡排序都属于交换排序。首先一听这名字,快速排序,似乎它的时间复杂度相比于冒泡排序会简单很多,那到底它的程序设计有没有对得起他的名字呢,让我们一探究竟,哈哈。。。。

另外在一位大咖的博客中发现,很多软件公司的笔试面试,包括像腾讯,微软等知名IT公司都喜欢考这个,还有大大小的程序方面的考试如软考,考研中也常常出现快速排序的身影。看到这儿,有没有一种想立刻掌握它的冲动,反正我是有,,

言归正传,快速排序由C. A. R. Hoare在1962年提出。它的基本思想是:通过一趟排序将要排序的数据分割成独立的两部分,其中一部分的所有数据都比另外一部分的所有数据都要小,然后再按此方法对这两部分数据分别进行快速排序,整个排序过程可以递归进行,以此达到整个数据变成有序序列。


基本思想

1)先以第一个数组元素作为基准值,赋值给X,X=A[0],腾空A[0]
2)设置两个变量i、j,排序开始的时候:i=0,j=N-1;
3)从j开始向前搜索,即由后开始向前搜索(j--),找到第一个小于X的值A[j],将A[j]放到A[0]
4)从i开始向后搜索,即由前开始向后搜索(i++),找到第一个大于key的A[i],将A[i]A[j]
5)重复第3、4步,直到i=j; (3,4步中,没找到符合条件的值,即3中A[j]不小于key,4中A[i]不大于key的时候改变j、i的值,使得j=j-1,i=i+1,直至找到为止。最后i==j这一过程一定正好是i+或j-完成的时候,此时将X=A[0]放到i==j处,此时令循环结束)。


例证


代码

namespace QuickSort
{
  public class QuickSortClass
  {
    public int Division(List<int> list, int left, int right)
    {
      //首先挑选一个基准元素
      int X = list[left];
      while (left < right)
      {
        //从数组的右端开始向前找,一直找到比X小的数字为止(包括X同等数)
        while (left < right && list[right] >= X)
          right = right - 1;
        //最终找到了比X小的元素,要做的事情就是此元素放到基准值的位置
        list[left] = list[right];
        //从数组的左端开始向后找,一直找到比X大的数字为止(包括X同等数)
        while (left < right && list[left] <= X)
          left = left + 1;
        //最终找到了比X大的元素,要做的事情就是将此元素放到最后的位置
        list[right] = list[left];
      }
      //最后就是把X放到该left的位置
      list[left] = baseNum;
      //最终,我们发现left位置的左侧数值部分比left小,left位置右侧数值比left大
//至此,我们完成了第一篇排序
      return left;
    }
 
    public void QuickSort(List<int> list, int left, int right)
    {
      //左下标一定小于右下标,否则就超越了
      if (left < right)
      {
        //对数组进行分割,取出下次分割的基准标号
        int i = Division(list, left, right);
 
        //对“基准标号“左侧的一组数值进行递归的切割,以至于将这些数值完整的排序
        QuickSort(list, left, i - 1);
 
        //对“基准标号“右侧的一组数值进行递归的切割,以至于将这些数值完整的排序
        QuickSort(list, i + 1, right);
      }
    }
  }
}


有没有优于冒泡排序?

相比冒泡排序,每次交换是跳跃式的。每次排序的时候设置一个基准点,将小于等于基准点的数全部放到基准点的左边,将大于等于基准点的数全部放到基准点的右边。这样在每次交换的时候就不会像冒泡排序一样每次只能在相邻的数之间进行交换,交换的距离就大的多了。因此总的比较和交换次数就少了,速度自然就提高了。当然在最坏的情况下(基准值选到了最大值或最小值),仍可能是相邻的两个数进行了交换。因此快速排序的最差时间复杂度和冒泡排序是一样的都是O(N2),它的平均时间复杂度为O(NlogN)。所以快速排序肯定是优于冒泡排序的,而且快速排序相对于其他排序方法,时间复杂度也是比较小的。


分析

1.当分区选取的基准元素为待排序元素中的最大或最小值时,为最坏的情况,时间复杂度和直接插入排序的一样,移动次数达到最大值

                  Cmax = 1+2+...+(n-1) = n*(n-1)/2 = O(n2) 此时最好时间复杂为O(n2

2.当分区选取的基准元素为待排序元素中的"中值",为最好的情况,时间复杂度为O(nlog2n)。

3.快速排序是不稳定排序:当待排序元素类似[6,1,3,7,3]且基准元素为6时,经过分区,形成[1,3,3,6,7],两个3的相对位置发生了改变,所是快速排序是一种不稳定排序。

 

结语

本文的例子是以序列中的第一个数为基准数,快速排序的基本思想是从某一个记录中任取一个键值作为基准数,通常取得是第一个,最后一个或者中间的一个作为基准数。

评论 13
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

木子松的猫

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值