美文网首页
排序算法:快速排序递归实现

排序算法:快速排序递归实现

作者: 疋瓞 | 来源:发表于2021-12-24 09:57 被阅读0次

1、环境配置:

  • 系统:win10
  • 编程语言:C++
  • 编译器:DevC++

2、算法思想:

  • 以数组中第一个元素为标准,让比它大的去它右边,让比他小的去它左边,然后在他右边实行同样的方法,在他左边实行同样的方法;
  • 伪代码
int fast( i, j, a[1 ... n] )//i为a[]的首项下标,j为a[]的最后一项下标 
{
    if ( i >= j ) then return(0);
    bz = a[i]; //选第一个作为标准 
    p = i;    //p是指向标准的指针 
    z = j;
    for  m = i to m < z+1  do
    {
        if ( bz > a[m] ) then {
                                sl  = a[m];
                                a[m] = a[p];
                                a[p] = sl;
                                p = m;
                              }
        if ( bz < a[m] ) then {   //比bz大的直接放到最后一个 
                                sh  = a[m];
                                a[m] = a[z];
                                a[z] = sh;
                                z = z - 1;
                                m = m - 1;
                              }
    }
    fast( p + 1, j, a );
    fast( i, p - 1, a );
}

3、第一代代码:

  • 实现了把大的放右边,小的放左边的操作。
/*
《快速排序》
1、取一个数组中的第一位数i,然后比较其余数,
重排,让i的左边比i小,右边比i大。
2、然后从左边取第一个数重复上述过程,右边取
第一个数,重复上述过程。 
3、终止条件是左右两边都只剩一个数据 
*/

#include<iostream>

using namespace std;

int fast(int i,int j,int a[]);//i是开始序号,j是结束序号。 

int main()
{
   int A[] = {4,2,5,3,6,0};
   for(int s=0; s<sizeof(A)/sizeof(A[0]); s++){
    cout<<A[s]<<",";
   }
   cout<<""<<endl; 
   for(int tm=0; tm<sizeof(A)/sizeof(A[0]); tm++){
    cout<<"_____";
   }
   cout<<""<<endl; 
    
   fast(0,5,A);
   
   cout<<""<<endl; 
   for(int tm=0; tm<sizeof(A)/sizeof(A[0]); tm++){
    cout<<"_____";
   }
   cout<<""<<endl; 
   for(int s=0; s<sizeof(A)/sizeof(A[0]); s++){
    cout<<A[s]<<",";
   }
   
   return 0;
}

//快速排序
int fast(int i,int j,int a[]){
    if(i == j){
        return 0;
    }
    int bz = a[i];//选第一个作为标准 
    int p = i;//p是指向标准的指针 
    int z = j;
    for(int m=i; m<z+1; m++){
        cout<<"m= "<<m<<" |";
        if(bz > a[m]){  
            int sl=0;
            sl = a[m];
            a[m] = a[p];
            a[p] = sl;
            p = m;
        }
        if(bz < a[m]){
            if(m == z){
                return 0;
            }
            int sh=0;
            sh = a[m];
            a[m] = a[z];
            a[z] = sh;
            z=z-1;
            m=m-1;
        }           
        for(int s=0; s<j+1; s++){
            cout<<a[s]<<",";
        }
        cout<<"i="<<i<<"  j="<<j<<endl;
        cout<<""<<endl;     
    }
    
} 

4、结果展示:

结果展示.png

关于第一代代码反思分析:

  • 问题一:第一代代码是可以实现“左小右大”的第一次筛选了,但是发现在完成筛选循环后,在fast代码最后最后添加fast(p+1,j,a);和fast(i,p-1,a);这两条代码就是不执行,原因如下:
//程序有两个出口
if(i == j){
    return 0;
}
...
if(bz < a[m])//本意是在调整右边的时候,不用遍历完所有数组元素就能早点结束。
{
    if(m == z){
        return 0;
}

测试后发现,去掉第二个出口,对程序结果没有影响,程序只不过会遍历完所有数组元素而已。

  • 问题二:在调整了出口问题后,我发现,在fast代码最后最后添加fast(i,p-1,a),程序可以跑,可以将左边部分顺利排序,但是在添加fast(p+1,j,a);程序就会出错。原来是p在fast代码中随着m的增加有可能增加,然后在传递的时候,会通过p+1继续增加一次。这样的话,原来的递归终止条件if(i == j)就会无法响应,程序会陷入死循环,这个在下面的代码中有注释。
  • 总结:第一代代码在解决了上述两个问题之后,就能实现递归调用了!

5、第二代代码:

  • 将整个数组排序。
#include<iostream>

using namespace std;

int fast(int i,int j,int a[]);//i是开始序号,j是结束序号。 

int main()
{
   int A[] = {4,2,5,3,6,0};
   for(int s=0; s<sizeof(A)/sizeof(A[0]); s++){
    cout<<A[s]<<",";
   }
   cout<<""<<endl; 
   for(int tm=0; tm<sizeof(A)/sizeof(A[0]); tm++){
    cout<<"_____";
   }
   cout<<""<<endl; 
    
   fast(0,5,A);
   
   
   cout<<""<<endl; 
   for(int tm=0; tm<sizeof(A)/sizeof(A[0]); tm++){
    cout<<"_____";
   }
   cout<<""<<endl; 
   for(int s=0; s<sizeof(A)/sizeof(A[0]); s++){
    cout<<A[s]<<",";
   }
   
   return 0;
}

//快速排序
int fast(int i,int j,int a[]){
/*
这里如果设置成i==j,在判断左边的时候,不会出错。
在判断右边的时候,p有可能在程序中向右移动一次,
然后在传参时继续移动一次,导致p>j,陷入死循环。
*/ 
    if(i >= j)
    {
        return 0;
    }
    int bz = a[i];//选第一个作为标准 
    int p = i;//p是指向标准的指针 
    int z = j;
    for(int m=i; m<z+1; m++){
        if(bz > a[m]){  
            int sl=0;
            sl = a[m];
            a[m] = a[p];
            a[p] = sl;
            p = m;//在这里p会向后移动 
        }
        if(bz < a[m]){
            int sh=0;
            sh = a[m];
            a[m] = a[z];
            a[z] = sh;
            z=z-1;
            m=m-1;
        }                   
    }
    /*
    发现使用递归排左边没问题,排右边就陷入死循环,
    下面两条打印语句帮了大忙,DEVC++缺点就是排错太难了。 
    */  
    cout<<"i="<<i<<",j="<<j<<endl;
    cout<<"p="<<p<<endl;
    
    fast(p+1,j,a);
    fast(i,p-1,a);
    
} 

6、结果展示:

结果展示.png

7、反思总结:

  • 1、写递归程序的时候,一定要注意出口(递归终止条件/递归返回条件)设置过多,可能会造成无法递归执行。
  • 2、写递归程序之前一定要把算法思路明确,然后先实现算法思路当中的“基本任务”,比如这个算法中基本任务就是选第一个做标准,小的放它左边,大的放它右边。完成了基本任务,调整调整程序,加上“自己调自己”这个步骤,就能实现递归了。

相关文章

  • 三大排序算法

    归并排序[稳定的排序算法] 递归实现 非递归实现 快速排序[不稳定的排序算法] 堆排序[不稳定的排序算法]

  • 排序

    八大排序算法 一、归并排序 递归及非递归的JAVA实现 二、快速排序 快排算法JAVA实现 三、堆排序 堆排序堆排...

  • 快速排序&快速排序与归并排序的对比

    快速排序算法 快速排序算法是从上到下解决问题使用递归实现,通过巧妙的方式,实现原地排序 分析时间复杂度O(nlog...

  • 看图说话排序算法之冒泡排序

    排序算法的种类非常多,这里总结冒泡排序和对冒泡排序的改进---快速排序的循环实现和递归实现。 一丶冒泡排序 假设待...

  • 常见排序算法

    这里介绍四种排序算法,选择排序、快速排序、归并排序、计数排序 选择排序(使用递归) 选择排序(使用循环) 快速排序...

  • 七大排序算法之快速排序

    七大排序算法之快速排序 @(算法笔记)[排序算法, 快速排序, C++实现] [TOC] 快速排序的介绍: 快速排...

  • 剑指offer学习笔记:2.4 算法和数据操作

    2.4 算法和数据操作 重点关注二分查找,归并排序和快速排序。很多算法都有递归和循环两种不同实现方法。通常基于递归...

  • 2020-08-21 算法合集

    1. 冒泡排序 2.选择排序 3. 插入排序 4. 希尔排序 5. 归并排序(递归实现) 6. 快速排序(递归实现...

  • 算法汇总

    关于算法: 基础技巧:分治、二分、贪心排序算法:快速排序、归并排序、计数排序搜索算法:回溯、递归、深度优先遍历,广...

  • 数据结构&算法(一)

    一、Java实现快速排序算法 二、Java实现折半插入排序算法 三、Java实现冒泡排序算法

网友评论

      本文标题:排序算法:快速排序递归实现

      本文链接:https://www.haomeiwen.com/subject/zjatqrtx.html