408数据结构之快速排序

快速排序

关于快速排序,408试卷中多为选择题,考察手动模拟快速排序过程,特别是对”划分一次子集,就有一个元素确定最终位置“这一特点的考察,2016年出现了涉及快速排序思想的数据结构大题,可见深入理解其思想和算法的必要性。

1、主流辅导书写法

列出《王道》和《天勤》的写法,更加推荐看王道上的算法。

1)王道数据结构

王道书的写法来自严蔚敏的《数据结构》,主元直接选择待排集合中的第一个元素,通俗易懂,便于理解快速排序算法的本质,但是在划分子集的时候有多余的比较,选主元pivot也简单选择第一个元素,存在极端情况时间复杂度为O(N2),有提升空间(应试的话掌握到这里就足够了)。

void QuickSort(ElemType A[],int low,int high){
    if(low<high){		//结束递归条件
        int pivotpos=Partiton(A,low,high);		//选主元,划分子集
        QuickSort(A,low,pivotpos-1);		//递归处理主元两侧的子集
        QuickSort(A,pivotpos+1,high);
    }
}
int Partiton(ElemType A[],int low,int high){
	ElemType pivot=A[low];		//选取集合中第一个元素为主元
    while(low<high){
        while(low<high&&A[high]>=pivot) --high;		//从右开始找小于主元的元素
        A[low]=A[high];								//换到左面
        while(low<high&&A[low]<=pivot) ++low;		//从左开始找大于主元的元素
        A[high]=A[low];								//换到右面
    }
    A[low]=pivot;							//循环结束时,low=high, 也就是主元的最终位置
    return low;								//返回主元的最终位置
}

2)天勤数据结构

天勤书上的算法就不推荐看了,既不便理解快速排序的本质,在性能上有没有实质上的提升。

void QuickSort(int R[],int low,int high){
    int temp;
    int i=low,j=high;
    if(low<high){
        temp=R[low];
        while(i<j){
			while(j>i&&R[j]>=temp) --j;
            if(i<j){
                R[i]=R[j];
                ++i;
            }
   			while(i<j&&R[j]<=temp) ++i;
            if(i<j){
                R[j]=R[j];
                --j;
            }
        }
        R[i]=temp;
        QuickSort(R,low,i-1);
        QuickSort(R,i+1,high);
	}
}

2、浙江大学《数据结构》慕课给出算法

推荐这门慕课,感谢陈越姥姥和何钦铭老师的付出~

https://www.icourse163.org/course/ZJU-93001?tid=1461682474

看完这个算法就想说”老程序员了“,考虑到了几点实际应用的细节:

1、统一函数接口;

2、引入阈值Cutoff,快速排序属于递归算法,且不适宜处理基本有序的集合,引入Cutoff以后就可以视数据规模调整处理方法;

3、主元pivot选取集合中头、中、尾三个数的中值,有效的避免了处理原本就有序的集合所出现的极端情况,选取函数设计的非常合理,调用完以后同时将划分子集的规模也减小2,算法的额外开销微乎其微。

4、划分子集时,采用一次交换两边的元素,比每次把一边的元素换到另一边的做法更加高效。

void QuickSort( ElementType A[], int N )
{ /* 统一接口 */
     Qsort( A, 0, N-1 );
}
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 ); /* 元素太少,用简单排序 */ 
}
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 */
}
posted @ 2021-07-04 15:11  来点新的  阅读(913)  评论(0)    收藏  举报