• 【数据结构第八周】排序(下)【快速排序】


    步骤:

    1、从数列中挑出一个元素,称为"基准"或者“主元”(pivot)

    2、重新排序数列,所有元素比基准值小的摆放在基准前面,所有元素比基准值大的摆在基准的后面(相同的数可以到任一边)。在这个分区退出之后,该基准就处于数列的中间位置。这个称为分区(partition)操作

    3、递归地把小于基准值元素的子数列和大于基准值元素的子数列排序

    选主元的时候可以使用“取头、中、尾的中位数”这种方法。

    如果你选取第一个元素作为主元,如果一个数列本身就是有序的,用这种办法产生的O(N^2)的复杂度显然是不能接受的。

    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 ];
    }
    

    对小规模的数据(例如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[ ++i ] < 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 );
    	}
    
    }
    
  • 相关阅读:
    LOJ 6089 小Y的背包计数问题 —— 前缀和优化DP
    洛谷 P1969 积木大赛 —— 水题
    洛谷 P1965 转圈游戏 —— 快速幂
    洛谷 P1970 花匠 —— DP
    洛谷 P1966 火柴排队 —— 思路
    51Nod 1450 闯关游戏 —— 期望DP
    洛谷 P2312 & bzoj 3751 解方程 —— 取模
    洛谷 P1351 联合权值 —— 树形DP
    NOIP2007 树网的核
    平面最近点对(加强版)
  • 原文地址:https://www.cnblogs.com/acmsummer/p/4332554.html
Copyright © 2020-2023  润新知