浅谈快速排序

转载请注明出处:http://blog.csdn.net/g96968586/article/details/24185967

谈起快速排序,大家都不陌生了,学过数据结构的人(除了那些逃课或者上课睡觉的人)都知道它,如果还有人现在不能马上手写出快速排序的算法,那就赶紧过来跟我一起重温一下快速排序的精髓吧!面试可是经常会被问起或当场手写代码的哦!

快速排序最早由图灵奖获得者Tony Hoare设计出来的,该算法被列为20世纪十大算法之一。

快速排序的基本思想是:通过一趟排序将待排记录分割成独立的两部分,其中一部分记录的关键字均比另一部分记录的关键字小,则可分别对这两部分记录继续进行排序,以达到整个序列有序的目的。

我们现在直接上代码分析(C语言):

#define MAXSIZE 10
#define STATUS bool
//声明结构体
typedef struct{
int r[MAXSIZE];
int length;
}SqList;




//交换函数,下面会用到,在这里先定义
/*交换L中数组r的下标为i和j的值*/
void swap(SqList *L,int i,int j){
int temp = L->r[i];
L->r[i] = L->r[j];
L->r[j] = temp;
}

/* 对顺序表L作快速排序 */
void QuickSort ( SqList *L)
{
    Qsort(L,1,L->length);
}

由于需要递归调用,我们外封装了 一个函数,现在来看看Qsort的具体实现。


/* 对顺序表L中的子序列L->r[low] ~ L->r[high]作快速排序,low为当前待排序的序列最小下标值,high为当前待排序的序列最大下标值 */
void Qsort ( SqList *L,int low, int high)
{
  int pivot;  /* 枢轴值 */
  if(low < high)
 {
     pivot = Partition (L,low,high);  /* 将L->[low...high]一分为二,算出枢轴值pivot */
     Qsort(L,low,pivot-1);  /* 对低子表递归操作 */
     Qsort(L,pivot+1,high);  /* 对高子表递归操作 */
}

这一段的核心是“pivot = Partition (L,low,high);” ,假设我们要对数组{50,10,90,30,70,40,80,60,20}进行排序,Partition函数要做的就是先选取当中的一个关键字,比如选择第一个关键字50,然后想尽办法将它放到一个位置,使得它左边的值都比它小,右边的值都比它大,我们将这样的关键字成为枢轴(pivot)。

在经过Partition(L,1,9)的执行后,数组就变成{20,10,40,30,50,70,80,60,90},并返回5给pivot,数字5表明50放置在数组下标为5的位置,这时候你是否发现,50左边的值均比它小,右边的值都比它大。后面的递归调用"Qsort(L,1,5-1);"和"Qsort(L,5+1,9)"语句,其实就是在对{20,10,40,30}和{70,80,60,90}进行同样的Partition操作,直到顺序全部正确为止。


下面就来看看核心函数Partition的实现。

/* 交换顺序表L中子表的记录,使枢轴记录到位,并返回其所在位置,此时在它之前(后)的记录均不大(小)于它 */

int Partition ( SqList *L,int low,int high)
{
       int pivotkey;
       pivotkey = L->r[low];   /* 用子表的 第一个记录作枢轴记录 */
       while(low < high)   /* 从表的两端交替向中间扫描 */
       {
            while(low < high && L->r[high] >= pivotkey)    high - - ;
            swap(L,low,high);    /* 将比枢轴记录小的记录交换到低端 */
            while(low < high && L->r[low] <= pivotkey )   low ++;
            swap(L,low,high);  /* 将比枢轴记录大的记录交换到高端 */
        }
          return low;   /*  返回枢轴所在位置 */
}

我们照着代码来分析:



可以看出Partition函数,其实就是将选取的pivotkey不断交换,将比它小的换到左边,比它大的换到右边,它也在交换中不断更改自己的位置,直到完全满足这个要求为止。

我在这里就不分析快排的时间和空间复杂度了,那些数字符号不想打,哈哈。快速排序的时间复杂度是O(nlogn),空间复杂度为O(logn)。

最后注明一下,快速排序是一种不稳定的排序方法,因为它的关键字比较和交换是跳跃进行的。如果有人不清楚什么是稳定和不稳定算法,百度一下就知道啦!我在这里就不说了,在接下来一篇博客,我将带领大家一起去优化我们当前说的快速排序。是的,兜了大半天,我们当前的快速排序算法还不是最好的,还有很多地方可以优化呢~哈哈

附上Java语言编写的快速排序算法,比我们用c语言实现的思路要更加清晰,大家自行分析吧!

public static void quickSort(int a[], int start, int end)
{       inti,j;
         i= start;
         j= end;
         if((a==null)||(a.length==0))
             return;
         while(i<j){
             while(i<j&&a[i]<=a[j]){    //以数组start下标的数据为key,右侧扫描
                 j--;
             }
             if(i<j){                  //右侧扫描,找出第一个比key小的,交换位置
                 int temp = a[i];
                 a[i]= a[j];
                 a[j]= temp;
             }
              while(i<j&&a[i]<a[j]){   //左侧扫描(此时a[j]中存储着key值)
                 i++;
               }
             if(i<j){                //找出第一个比key大的,交换位置
                 int temp = a[i];
                 a[i]= a[j];
                 a[j]= temp;
             }
        }
        if(i-start>1){
             //递归调用,把key前面的完成排序
            quickSort(a,start,i-1);
        }
        if(end-i>1){
            quickSort(a,i+1,end);   //递归调用,把key后面的完成排序
        }
}

注:参考书籍《大话数据结构》,文中的图片均出自该书。
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值