C语言网

 找回密码
 加入社区!

QQ登录

只需一步,快速开始

查看: 2833|回复: 23

[C语言] 各种排序—你都会吗(计数排序,基数排序,快速排序,...) [复制链接]

Rank: 12Rank: 12Rank: 12

主题
18
帖子
326
C币
1431 枚
在线时间
238 小时
发表于 2011-8-16 15:52:18 |显示全部楼层
分享到:
共包含
"插入排序","快速排序","归并排序","冒泡排序","选择排序","希尔排序","计数排序","基数排序","堆排序  "
  1. #include <stdio.h>
  2. #include <stdlib.h>
  3. #include <conio.h>
  4. #include <string.h>
  5. #include <Windows.h>
  6. #include <time.h>

  7. //把函数名,变量名和母语(拼音)联想下,别跟英语想一块去了~~~~

  8. #define MAX            123456        //长度
  9. #define PAIXU_CHARU     0           //插入排序
  10. #define PAIXU_KUAISU    1           //快速排序
  11. #define PAIXU_GUIBING   2           //归并排序
  12. #define PAIXU_MAOPAO    3           //冒泡排序
  13. #define PAIXU_XUANZE    4           //选择排序
  14. #define PAIXU_XIER      5           //希尔排序
  15. #define PAIXU_YIERSAN   6            //计数排序
  16. #define PAIXU_GESHIBAI  7            //基数排序
  17. #define PAIXU_DUI       8            //堆排序
  18. #define PAIXU_QSORT     9            //qsort函数

  19. #define FANGFASHU       10     //方法总数


  20. void data_shuchu(int* p,int leng);  //打印数组
  21. void data_fuzhi(int* p,int* data,int leng);   //拷贝数组

  22. void paixu_maopao(int* p,int leng,int (* cmp)(const void* a,const void* b));
  23. void paixu_xuanze(int* p,int leng,int (* cmp)(const void* a,const void* b));   
  24. void paixu_charu(int* p,int leng,int (* cmp)(const void* a,const void* b));   
  25. void paixu_kuaisu(int* p,int leng,int (* cmp)(const void* a,const void* b));
  26. void paixu_xier(int* p,int leng,int (* cmp)(const void* a,const void* b));
  27. void paixu_geshibai(int* p,int leng,int (* cmp)(const void* a,const void* b));
  28. void paixu_dui(int* p,int leng,int (* cmp)(const void* a,const void* b));
  29. int* paixu_guibing(int* p,int leng,int (* cmp)(const void* a,const void* b));
  30. int* paixu_yiersan(int* p,int leng,int (* cmp)(const void* a,const void* b));
  31. int* guibing_hebing(int* zuo_data,int zuo_leng,int* you_data,int you_leng,int (* cmp)(const void* a,const void* b));
  32. int  kuaisu_dingwei(int* p,int tou,int wei,int (* cmp)(const void* a,const void* b));
  33. void dui_jian(int* p,int s,int leng,int (* cmp)(const void* a,const void* b));
  34. //上面是各种不同排序的实现函数
  35. //  int* p----要排序的数组
  36. //  int leng-----数组的长度
  37. //  int (* cmp)(const void* a,const void* b)-------排序方法函数的指针


  38. int  paixu_fangfa(const void* a,const void* b);   //指定的排序方法
  39. double pk_paixu(int* p,int leng,int style,int (* cmp)(const void* a,const void* b));
  40. //排序并返回所用时间
  41. //int style-----指定用什么方法排序

  42. void main()
  43. {
  44.    
  45.         int* data=new int[MAX];     //存放原数据
  46.         int* p=new int[MAX];        //存放待排序的数据
  47.         int i;
  48.         double yongshi;              //排序所用的时间
  49.         double paixu_time[FANGFASHU]={0};      //保存每种排序的时间总和
  50.         char*  paixu_str[FANGFASHU]={"插入排序","快速排序","归并排序","冒泡排序","选择排序","希尔排序","计数排序","基数排序","堆排序  ","QSORT   "};
  51.                   //排序字符串,一定要跟宏定义的顺序一样,要不然就会牛头对马嘴了~~~
  52.         srand(time(0));      
  53.         for(i=0;i<MAX;i++)
  54.                 data[i]=rand();
  55.         //给原数据赋值
  56.        
  57.         for(i=0;i<3*FANGFASHU;i++)   //每种方法调用3次
  58.         {
  59.                    if(0==i%FANGFASHU)
  60.                         printf("第%d轮:\n",i/FANGFASHU+1);

  61.                         data_fuzhi(p,data,MAX);    //把data里德数据复制给p
  62.                         //data_shuchu(p,MAX);        //打印数组
  63.                         yongshi=pk_paixu(p,MAX,i%FANGFASHU,paixu_fangfa);   //排序
  64.                         //data_shuchu(p,MAX);        //打印数组
  65.                         paixu_time[i%FANGFASHU]+=yongshi;  //保存所用时间

  66.                         printf("%s排序用时:  %lf\n",paixu_str[i%FANGFASHU],yongshi);   //打印所用时间

  67.                         if(FANGFASHU-1==i%FANGFASHU) //每轮完后回车
  68.                            printf("\n");
  69.         }
  70.        
  71.         for(int j=0;j<FANGFASHU;j++)        
  72.             printf("%s平均用时:  %lf\n",paixu_str[j],paixu_time[j]/(i/FANGFASHU));

  73.         //打印每种方法所用时间

  74.         getch();
  75.         return;
  76. }


  77. double pk_paixu(int* p,int leng,int style,int (* cmp)(const void* a,const void* b))//排序并返回所用时间
  78. {
  79.         int* data;           //用来保存数据

  80.         double t_avg;
  81.         LONGLONG t1_long;
  82.         LONGLONG t2_long;
  83.         LARGE_INTEGER litmp;
  84.         //上面这些变量是用来计算排序时间的

  85.         QueryPerformanceFrequency(&litmp);
  86.         t_avg=litmp.QuadPart;
  87.         //得到计算时间的频率

  88.         QueryPerformanceCounter(&litmp);
  89.         t1_long=litmp.QuadPart;
  90.         //记下排序前的时间

  91.         switch(style)
  92.         {
  93.             case PAIXU_CHARU:
  94.                         //paixu_charu(p,leng,cmp);
  95.                 break;

  96.                 case PAIXU_KUAISU:
  97.                         paixu_kuaisu(p,leng,cmp);
  98.                 break;

  99.                 case PAIXU_GUIBING:
  100.                         data=paixu_guibing(p,leng,cmp);
  101.                 break;

  102.                 case PAIXU_MAOPAO:
  103.                         //paixu_maopao(p,leng,cmp);
  104.                 break;

  105.                 case PAIXU_XUANZE:
  106.                         //paixu_xuanze(p,leng,cmp);
  107.                 break;
  108.                
  109.                 case PAIXU_XIER:
  110.                         paixu_xier(p,leng,cmp);

  111.                 case PAIXU_YIERSAN:
  112.                         data=paixu_yiersan(p,leng,cmp);
  113.                 break;

  114.                 case PAIXU_GESHIBAI:
  115.                         paixu_geshibai(p,leng,cmp);
  116.                 break;

  117.                 case PAIXU_DUI:
  118.                         paixu_dui(p,leng,cmp);
  119.                 break;

  120.                 case PAIXU_QSORT:
  121.                         qsort(p,leng,sizeof(int),cmp);
  122.                 break;

  123.                 default:break;
  124.         }
  125.         //根据style传来的的值对号入座,调用不同的方法排序

  126.         QueryPerformanceCounter(&litmp);
  127.         t2_long=litmp.QuadPart;
  128.         //记下排序后的时间

  129.        
  130.         if(PAIXU_GUIBING==style||PAIXU_YIERSAN==style)
  131.            data_fuzhi(p,data,leng);           //拷贝数据

  132.     return (t2_long-t1_long)/t_avg;       //返回排序所用时间
  133. }

  134. void data_shuchu(int* p,int leng)        //打印数组
  135. {
  136.         for(int i=0;i<leng;i++)
  137.         {       
  138.                 if(i%10==0)
  139.                         printf("\n");
  140.                 printf("%d  ",p[i]);
  141.         }
  142.         printf("\n");
  143.         return;
  144. }

  145. void data_fuzhi(int*p,int* data,int leng)   //拷贝数据
  146. {
  147.          for(int i=0;i<leng;i++)
  148.                          *(p+i)=*(data+i);
  149.                  return;
  150. }

  151. int* paixu_guibing(int* p,int leng,int (* cmp)(const void* a,const void* b))    //归并排序
  152. {
  153.         if(leng<=1)                   //长度小于等于1当然就不要排序了~~~~
  154.                 return p;

  155.         int zuo_leng=leng/2;         
  156.         int you_leng=leng-zuo_leng;
  157.         int* zuo_data=new int[zuo_leng];
  158.         int* you_data=new int[you_leng];
  159.         //把数据切成两半所需要的用的变量
  160.         //分别是用来存放左右两边的长度和数据

  161.         for(int i=0;i<zuo_leng;i++)
  162.         {
  163.               *(zuo_data+i)=*(p+i);
  164.                   *(you_data+i)=*(p+i+zuo_leng);
  165.         }
  166.         if(0!=leng/2)
  167.                 *(you_data+you_leng-1)=*(p+leng-1);
  168.         //用传进来的数据p分别给zuo_data\you_data变量赋值


  169.         zuo_data=paixu_guibing(zuo_data,zuo_leng,cmp);  
  170.         you_data=paixu_guibing(you_data,you_leng,cmp);
  171.         //调用自己,把左边的一半再分成两半,右边也一样


  172.         return guibing_hebing(zuo_data,zuo_leng,you_data,you_leng,cmp);//对两边的数据进行排序与合并,返回合并后的数据
  173. }

  174. int* guibing_hebing(int* zuo_data,int zuo_leng,int* you_data,int you_leng,int (* cmp)(const void* a,const void* b))   //归并排序之对两边的数据进行排序与合并,返回合并后的数据
  175. {
  176.         int* data=new int[zuo_leng+you_leng];//用来存放左右两边合并的数据

  177.         int zuo=0;
  178.         int you=0;

  179.         while(zuo<zuo_leng&&you<you_leng)
  180.         {
  181.                if(0>=cmp((zuo_data+zuo),(you_data+you)))
  182.                    {
  183.                       *(data+zuo+you)=*(zuo_data+zuo);
  184.                       zuo++;
  185.                    }
  186.                    else
  187.                    {
  188.                       *(data+zuo+you)=*(you_data+you);
  189.                       you++;
  190.                    }
  191.         }
  192.         //上面是根据比较左右两边的大小决定是谁先给data赋值,一个一个的
  193.         //直到有一边没数据了,就不用比较了~~~

  194.         while(zuo<zuo_leng)         
  195.                 data[zuo+you]=zuo_data[zuo++];
  196.         while(you<you_leng)
  197.                 data[zuo+you]=you_data[you++];
  198.         //然后把剩下的数据直接赋值给data,只有一个while会执行,
  199.         //如果左右都有数据是跳不出上面那段循环的

  200.     return data;      //返回合并后的数据
  201. }

  202. void paixu_kuaisu(int* p,int leng,int (* cmp)(const void* a,const void* b))        //快速排序
  203. {
  204.         int* stack=new int[leng*2];
  205.         int top=0;
  206.         //用来实现栈的功能

  207.         int tou=0;
  208.         int wei=leng-1;
  209.         int index;

  210.         while(tou<wei)
  211.         {
  212.             index=kuaisu_dingwei(p,tou,wei,cmp);//对数据中的一位进行定位,返回其位置,并且使左边的都>=或<=右边

  213.                 stack[top++]=index+1;
  214.                 stack[top++]=wei;
  215.                 //把右边的先保存起来

  216.                 wei=index-1;      //继续左边的定位
  217.                 while(tou>=wei&&top)    //右边的都定位完了,就定位左边的
  218.                 {
  219.                    wei=stack[--top];
  220.                    tou=stack[--top];
  221.                 }
  222.                 //所有的数据都找到了自己的位置,自然就等于排好序了~~~~
  223.         }

  224.     return;
  225. }

  226. int kuaisu_dingwei(int *p,int tou,int wei,int (* cmp)(const void* a,const void* b))//快速排序,对数据中的一位进行定位,返回其位置,并且使左边的都>=或<=右边
  227. {
  228.         int data=p[tou+(wei-tou)/2];
  229.         p[tou+(wei-tou)/2]=p[tou];
  230.         //这里是选择了中间的那一位
  231.         //保存中间位数据的值,并把第一位的值赋给中间位

  232.         while(tou<wei)
  233.         {
  234.               while(tou<wei&&0<=cmp((p+wei),&data))
  235.                              wei--;
  236.                     *(p+tou)=*(p+wei);
  237.                         //把>或<的数据移到左边

  238.                     while(tou<wei&&0>=cmp((p+tou),&data))
  239.                              tou++;
  240.                     *(p+wei)=*(p+tou);
  241.                     //把>或<的数据移到右边
  242.         }
  243.         //使左边的都>=或<=右边

  244.         *(p+tou)=data;  //这里也可以用wei,因为tou=wei
  245.         return tou;        //返回位置
  246. }

  247. void paixu_maopao(int* p,int leng,int (* cmp)(const void* a,const void* b))//冒泡排序,跳过
  248. {
  249.         int data;

  250.         for(int i=0;i<leng-1;i++)
  251.         {
  252.            for(int j=leng-1;j>i;j--)
  253.            {
  254.                if(0>cmp((p+j),(p+j-1)))
  255.                                         {
  256.                                           data=*(p+j);
  257.                                           *(p+j)=*(p+j-1);
  258.                                           *(p+j-1)=data;
  259.                                         }
  260.            }
  261.         }
  262.         return;
  263. }

  264. void paixu_xuanze(int* p,int leng,int (* cmp)(const void* a,const void* b))//选择排序,跳过
  265. {
  266.         int data;

  267.         for(int i=0;i<leng-1;i++)
  268.         {
  269.                 for(int j=i;j<leng;j++)
  270.                 {
  271.                 if(0>cmp((p+j),(p+i)))
  272.                         {
  273.                           data=*(p+i);
  274.                           *(p+i)=*(p+j);
  275.                           *(p+j)=data;
  276.                         }
  277.                 }
  278.         }
  279. return;
  280. }

  281. void paixu_charu(int *p,int leng,int (* cmp)(const void* a,const void* b))//插入排序,跳过
  282. {
  283.         int data;
  284.         int index;

  285.         for(int i=1;i<leng;i++)
  286.         {
  287.           data=*(p+i);
  288.                 index=i;
  289.                 while(index>0&&0>cmp(&data,(p+index-1)))
  290.                 {
  291.                     *(p+index)=*(p+index-1);
  292.                           index--;
  293.                 }
  294.                 *(p+index)=data;
  295.         }

  296.     return;
  297. }

  298. void paixu_xier(int* p,int leng,int (* cmp)(const void* a,const void* b))//希尔排序
  299. {
  300.     int index;
  301.         int data;
  302.         int n;

  303.         for(n=leng/2;n>0;n/=2)     //把数据进行分组,然后对没一组进行插入排序
  304.         {
  305.              for(int i=n;i<leng;i++)
  306.                  {
  307.                      data=p[i];
  308.                          index=i-n;
  309.                          while(index>=0&&0>cmp(&data,(p+index)))
  310.                          {
  311.                              p[index+n]=p[index];
  312.                                  index-=n;
  313.                          }                 
  314.                          p[index+n]=data;
  315.                  }
  316.                  //上面把n当成1,就是插入排序了,一模一样~~~~
  317.                  //最终n就是要变成1的,进行一个真正的插入排序(最后一趟)
  318.                  //之所以比插入快,是因为之前的排序使最后一趟插入是不需要擦太深~~~~
  319.         }
  320.     return;
  321. }

  322. int* paixu_yiersan(int* p,int leng,int (* cmp)(const void* a,const void* b))//计数排序
  323. {
  324.         int max=0;
  325.         for(int i=0;i<leng;i++)
  326.                 if(max<p[i])
  327.                         max=p[i];
  328.         //寻找最大的值
  329.    
  330.         int* index=new int[max+1];
  331.         int* data=new int[leng];
  332.         bool shunxu=true;
  333.         int a=1;
  334.         int b=2;   
  335.         if(0<cmp(&a,&b))
  336.                 shunxu=false;
  337.     //看排序是按升序还是降序

  338.         memset(index,0,(max+1)*sizeof(int));  //把index中的数据初始化为0

  339.         for(int i=0;i<leng;i++)
  340.              index[p[i]]++;
  341.         //把有值的地方赋值为1

  342.          for(int i=1;i<=max;i++)
  343.                  index[i]+=index[i-1];
  344.          //计算位置
  345.    
  346.          for(int i=leng-1;i>=0;i--)
  347.          {
  348.                  if(shunxu)
  349.                    data[index[p[i]]-1]=p[i];
  350.                  else
  351.                    data[leng-index[p[i]]]=p[i];
  352.                  index[p[i]]--;
  353.          }
  354.          //根据index中的位置把p中的值赋值给data

  355.     return data;//返回排序好的数据
  356. }

  357. void paixu_dui(int* p,int leng,int (* cmp)(const void* a,const void* b)) //堆排序
  358. {
  359.         int data;
  360.         for(int i=leng/2;i>=0;i--)
  361.             dui_jian(p,i,leng,cmp);
  362.         //建堆
  363.        
  364.         for(int i=leng-1;i>0;i--)
  365.         {
  366.            data=p[0];
  367.            p[0]=p[i];
  368.            p[i]=data;
  369.            dui_jian(p,0,i-1,cmp);
  370.         }
  371.         //最后一个和第一个交换
  372.         //重新调整堆

  373.     return;
  374. }

  375. void dui_jian(int* p,int s,int leng,int (* cmp)(const void* a,const void* b))  //堆排序,建堆
  376. {
  377.         int data=p[s];

  378.     for(int i=2*s;i<leng;i*=2)
  379.         {
  380.            if(i<leng&&0>cmp((p+i),(p+i+1)))
  381.                    i++;
  382.                    if(0<=cmp(&data,(p+i)))
  383.                    break;
  384.            p[s]=p[i];
  385.            s=i;
  386.         }
  387.         p[s]=data;
  388.         //使堆顶为最小或最大值

  389.     return;
  390. }

  391. void paixu_geshibai(int* p,int leng,int (* cmp)(const void* a,const void* b))//基数排序
  392. {
  393.         int max=1;
  394.         int x=1;
  395.         int n=0;
  396.         int p_index=0;
  397.         int* p_data[10];
  398.         int data_index[10]={0};
  399.         bool max_xunzhao=true;
  400.        
  401.         bool shunxu=true;
  402.         int a=1;
  403.         int b=2;   
  404.         if(0<cmp(&a,&b))
  405.                 shunxu=false;
  406.         //看排序是按升序还是降序

  407.         for(int i=0;i<10;i++)
  408.                 p_data[i]=new int[leng];
  409.         //为10个基数申请空间
  410.        
  411.         while(x<=max)
  412.         {
  413.                 for(int i=0;i<leng;i++)
  414.                 {
  415.                         if(max_xunzhao)
  416.                            if(max<p[i])
  417.                                max=p[i];
  418.                            //寻找最大的数,只执行一次就可以了

  419.                         if(x>p[i])
  420.                                 p_data[0][data_index[0]++]=p[i];   //小于x就不用计算n的值了,因为计算了也是0
  421.                         else
  422.                         {
  423.                         n=(p[i]/x)%10;                    //计算基数
  424.                             p_data[n][data_index[n]++]=p[i];     //放到相应的空间里
  425.                         }
  426.                 }

  427.                 if(shunxu)
  428.                         for(int i=0;i<10;i++)
  429.                         {
  430.                                 for(int j=0;j<data_index[i];j++)
  431.                                    p[p_index++]=p_data[i][j];
  432.                                 data_index[i]=0;
  433.                         }
  434.                 else
  435.                    for(int i=9;i>=0;i--)
  436.                         {
  437.                                 for(int j=0;j<data_index[i];j++)
  438.                                    p[p_index++]=p_data[i][j];
  439.                                 data_index[i]=0;
  440.                         }
  441.                    //上面是看升序还降序,决定是++还--
  442.                    //把空间里的数据按顺序放回p

  443.             x*=10;
  444.                 p_index=0;
  445.                 max_xunzhao=false;
  446.         }
  447.    return;
  448. }

  449. int paixu_fangfa(const void* a,const void* b)  //排序方法,是降序还升序
  450. {
  451. return *(int*)a-*(int*)b;
  452. }
复制代码
然后问下要想把比较的类型int改为void该怎么去索引和交换数据啊~~~
先谢了!!!
一直在坚持

Rank: 16Rank: 16Rank: 16Rank: 16

主题
18
帖子
261
C币
865 枚
在线时间
296 小时
发表于 2011-8-16 16:23:16 |显示全部楼层
多谢共享~

Rank: 3Rank: 3

主题
7
帖子
22
C币
223 枚
在线时间
18 小时
发表于 2011-9-26 17:28:56 |显示全部楼层
不错的贴子!!!

Rank: 3Rank: 3

主题
21
帖子
132
C币
169 枚
在线时间
21 小时
发表于 2011-9-30 22:14:46 |显示全部楼层
哇哇。还是好多不会
C语言编译器:gcc
IDE:Vim + gdb

Rank: 4

主题
0
帖子
88
C币
242 枚
在线时间
23 小时
发表于 2011-10-11 23:04:42 |显示全部楼层
顶…………

Rank: 2

主题
0
帖子
7
C币
67 枚
在线时间
8 小时
发表于 2011-10-14 11:35:32 |显示全部楼层
int (* cmp)(const void* a,const void* b)——这条代码是什么意思?
形参为空类型的常量指针? (* cmp)又是什么意思,可以这样子强制转换吗?

谁来帮忙解释一下啊!

Rank: 1

主题
2
帖子
19
C币
53 枚
在线时间
3 小时
发表于 2011-10-14 11:45:34 |显示全部楼层
我需要花些时间啊

Rank: 1

主题
0
帖子
4
C币
28 枚
在线时间
4 小时
发表于 2011-10-15 11:38:52 |显示全部楼层
道行不够啊

Rank: 12Rank: 12Rank: 12

主题
18
帖子
326
C币
1431 枚
在线时间
238 小时
发表于 2011-10-19 12:30:54 |显示全部楼层
telu 发表于 2011-10-14 11:35
int (* cmp)(const void* a,const void* b)——这条代码是什么意思?
形参为空类型的常量指针? (* cmp) ...

是函数指针
一直在坚持

Rank: 2

主题
0
帖子
7
C币
67 枚
在线时间
8 小时
发表于 2011-10-21 21:16:41 |显示全部楼层
raotf 发表于 2011-10-19 12:30
是函数指针

谢谢了,前些天我搞懂了
您需要登录后才可以回帖 登录 | 加入社区!

C语言 ( 粤ICP备11042647号-2 )

GMT+8, 2012-2-23 15:16

©2009-2011 cyuyan.com.cn

回顶部