zoukankan      html  css  js  c++  java
  • 快速排序

            快排和归并排序是比较经常见到的两种排序算法,下面我将用我自己的话来讲解快速排序和归并的知识点。

        (一)快速排序

       首先要明白,快速排序是基于冒泡排序的基础上做得改进,冒泡排序的交换次数太多了,快速排序就是为了来减少交换次数的,那接下来就好好的分析一下整个过程。

          快速排序定义:快排是利用分治的思想,如果要排序的数组中下标是从p到r之间的一组数据,我们选择p到r之间的任意一个数据作为分区点(pivot(分区点)),我们遍历p到r之间的数据,将小于pivot放到左边,将大于pivot放到右边,将pivot放到中间,这样经过这一步骤之后,数组p到r之间的数据分成了三部分。前面p到q-1都是小于pivot的,中间pivot, 后面的q+1到r之间都是大于pivot的。

         

      根据分治的思想,我们可以想到用递归来实现快速排序;

         递归的跳出条件就是:当p和r相等的时候,待排序的数组里面只剩下一个元素了。

         递推公式就是:f(x)=f(p...q-1)+f(q+1,r)  。

       大概的递归伪代码如下

    quickSort(arr,p,r)
    {
    if(p<r)
        { q
    =partion(arr,p,r) quickSort(arr,p,q-1) quickSort(arr,q+1,r)
        }   }

      接下来最关键的就是这分区函数的实现;

        分区函数的实现,有很多种方式。下面这个是我认为最好理解的。

     我们先选取最右边的作为基准参数,这个i和j的作用大概如下:把数组arr分割成[p到i-1]是小于pivot,类似于选择排序。我们假定arr[i]代码的就是小于基准的数据。

           static int Partion(ref List<int> intList,int l,int r)
            {
                var arr = intList.ToArray();
                var pivot = arr[r];
                int j = l;
                int i = 0;
                //
                for(j = l; j <=r; j++)
                {
                    if (arr[j] <= pivot)
                    {
                        var temp = arr[j];
                        arr[j] = arr[i];
                        arr[i] = temp;
                        if(arr[j]!=pivot)
                        i++;
                    }
                }
                intList = arr.ToList();
                return i;
            }

     (二)时间复杂度和空间复杂度分析

      快速排序是原地,不稳定排序算法。原地排序算法,上面已经做到了。

           空间复杂度为o(1)。不稳定的排序算法例如:6,8,7,6,4,9,5  分区完了之后,两个6的前后顺序会改变。

      那么时间复杂度怎么分析:

           这里主要是用到了递归,和第一次分区的时间复杂度为o(n);

      最好的情况下,我们刚刚好平均分成了两份,如果我们对n个元素进行快速排序所需要的时间T(n),那么时间复杂度的公式如下:

          T(1)=1;

          T(n)=2(T/n)+n;

       通过这个公式,如何来求解T(n)呢,还不够直观,那我们再进一步分解计算过程。

         T(n)=2*T(n/2)+n

          =2*(2*T(n/4)+n/2)+N=4*T(n/4)+2*n

               =4*(2*T(n/8)+n/4)+2*n

          =以此类推... 得到时间复杂度为o(nlogn)。

      最坏情况下,就是o(n²)。

       思考题:为什么快速排序需要定义两个变量(i和j)

        哪里都有讲快速排序的,啥的,我也看了很多篇别人写的文章。但是好多文章里面都是直接就说拿两个i,j变量,就开始比较了。

        快速排序,简单的说就是,先确定一个基准,然后就把比这个基准大的放到一边,比这个基准小的放到一边。放到一边的时候,是不管它是有序还是无序的。接下来在把之前的操作重复一下,其实就是一个递归的过程。

        为什么要定义两个变量进行快速排序呢?

        其实是这样的,快速排序,为啥叫快速排序呢,快在哪里,快在它减少了交换次数,还有一个原因就是快速排序是在快速排序是不用新开内存的,可以减少内存的使用。它就是在原地完成排序的。可能这样讲,你还是不明白,那我们来进行假设,如果只定义一个变量i的话呢,然后进行比较大小,那不就成了冒泡排序了吗。刚刚还说了快速排序是在原地完成排序的,不需要另外开辟空间资源的。你单独定义一个变量显然是不能实现的。

       为啥要定义如果基准数量在这边,那么就要先从另外一边开始扫描呢。

       先想想如果是放在同一边的话,那不就成了个冒泡排序吗。

       

  • 相关阅读:
    STL中set底层实现方式? 为什么不用hash?
    main 主函数执行完毕后,是否可能会再执行一段代码?(转载)
    计算机网络(转载)
    2014! 的末尾有多少个0
    最常见的http错误
    内存分配(转载)
    delphi中指针操作符^的使用
    虚拟方法virtual的用法
    调用父类方法
    指针
  • 原文地址:https://www.cnblogs.com/gdouzz/p/6731153.html
Copyright © 2011-2022 走看看