C++ 各种排序算法总结

1. Merge Sort / 归并排序

/*  Divide and conquer
 *  将一个数组中的两个相邻有序区间合并成一个
 *
 *  参数说明:
 *     A     -- 包含两个有序区间的数组
 *     lo    -- 第1个有序区间的起始地址。
 *     mi    -- 第1个有序区间的结束地址。也是第2个有序区间的起始地址。
 *     hi    -- 第2个有序区间的结束地址。
 */

  

 1 void merge(int A[],int lo,int hi,int mi){
 2     //以mi为界、各自有序癿子向量[lo, mi)和[mi, hi) 
 3     int temp[hi-lo+1];
 4     int i=lo, j=mi+1, k=0;
 5 
 6     while(i<=mid&&j<=lo){
 7         if(A[i]<=A[j])    
 8             temp[k++]=A[i++];
 9         else            
10             temp[k++]=A[j++];
11     }
12     while(i<=mid)    temp[k++]=A[i++];
13     while(j<=hi)    temp[k++]=A[j++];
14 
15     for(i=0;i<k;i++)     
16         A[lo++]=temp[i++];
17 }
18 
19 void mergeSort(int lo,int hi){
20     if(hi-lo < 2)    return;
21 
22     int mi=(hi+lo)>>1;
23     mergeSort(lo,mi);
24     mergeSort(mi,hi);
25     merge(lo,hi,mi);
26 }

2. Quick Sort /快排

/*   Divide and conquer
 *
 * - 在R[low,high]中任选一个记录作为基准(Pivot),
 *   以此基准将当前无序区划分为左、右两个较小的子区间R[low,pivotpos-1)和R[pivotpos+1,high],
 *
 * - 并使左边子区间中所有记录的关键字均小于等于基准记录(不妨记为pivot)的关键字pivot.key,此时左标记向右移动,
 *   直到左标记的关键字大于右标记的关键字,这时左标记停下,右标记同理进行操作。
 *   直到左标记和右标记都停下时,分两种情况讨论:
 *	 1.左标记与右标记不在同一位置,此时交换左右两标记的关键字
 *	 2.左右标记在同一位置,此时交换这一位置关键字和基准的位置
 *
 * - 此后就是分两边情况递归  
 */

  

 1 void QuickSort(int R[],int low,int high){
 2     int i,j,temp;
 3     i=low;    j=high;
 4     if(low<high){
 5         temp=R[low];
 6         while(i!=j){
 7             while(i<j&&R[j]>=temp)    
 8                 j--;
 9             if(i<j)            
10                 R[i++]=R[j];
11 
12             while(i<j&&R[i]<temp)    
13                 i++;
14             if(i<j)            
15                 R[j--]=R[i];
16         }
17         R[i]=temp;
18         QuickSort(R,low,i-1);
19         QuickSort(R,i+1,high);
20     }
21 }

 

3. 冒泡排序

/*   
* 借助布尔型标志位sorted,可及时提前退出,而不致蛮力地做n-1趟扫描交换 * 对尾部有序(或接近有序)的输入,算法依然亦步亦趋地收敛,导致元素比较次数过多
*/

 

void bubblesort1 ( int A[], int n ) { 
    for ( bool sorted = false; sorted = !sorted; n-- ) { 
   //在尚未确认已全局排序之前,逐趟进行扫描交换 for ( int i = 1; i < n; i++ ) {
     //自左向右逐对检查当前范围A[0, n)内的各相邻元素 if ( A[i-1] > A[i] ){ swap ( A[i-1], A[i] ); sorted = false; //因整体排序不能保证,需要清除排序标志 } } } }
 void bubblesort2 ( int A[], int n ) { 
    for ( bool sorted = false; sorted = !sorted; n-- ) { //在尚未确认已全局排序之前,逐趟进行扫描交换
       for ( int i = 1; i < n; i++ ) { //自左向右逐对检查当前范围A[0, n)内的各相邻元素
          if ( A[i-1] > A[i] ) { //一旦A[i-1]与A[i]逆序,则
             swap ( A[i-1], A[i] ); //交换之,并
             sorted = false; //因整体排序不能保证,需要清除排序标志
          }
       }
    }
 } 

 

 

/*
 * 借助整数m尽快地收缩待排序区间:既可提前退出,更可减少每趟(及所有)扫描交换中元素比较操作
 * 对尾部有序(或接近有序)的输入,算法收敛的速度大大提高
 * 元素交换的次数仅取决于输入序列,与版本1和版本2相同
 */
 1 void bubblesort3 ( int A[], int n ) { 
 2     for ( int m; 1 < n; n = m ) { //在尚未确认已全局排序之前,逐趟进行扫描交换
 3        for ( int i = m = 1; i < n; i++ ) { //自左向右逐对检查当前范围A[0, m)内的各相邻元素
 4           if ( A[i-1] > A[i] ) { //一旦A[i-1]与A[i]逆序,则
 5              swap ( A[i-1], A[i] ); //交换之,并
 6              m = i; //更新待排序区间的长度
 7           }
 8        }
 9     }
10  } 

 

上一篇:【动态规划】背包问题-例题分析


下一篇:「LibreOJ β Round」ZQC 的手办