10.1快速排序

快速排序

算法概述
  • 分而治之
void Quicksort( ElementType A[], int N )
{
    if( N<2 ) return;
    pivot = 从A[]中选一个主元;
    将S = { A[]\pivot } 分成2个独立子集:
    	A1={ a∈S | a<=pivot } 和
        A2={ a∈S | a<=pivot };
    A[] = Quicksort(A1,N1)∪
    			   {pivot}∪
          Quicksort{A2,N2};
}
  • 什么是快速排序算法的最好情况?
    • 每次正好中分-> T(N) = O(NlogN)
选主元
  • 取头、中、尾的中位数
ElementType Median3(ElementType A[], int Left, int Right )
{
    int Center = ( Left + Right ) / 2;
    if( A[Left] > A[Center] )
        Swap(&A[Left], &A[Center]);
    if( A[Left] > A[Right] )
        Swap(&A[Left], &A[Right]);
    if( A[Center] > A[Right] )
        Swap(&A[Center], &A[Right]);
    // left <= center <= right
    Swap(&A[Center], &A[Right-1]);
    //只需考虑left+1到right-2
    return A[Right-1];
}
子集划分
  • 如果有元素正好等于pivot怎么办?
    • 停下来交换√
    • 不理它,继续移动指针->会导致主元一直停在一侧,时间复杂度为nlogn
小规模数据的处理
  • 快速排序的问题
    • 用递归
    • 小规模(N不到100)可能不如插入排序快
  • 解决方案
    • 当递归的数据规模充分小,则停止递归,直接调用简单排序(如插入排序)
    • 在程序中定义一个Cutoff的阈值
算法实现
void Quicksort( ElementType A[], int Left, int Right )
{
    if( Cutoff <= Right-Left ) {
        Pivot = Median3( A, Left, Right );
        i = Left; j = Right-1;
        for(;;) {
            while( A[++1] < Pivot );
            while( A[--j] < Pivot );
            if( i<j )
                Swap( &A[i],&A[j]);
            else
                break;
        }
        Swap( &A[i], &A[Right-1]);
        Quicksort(A, Left, i-1);
        Quicksort(A, i+1, Right);
    }
    else
        Insertion_Sort( A+Left, Right-Left+1 );
}
void Quick_sort( ElementType A[], int N)
{
    Quicksort( A, 0, N-1);
}
  • 快速排序不是稳定的算法
/* 快速排序 - 直接调用库函数 */
 
#include <stdlib.h>
 
/*---------------简单整数排序--------------------*/
int compare(const void *a, const void *b)
{ /* 比较两整数。非降序排列 */
    return (*(int*)a - *(int*)b);
}
/* 调用接口 */ 
qsort(A, N, sizeof(int), compare);
/*---------------简单整数排序--------------------*/
 
 
/*--------------- 一般情况下,对结构体Node中的某键值key排序 ---------------*/
struct Node {
    int key1, key2;
} A[MAXN];
  
int compare2keys(const void *a, const void *b)
{ /* 比较两种键值:按key1非升序排列;如果key1相等,则按key2非降序排列 */
    int k;
    if ( ((const struct Node*)a)->key1 < ((const struct Node*)b)->key1 )
        k = 1;
    else if ( ((const struct Node*)a)->key1 > ((const struct Node*)b)->key1 )
        k = -1;
    else { /* 如果key1相等 */
        if ( ((const struct Node*)a)->key2 < ((const struct Node*)b)->key2 )
            k = -1;
        else
            k = 1;
    }
    return k;
}
/* 调用接口 */ 
qsort(A, N, sizeof(struct Node), compare2keys);
/*--------------- 一般情况下,对结构体Node中的某键值key排序 ---------------*/
/* 快速排序 */
 
ElementType Median3( ElementType A[], int Left, int Right )
{ 
    int Center = (Left+Right) / 2;
    if ( A[Left] > A[Center] )
        Swap( &A[Left], &A[Center] );
    if ( A[Left] > A[Right] )
        Swap( &A[Left], &A[Right] );
    if ( A[Center] > A[Right] )
        Swap( &A[Center], &A[Right] );
    /* 此时A[Left] <= A[Center] <= A[Right] */
    Swap( &A[Center], &A[Right-1] ); /* 将基准Pivot藏到右边*/
    /* 只需要考虑A[Left+1] … A[Right-2] */
    return  A[Right-1];  /* 返回基准Pivot */
}
 
void Qsort( ElementType A[], int Left, int Right )
{ /* 核心递归函数 */ 
     int Pivot, Cutoff, Low, High;
       
     if ( Cutoff <= Right-Left ) { /* 如果序列元素充分多,进入快排 */
          Pivot = Median3( A, Left, Right ); /* 选基准 */ 
          Low = Left; High = Right-1;
          while (1) { /*将序列中比基准小的移到基准左边,大的移到右边*/
               while ( A[++Low] < Pivot ) ;
               while ( A[--High] > Pivot ) ;
               if ( Low < High ) Swap( &A[Low], &A[High] );
               else break;
          }
          Swap( &A[Low], &A[Right-1] );   /* 将基准换到正确的位置 */ 
          Qsort( A, Left, Low-1 );    /* 递归解决左边 */ 
          Qsort( A, Low+1, Right );   /* 递归解决右边 */  
     }
     else InsertionSort( A+Left, Right-Left+1 ); /* 元素太少,用简单排序 */ 
}
 
void QuickSort( ElementType A[], int N )
{ /* 统一接口 */
     Qsort( A, 0, N-1 );
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值