递归排序算法

1.思想:

  递归调用是用相同的方法去解决更小的问题,直到问题规模小于或等于某个边界条件时,不再进行递归(递归的出口),而是直接处理,然后不断向下执行函数返回结果。

2.分治法

   1.当问题小到一定规模时,可以直接求解;

   2.当问题规模较大时,可以分解为若干个相互独立的子问题,这些子问题与原问题具有相同的特征。若不能直接解决,则可分别递归求解;

   3.原问题的解是子问题的解的组合。

3.折半查找

  递归实现如下:

    

int BinSearch(int *arr,int key,int low,int high){
    int mid = (low + high)/2;    //取中
    if(low>high)                     
        return -1;            //找不到目标关键字,也就是递归程序的出口
    if(key = mid)                //找到返回,出口
        return mid;
    else if(key<mid)
         return BinSearch(arr,key,low,mid-1);      //递归调用
    else
        return BinSearch(arr,key,mid+1,high);
} 

 

 

4.归并排序

   要点:采用分治法的策略,将已有的有序子序列合并为完全有序的序列,首先要让子序列有序,然后再使子序列间有序,最后等到完全有序的序列。

   思想:将待排序序列R[0,...n-1]分为n个长度为1的子序列,讲相邻的子序列进行归并,得到n/2个长度为2的有序表;将这些有序序列再次归并,得到n/4个长度为4的有序序列;如此反复进行下去,最后得到一个长度为n的                     有序序列。

  首先要做两步:

      1.分解  ——将序列每次折半划分

      2.合并 ——将划分后的序列段两两合并后排序

 

那么现在我们就要解决两个问题,怎么分解和合并?

  分析:
        在某趟归并中,设各子文件长度为length(最后一个子文件的长度可能小于length),则归并前R[1..n]中共有n/length个有序的子文件:R[1..length],R[length+1..2length],…
  注意:
       调用归并操作将相邻的一对子文件进行归并时,必须对子文件的个数可能是奇数、以及最后一个子文件的长度小于length这两种特殊情况进行特殊处理:
    ① 若子文件个数为奇数,则最后一个子文件无须和其它子文件归并(即本趟轮空);
    ② 若子文件个数为偶数,则要注意最后一对子文件中后一子文件的区间上界是n。

一趟归并代码:

void  Merge(int * a,int low,int mid,int high)  
{  
   int i=low,j=mid+1,p=0;  
   int * r=new int[high-low+1];  
   while(i<=mid && j<=high)  
   {  
       r[p++]=(a[i]<=a[j])?a[i++]:a[j++];  
   }  
   while(i<=mid)  
       r[p++]=a[i++];  
   while(j<=high)  
       r[p++]=a[j++];  
   for(p=0,i=low;i<=high;p++,i++)  
       a[i]=r[p];  
   delete [] r;  
}

 

void MergePass(int *a,int n,int length)  
{  
 int i=0;  
    for(;i+2*length<n-1;i+=2*length)  
 {  
        Merge(a,i,i+length-1,i+2*length-1);  
 }  
 if(i+length<=n-1)  
       Merge(a,i,i+length-1,n-1);//尚有两个子文件,其中后一个长度小于length,归并最后两个子文件  
   //注意:若i≤n-1且i+length-1≥n-1时,则剩余一个子文件轮空,无须归并  
}  

二路归并代码:

//自底向上  
void MergeSort(int *a,int n)  
{  
   for(int length=1;length<n;length*=2)  
      MergePass(a,n,length);  
}  

 5.快速排序

基本思想:首先从待排序中选定一个基数,通过关键字和基数的比较将待排序列划分为两个子序列,其中在基数前的都不大于基数;我们发现每次都是把基数归位。

划分算法:

  

int Partition(int arr[],int low,int high){
    int temp =arr[low];
    while(low<high){    //low和high从待排序列两端向中间移动 
        while(low<high&&arr[high]>=temp) --high;    
        arr[low] = arr[high];    //将 比temp小的移到低端 
        while(low<high&&arr[low]<=temp) --low;
        arr[high] = arr[low];    //将比temp大的移到高端 
    }
    arr[low] = temp;
    return low;
}

 递归核心代码:

 

void QSort(int arr[],int s,int t){
    int pirvotloc;
    if(s<t){
        pirvotloc = Partition(arr,s,t); //进行划分并返回基数位置
        QSort(arr,s,pirvotloc-1);       //对基数前的子序列进行递归排序
        QSort(arr,pirvotlov+1,t);      //对基数后的子序列进行递归排序
    }
} 

 

posted @ 2017-10-14 11:25  im.lhc  阅读(13224)  评论(0编辑  收藏  举报