zoukankan      html  css  js  c++  java
  • C语言实现数组快速排序(含对算法的详细解释)

    /* 
    
    说明: 
    
    代码参考过网上代码,但分析为个人原创,本贴重在说明快速排序算法的思想和运行过程。 
    
    */ 
    
    代码部分: 
    
    #include<stdio.h>
     #include<stdlib.h>
     void quickSort(int* arr,int startPos, int endPos) 
     {
      int i, j; 
      int key; 
      key = arr[startPos]; 
      i = startPos; 
      j = endPos; 
      while (i<j)
      {
       while (arr[j] >= key && i<j)--j; //————1 从后往前扫,直到找到一个a[j]<key或遍历完
      arr[i] = arr[j]; 
       while (arr[i] <= key && i<j)++i; //————2 从前往后扫,直到找到一个a[i]>key或遍历完
      arr[j] = arr[i];
      }
      arr[i] = key; 
      if (i - 1>startPos) quickSort(arr, startPos, i - 1); //————1 如果key前还有两个及以上的数,排key前的数(有一个的话自然就不用排了)
     if (endPos>i + 1) quickSort(arr, i + 1, endPos);//————2 如果key后还有两个及以上的数,排key后的数
    }
    int main() 
     {
      int a[11], i;
      for (i = 0; i<11; i++) 
       scanf_s("%d", &a[i]);
      quickSort(a, 0, 10); 
      for (i = 0; i<11; i++)
       printf("%d ", a[i]);
      printf("\n"); 
      return 0;
     }  
    
    解析部分: 
     /*
    以数组  a[0] a[1]  a[2]  a[3]  a[4]  a[5]  a[6]  a[7]  a[8]  a[9]  a[10]
                     0    2     32    39    23    45    36    57    14    27    39      为例,说明核心代码的实现机制 
    
    第一轮:
     首先进入quickSort(a, 0, 10); key=0,i=0,j=10,进入外层while,进入第一个内层while,由于0是数组中最小的,故j一直扫到头,j=0,arr[0] = arr[0]=0;
    显然无法进入第二个内层while,由于i=j=0,结束外层while,执行a[0]=key=0;显然不进入第一个if,进入第二个if,执行quickSort(a, 1, 10);进行从a[1]到
    a[10]的排序,第一轮结束。
     第二轮;
    执行quickSort(a, 1, 10),key=2,i=1,j=10,进入外层while,进入第一个内层while,由于2是传入段中最小的,故j一直扫到头,j=1,arr[1] = arr[1]=2;显然
     无法进入第二个内层while,由于i=j=1,结束外层while,执行a[1]=key=2;显然不进入第一个if,进入第二个if,执行quickSort(a, 2, 10);进行从a[2]到
    a[10]的排序,第二轮结束。
     第三轮:
     执行quickSort(a, 2, 10),key=32,i=2,j=10,进入外层while,进入第一个内层while,a[10]=39>key=32,--j,j变为9;a[9]=27<key=32,,退出第一个内层while,
     执行a[i]=a[2]=a[j]=a[9]=27,数组变为
                    a[0] a[1]  a[2]  a[3]  a[4]  a[5]  a[6]  a[7]  a[8]  a[9]  a[10]
                      0    2     27    39    23    45    36    57    14    27    39  
    注意此时a[j](即a[9])的值存入a[i](即a[2])中,a[j]可以被再赋值,32呢?32怎么没了呢?注意32始终由key保存,不用担心。注意此时i=2,j=9;
     程序顺次执行,满足第二个内层while,进入,开始从左往右扫。a[2]=27<key=32,++i,i变为3(注意这是必然的,因为第一次的a[i]是由上次内层while的a[j]送给
     的,而送给的条件是a[j](即这里的a[i])<key);a[i]=a[3]=39>key=32,执行a[j](前边已经说过,此时a[j]=a[9]的值已保存到a[2]中,a[j]可修改)=a[9]=a[3]
     =39,数组变为
                    a[0] a[1]  a[2]  a[3]  a[4]  a[5]  a[6]  a[7]  a[8]  a[9]  a[10]
                      0    2     27    39    23    45    36    57    14    39    39  
    注意此时a[i]=a[3]又变为可修改。
     注意此时i=3<j=9,未跳出外层while。
     继续执行第一个内层while,a[j]=a[9]=39>key=32,--j,j变为8(这也是必然的,道理同前边分析);a[j]=a[8]=14<key=32,退出第一个内层while,
     执行a[i]=a[3]=a[j]=a[8]=14,数组变为
                    a[0] a[1]  a[2]  a[3]  a[4]  a[5]  a[6]  a[7]  a[8]  a[9]  a[10]
                      0    2     27    14    23    45    36    57    14    39    39  
    注意此时a[j]=a[8]又变为可修改。此时i=3,j=8;
    程序顺次执行,满足第二个内层while,进入,开始从左往右扫。a[i]=a[3]=14<key=32,++i,i变为4(必然);a[i]=a[4]=23<key=32,++i,i变为5;a[i]=a[5]=
     45>key=32,退出第二个内层while,执行a[j]=a[8]=a[i]=a[5]=45,数组变为
                    a[0] a[1]  a[2]  a[3]  a[4]  a[5]  a[6]  a[7]  a[8]  a[9]  a[10]
                      0    2     27    14    23    45    36    57    45    39    39  
    注意此时a[i]=a[5]可修改,且i=5,j=8,未跳出外层while。
     继续执行第一个内层while,a[j]=a[8]=45>key=32,--j,j变为7(必然);a[j]=a[7]=57>key=32,--j,j变为6;a[j]=a[6]=36>key=32,--j,j变为5注意到此时i=j=5,
     直接退出三个while。执行a[i]=a[5]=key=32,数组变为
                    a[0] a[1]  a[2]  a[3]  a[4]  a[5]  a[6]  a[7]  a[8]  a[9]  a[10]
                      0    2     27    14    23    32    36    57    45    39    39  
    注意此时a[5]前的数都小于key=32,a[5]后的数都大于key=32,且startPos=2,endPos=10。
     显然两个if都满足,(这是人一次性判断的,计算机只能先判断第一个if,等程序再返回到本轮时再判断第二个if,我们一次性判断是为了说明方便)首先进入第一个
    if,执行quickSort(a, 2, 4),排a[5]前面的a[2]到a[4](a[0],a[1]在第二轮后已排好),进入下一轮(第四轮),但第三轮未结束,因为计算机还并未判断第二个
    if。
     第四轮:
     执行quickSort(a, 2, 4),key=a[2]=27,i=2,j=4,startPos=2,endPos=4。
     进入外层while,进入第一个内层while,a[j]=a[4]=23<key=27,执行a[i]=a[2]=a[j]=a[4]=23,数组变为
                    a[0] a[1]  a[2]  a[3]  a[4]  a[5]  a[6]  a[7]  a[8]  a[9]  a[10]
                      0    2     23    14    23    32    36    57    45    39    39  
    此时a[j]=a[4]可修改,且i=2,j=4,程序顺次执行,进入第二个while,a[i]=a[2]=23<key=27,++i,i变为3(必然):a[i]=a[3]=14<key=27,++i,i变为4,注意到i=
     j=4,退出所有循环,执行a[i]=a[4]=key=27,数组变为
                    a[0] a[1]  a[2]  a[3]  a[4]  a[5]  a[6]  a[7]  a[8]  a[9]  a[10]
                      0    2     23    14    27    32    36    57    45    39    39  
    此时i=j=4,startPos=2,endPos=4,显然满足第一个if不满足第二个if(key后已无数),故执行quickSort(a, 2, 3)(排a[4]前的),进入下一轮(第五轮),但
     第四轮未结束,因为计算机还并未判断第二个if。
     第五轮:
     执行quickSort(a, 2,3),key=a[2]=23,i=2,j=3,startPos=2,endPos=3。
     进入外层while,进入第一个内层while,a[j]=a[3]=14<key=23,执行a[i]=a[2]=a[j]=a[3]=14,数组变为
                    a[0] a[1]  a[2]  a[3]  a[4]  a[5]  a[6]  a[7]  a[8]  a[9]  a[10]
                      0    2     14    14    23    32    36    57    45    39    39  
    此时a[j]=a[3]可修改,且i=2,j=3,程序顺次执行,进入第二个while,a[i]=a[2]=14<key=23,++i,i变为3(必然):注意到i=j=3,退出所有循环,执行a[i]=a[3]=
     key=23,数组变为
                    a[0] a[1]  a[2]  a[3]  a[4]  a[5]  a[6]  a[7]  a[8]  a[9]  a[10]
                      0    2     14    23    27    32    36    57    45    39    39  
    此时i=j=3,startPos=2,endPos=3,显然不满足第一个if,再判断第二个,也不满足,故第五轮结束,返回到上一轮(第四轮)的第二个if处,前面已经分析过,不
     满足第二if,故第四轮结束,返回到上一轮(第三轮)的第二个if处(至此,到第三轮最终的a[i]=a[5]=key=32前的元素,都已排好),这次满足。执行
    quickSort(a, 6, 10),排a[5]后的元素,进入下一轮(记为第四*轮,为的是与上面的第四轮区别,同时也为了体现两者的联系)。第三轮结束。
     第四*轮:
     执行quickSort(a, 6, 10),key=a[6]=36,i=6,j=10,startPos=6,endPos=10。
     此时a[j]=a[3]可修改,且i=2,j=3,程序顺次执行,进入第二个while,a[i]=a[2]=14<key=23,++i,i变为3(必然):注意到i=j=3,退出所有循环,执行a[i]=a[3]=
     a[j]=a[10]=39>key=36,--j,j变为9;a[j]=a[9]=39>key=36,--j,j变为8;a[j]=a[8]=45>key=36,--j,j变为7;a[j]=a[7]=57>key=36,--j,j变为6;注意到i=j=6,
     退出所有while,执行a[i]=a[6]=key=36,数组不变。此时i=j=6,startPos=6,endPos=10。显然不满足第一个if,满足第二个if,执行quickSort(a, 7, 10)(排
    a[6]后的元素),进入第五*轮,第四*轮结束。
     第五*轮:
     执行quickSort(a, 7, 10),key=a[7]=57,i=7,j=10,startPos=7,endPos=10。
    a[j]=a[10]=39<key=57,执行a[i]=a[7]=a[j]=a[10]=39,数组变为
                    a[0] a[1]  a[2]  a[3]  a[4]  a[5]  a[6]  a[7]  a[8]  a[9]  a[10]
                      0    2     14    23    27    32    36    39    45    39    39  
    此时i=7,j=10,程序顺次执行,进入第二个内层while,a[i]=a[7]=39<key=57,++i,i变为8(必然);a[i]=a[8]=45<key=57,++i,i变为9;a[i]=a[9]=39<key=57,++i,
     i变为10;注意到i=j=10,退出所有while,执行a[i]=a[10]=key=57。数组变为
                    a[0] a[1]  a[2]  a[3]  a[4]  a[5]  a[6]  a[7]  a[8]  a[9]  a[10]
                      0    2     14    23    27    32    36    39    45    39    57  
    此时i=j=10,startPos=7,endPos=10。显然满足第一个if,不满足第二个if(a[i]=a[10]后面已没有元素),执行quickSort(a, 7, 9)(排a[10]前面的元素),进入
     第六*轮,但未退出第五*轮,因为计算机并还未判断第二个if。
     第六*轮:
     执行quickSort(a, 7, 9),key=a[7]=39,i=7,j=9,startPos=7,endPos=9。
    a[j]=a[9]=39=key=39,--j,j变为8;a[j]=a[8]=4>key=39,--j,j变为7;注意到i=j=7,退出所有while,执行a[i]=a[7]=key=39,数组不变。此时i=j=7,startPos=7,
     endPos=9。显然不满足第一个if(a[i]=a[7]前已无元素),满足第二个,执行quickSort(a, 8, 9)(排a[7]后面的元素),,进入第七*轮,第六*轮结束。
     第七*轮:
     执行quickSort(a, 8, 9),key=a[8]=45,i=8,j=9,startPos=8,endPos=9。
    a[j]=a[9]=39<key=45,执行a[i]=a[8]=a[j]=a[9]=39,数组变为
                    a[0] a[1]  a[2]  a[3]  a[4]  a[5]  a[6]  a[7]  a[8]  a[9]  a[10]
                      0    2     14    23    27    32    36    39    39    39    39  
    此时i=8,j=9,程序顺次执行,进入第二个内层while,a[i]=a[8]=39<key=45,++i,i变为9(必然);
     注意到i=j=9,退出所有while,执行a[i]=a[10]=key=57。数组变为
                    a[0] a[1]  a[2]  a[3]  a[4]  a[5]  a[6]  a[7]  a[8]  a[9]  a[10]
                      0    2     14    23    27    32    36    39    39    45    57
    此时i=j=9,startPos=8,endPos=9,显然不满足第一个if,再判断第二个,也不满足,第七*轮结束。程序回到第五*轮的第二个if,前面已经分析过,不满足,故第五*轮结束。
     至此,整个quickSort函数结束,数组已排好,如上所示。
    */ 
    
    如果大家觉得分析太多,不想看,建议大家按照代码手动执行一下,就豁然开朗了。当然,过程中可以结合、参考在下的分析。 
    
    代码已经过测试,在VS2013上成功运行! 
    
    发此文有两大目的: 
    
    1.和大家交流经验,供需要的人参考。 
    
    2.在下菜鸟,代码中难免有不妥之处,恳求大神批评指正。您的批评就是在下提高的起点,对于您的批评,在下将不胜感激! 
  • 相关阅读:
    Spring Boot (20) 拦截器
    Spring Boot (19) servlet、filter、listener
    Spring Boot (18) @Async异步
    Spring Boot (17) 发送邮件
    Spring Boot (16) logback和access日志
    Spring Boot (15) pom.xml设置
    Spring Boot (14) 数据源配置原理
    Spring Boot (13) druid监控
    Spring boot (12) tomcat jdbc连接池
    Spring Boot (11) mybatis 关联映射
  • 原文地址:https://www.cnblogs.com/zpcdbky/p/4104694.html
Copyright © 2011-2022 走看看