C/C++:各種基本算法實現小結(五)—— 排序算法

各種基本算法實現小結(五)—— 排序算法

(均已測試通過)

 

選擇排序 |____簡單選擇排序 |____堆排序 |____歸併排序

交換排序 |____冒泡排序 |____快速排序

插入排序 |____直接插入排序 |____折半排序 |____希爾排序

分配排序 |____箱排序 |____基數排序

======================================================================

簡單排序算法

 

1、 冒泡排序

測試環境:VC 6.0 (C)

  1. #include  
  2.  <stdio.h>  
  3. #include <stdlib.h>  
  4. #include <time.h>  
  5. #define MAX 11  
  6. void input(int num[])  
  7. {  
  8.     int i;  
  9.       
  10.     srand((unsigned)time(NULL));  
  11.     for(i=1; i<MAX; i++)  
  12.         num[i]=rand()%100;        
  13. }  
  14. void output(int num[])  
  15. {  
  16.     int i;  
  17.       
  18.     for(i=1; i<MAX; i++)  
  19.     {  
  20.         printf("%5d", num[i]);  
  21.         if(0 == i%10)  
  22.             printf("/n");  
  23.     }  
  24.     printf("/n");  
  25. }  
  26. void sort(int num[])  
  27. {  
  28.     int i, j, tmp;  
  29.     for(i=1; i<MAX-1; i++)  
  30.     {  
  31.         printf("bubble.../n");  
  32.         for(j=1; j<MAX-i; j++)  
  33.         {  
  34.             printf("%5d", num[j]);  
  35.             if(num[j]>num[j+1])  
  36.             {  
  37.                 tmp=num[j];  
  38.                 num[j]=num[j+1];  
  39.                 num[j+1]=tmp;                                 
  40.             }  
  41.         }  
  42.         printf("%5d/n", num[MAX-i]);  
  43.           
  44.         printf("bubble after.../n");  
  45.         for(j=1; j<MAX; j++)  
  46.             printf("%5d", num[j]);  
  47.         printf("/n");  
  48.     }  
  49. }  
  50. /* bubble sort */  
  51. /*  
  52. void sort(int num[]) 
  53. { 
  54.     int i, j, tmp; 
  55.     for(i=1; i<MAX-1; i++) 
  56.     { 
  57.         for(j=1; j<MAX-i; j++) 
  58.             if(num[j]>num[j+1]) 
  59.             { 
  60.                 tmp=num[j]; 
  61.                 num[j]=num[j+1]; 
  62.                 num[j+1]=tmp;                                
  63.             } 
  64.     } 
  65. } 
  66. */  
  67. void main()  
  68. {  
  69.     int num[MAX];  
  70.     printf("sort before.../n");  
  71.     input(num);  
  72.     output(num);  
  73.     sort(num);  
  74.     printf("sort after.../n");  
  75.     output(num);  
  76. }  

運行結果:

=======================================================

2、雙向冒泡排序

據說可以提高效率,減少比較次數和交換次數

但仔細分析可得,每次while循環,都for循環比較了兩次

因此每次low和high各減1,總體上比較次數並未減少,兩次for交換也未減少

個人認爲雙向冒泡算法並未有效的減少比較次數和交換次數,但此算法也富含編程思想,值得學習

 

測試環境:VC 6.0 (C)

  1. #include  
  2.  <stdio.h>  
  3. #include <stdlib.h>  
  4. #include <time.h>  
  5. #define swap(x, y){int tmp; tmp=x; x=y; y=tmp;}  
  6. #define MAX 11  
  7. void input(int num[])  
  8. {  
  9.     int i;  
  10.       
  11.     srand((unsigned)time(NULL));  
  12.     for(i=1; i<MAX; i++)  
  13.         num[i]=rand()%100;  
  14. }  
  15. void output(int num[])  
  16. {  
  17.     int i;  
  18.       
  19.     for(i=1; i<MAX; i++)  
  20.     {  
  21.         printf("%5d", num[i]);  
  22.         if(0 == i%10)  
  23.             printf("/n");  
  24.     }  
  25. }  
  26. void sort(int num[], int low, int high)  
  27. {  
  28.     int i;  
  29.       
  30.     while(low<high)  
  31.     {  
  32.         for(i=low; i<high; i++) /* bubble to high */  
  33.             if(num[i]>num[i+1])  
  34.                 swap(num[i], num[i+1]);  
  35.         high--;  
  36.           
  37.         for(i=high; i>low; i--)  /* bubble to low */  
  38.             if(num[i]<num[i-1])  
  39.                 swap(num[i], num[i-1]);  
  40.         low++;  
  41.     }  
  42. }  
  43. void main()  
  44. {  
  45.     int num[MAX];  
  46.     input(num);  
  47.       
  48.     printf("sort before.../n");  
  49.     output(num);  
  50.       
  51.     sort(num, 1, MAX-1);  
  52.     printf("sort after.../n");  
  53.     output(num);  
  54. }  

運行結果:

=======================================================

3、選擇排序

測試環境:VC 6.0 (C)

  1. #include <stdio.h>  
  2. #include <stdlib.h>  
  3. #include <time.h>  
  4. #define MAX 101  
  5. void input(int num[])  
  6. {  
  7.     int i;  
  8.       
  9.     srand((unsigned)time(NULL));  
  10.     for(i=1; i<MAX; i++)  
  11.         num[i]=rand()%100;        
  12. }  
  13. void output(int num[])  
  14. {  
  15.     int i;  
  16.       
  17.     for(i=1; i<MAX; i++)  
  18.     {  
  19.         printf("%5d", num[i]);  
  20.         if(0 == i%10)  
  21.             printf("/n");  
  22.     }  
  23.     printf("/n");  
  24. }  
  25. void sort(int num[])  
  26. {  
  27.     int i, j, k, tmp;  
  28.     for(i=1; i<MAX-1; i++)  
  29.     {  
  30.         k=i;  
  31.         for(j=i+1; j<MAX; j++)  
  32.             if(num[k]>num[j])  
  33.                 k=j;  
  34.         if(i<k)  
  35.         {  
  36.             tmp=num[i];  
  37.             num[i]=num[k];  
  38.             num[k]=tmp;  
  39.         }  
  40.     }  
  41. }  
  42. void main()  
  43. {  
  44.     int num[MAX];  
  45.     printf("sort before.../n");  
  46.     input(num);  
  47.     output(num);  
  48.     sort(num);  
  49.     printf("sort after.../n");  
  50.     output(num);  
  51. }  

運行結果:

=======================================================

 

中級排序算法

向部分已排好序數列插入新值,使整個數列最終都有序

 

1、直接插入排序

測試環境:VC 6.0 (C)

  1. #include <stdio.h>  
  2. #include <stdlib.h>  
  3. #include <time.h>  
  4. #define MAX 11  
  5. void input(int num[])  
  6. {  
  7.     int i;  
  8.       
  9.     srand((unsigned)time(NULL));  
  10.     for(i=1; i<MAX; i++)  
  11.         num[i]=rand()%100;        
  12. }  
  13. void output(int num[])  
  14. {  
  15.     int i;  
  16.       
  17.     for(i=1; i<MAX; i++)  
  18.     {  
  19.         printf("%5d", num[i]);  
  20.         if(0 == i%10)  
  21.             printf("/n");  
  22.     }  
  23.     printf("/n");  
  24. }  
  25. void sort(int num[])  
  26. {  
  27.     int i, pos, tmp;  
  28.     for(i=2; i<MAX; i++) /* from 2 to sorting */  
  29.     {  
  30.         pos=i;  
  31.         tmp=num[pos];  
  32.         while(pos>1 && tmp<num[pos-1])  
  33.         {             
  34.             num[pos]=num[pos-1];  
  35.             pos--;            
  36.         }  
  37.         num[pos]=tmp;  
  38.     }  
  39. }  
  40. void main()  
  41. {  
  42.     int num[MAX];  
  43.     printf("sort before.../n");  
  44.     input(num);  
  45.     output(num);  
  46.     sort(num);  
  47.     printf("sort after.../n");  
  48.     output(num);  
  49. }  

運行結果:

=======================================================

2、 折半插入排序

折半插入排序算法是一種穩定的排序算法,比直接插入算法明顯減少了關鍵字之間比較的次數

因此速度比直接插入排序算法快,但記錄移動的次數沒有變,

所以折半插入排序算法的時間複雜度仍然爲O(n^2),


測試環境:VC 6.0 (C)

  1. #include  
  2.  <stdio.h>  
  3. #include <stdlib.h>  
  4. #include <time.h>  
  5. #define MAX 11  
  6. void input(int num[])  
  7. {  
  8.     int i;  
  9.       
  10.     srand((unsigned)time(NULL));  
  11.     for(i=1; i<MAX; i++)  
  12.         num[i]=rand()%100;  
  13. }  
  14. void output(int num[])  
  15. {  
  16.     int i;  
  17.       
  18.     for(i=1; i<MAX; i++)  
  19.     {  
  20.         printf("%5d", num[i]);  
  21.         if(0 == i%10)  
  22.             printf("/n");  
  23.     }  
  24.     printf("/n");  
  25. }  
  26. void sort(int num[], int low, int high)  
  27. {  
  28.     int i, j, mid;  
  29.     int l, h;  
  30.     for(i=2; i<=high; i++)  
  31.     {  
  32.         l=low;  
  33.         h=i-1;  
  34.         num[0]=num[i]; /* save */  
  35.           
  36.         while(l<=h)  
  37.         {  
  38.             mid=(l+h)/2;  
  39.             if(num[0]<num[mid])  
  40.                 h=mid-1;  
  41.             else  
  42.                 l=mid+1;  
  43.         }  
  44.           
  45.         for(j=i; j>l; j--)  /* move */  
  46.             num[j]=num[j-1];  
  47.         num[l]=num[0];  
  48.     }  
  49. }  
  50. void main()  
  51. {  
  52.     int num[MAX];  
  53.       
  54.     input(num);  
  55.       
  56.     printf("sort before.../n");  
  57.     output(num);  
  58.     sort(num, 1, MAX-1);  
  59.       
  60.     printf("sort after.../n");  
  61.     output(num);      
  62. }  

運行結果:

=======================================================

3、 2-路插入排序

2-路插入排序:是在折半插入排序的基礎上再次改進,其目的是減少排序過程中記錄移動的次數

測試環境:VC 6.0 (C)

  1. #include <stdio.h>  
  2. #include <stdlib.h>  
  3. #include <time.h>  
  4. #define MAX 11  
  5. int num2[MAX];  
  6. void input(int num[])  
  7. {  
  8.     int i;  
  9.       
  10.     srand((unsigned)time(NULL));  
  11.     for(i=1; i<MAX; i++)  
  12.         num[i]=rand()%100;  
  13. }  
  14. void output(int num[])  
  15. {  
  16.     int i;  
  17.       
  18.     for(i=1; i<MAX; i++)  
  19.     {  
  20.         printf("%5d", num[i]);  
  21.         if(0 == i%10)  
  22.             printf("/n");  
  23.     }  
  24.     printf("/n");  
  25. }  
  26. void bi_insertsort(int num[], int len)  
  27. {  
  28.     int i, j, pos, head, tail;  
  29.     head=tail=1;  
  30.     num2[1]=num[1];  
  31.     for(i=2; i<=len; i++)  
  32.     {  
  33.         if(num[i]>num2[1])  /* larger, save to tail */  
  34.         {  
  35.             for(j=tail; j>1; j--)  
  36.             {  
  37.                 if(num[i]<num2[j])  
  38.                     num2[j+1]=num2[j];  
  39.                 else  
  40.                     break;  
  41.             }  
  42.             num2[j+1]=num[i];  
  43.             tail++;  
  44.         }   
  45.         else    /* smaller, save to head */  
  46.         {  
  47.             if(head==1)   /* first to end, then to head... */  
  48.             {  
  49.                 num2[len]=num[i];  
  50.                 head=len;  
  51.             }  
  52.             else  
  53.             {  
  54.                 for(j=head; j<=len; j++)  
  55.                 {  
  56.                     if(num[i]>num2[j])  
  57.                         num2[j-1]=num2[j];  
  58.                     else  
  59.                         break;  
  60.                 }  
  61.                 num2[j-1]=num[i];  
  62.                 head--;  
  63.             }  
  64.         }         
  65.     }  
  66.       
  67.     pos=1;  
  68.     for(i=1; i<=len; i++) /* move back data from num2[] to num[] */  
  69.     {  
  70.         if(head<=len)  
  71.             num[i]=num2[head++];  
  72.         else if(pos<=tail)  
  73.             num[i]=num2[pos++];  
  74.     }  
  75. }  
  76. int main()  
  77. {  
  78.     int num[MAX]; /* 1 - len is num, 0->null */  
  79.     input(num);  
  80.     printf("sort before.../n");  
  81.     output(num);  
  82.       
  83.     bi_insertsort(num, MAX-1);  
  84.     printf("sort after.../n");  
  85.     output(num);  
  86.       
  87.     return 0;  
  88. }  

運行結果:

=======================================================

4、合併插入排序(數組實現)

將兩個有序數組A、B合併成另一個有序的大數組C

 

測試環境:VC 6.0 (C)

  1. #include <stdio.h>  
  2. void input_num1(int num[], int n1)  
  3. {  
  4.     int i;  
  5.     for(i=1; i<=n1; i++)  
  6.         num[i]=3*(i-1);  
  7.     printf("/nnum 1.../n");  
  8.     for(i=1; i<=n1; i++)  
  9.     {  
  10.         printf("%5d", num[i]);  
  11.         if(0 == i%10)  
  12.             printf("/n");  
  13.     }  
  14. }  
  15. void input_num2(int num[], int n2)  
  16. {  
  17.     int i;  
  18.     for(i=1; i<=n2; i++)  
  19.         num[i]=i;  
  20.     printf("/nnum 2.../n");  
  21.     for(i=1; i<=n2; i++)  
  22.     {  
  23.         printf("%5d", num[i]);  
  24.         if(0 == i%10)  
  25.             printf("/n");  
  26.     }  
  27. }  
  28. void output_num3(int num1[], int n1, int num2[], int n2, int num3[], int n3)  
  29. {  
  30.     int pos1, pos2, pos3;  
  31.     pos3=pos2=pos1=1;  
  32.       
  33.     while(pos1<=n1 && pos2<=n2)  
  34.     {  
  35.         if(num1[pos1]<num2[pos2])  
  36.             num3[pos3++]=num1[pos1++];  
  37.         else  
  38.             num3[pos3++]=num2[pos2++];  
  39.     }  
  40.     while(pos1<=n1)  
  41.         num3[pos3++]=num1[pos1++];  
  42.     while(pos2<=n2)  
  43.         num3[pos3++]=num2[pos2++];  
  44.     printf("/n/nnum 3.../n");  
  45.     for(pos3=1; pos3<=n3; pos3++)  
  46.     {  
  47.         printf("%5d", num3[pos3]);  
  48.         if(0 == pos3%10)  
  49.             printf("/n");  
  50.     }  
  51. }  
  52. void main()  
  53. {  
  54.     int num1[11];  
  55.     int num2[21];  
  56.     int num3[31];  
  57.       
  58.     input_num1(num1, 10);  
  59.     input_num2(num2, 20);  
  60.     output_num3(num1, 10, num2, 20, num3, 30);  
  61. }  

運行結果:

=======================================================

5、合併插入排序(鏈表實現)

將兩個有序鏈表A、B合併成另一個有序的大鏈表C(鏈表單元來自A和B)

 

測試環境:VC 6.0 (C)

  1. #include <stdio.h>  
  2. #include <malloc.h>  
  3. struct _link  
  4. {  
  5.     int data;  
  6.     struct _link *next;  
  7. };  
  8. typedef struct _link link, *plink;  
  9. plink init_link()  
  10. {  
  11.     plink p;  
  12.       
  13.     p=(plink)malloc(sizeof(link));  
  14.     if(!p) /* if(p == NULL) */  
  15.     {  
  16.         printf("Error. malloc fail.../n");  
  17.         return NULL;  
  18.     }  
  19.     p->data=-1;  
  20.     p->next=NULL;  
  21.     return p;  
  22. }  
  23. plink input_num1(plink plk, int n1)  
  24. {  
  25.     int i, count;  
  26.     plink p, s;  
  27.       
  28.     p=plk;  
  29.       
  30.     for(i=1; i<=n1; i++)  
  31.     {  
  32.         s=(plink)malloc(sizeof(link));  
  33.         if(!s) /* if(p == NULL) */  
  34.         {  
  35.             printf("Error. malloc fail.../n");  
  36.             return NULL;  
  37.         }  
  38.         s->data=3*(i-1);  
  39.         s->next=NULL;  
  40.         p->next=s;  
  41.         p=p->next;  
  42.     }             
  43.       
  44.     count=0;  
  45.     s=plk->next;  
  46.     while(s)  
  47.     {  
  48.         count++;  
  49.         printf("%5d", s->data);  
  50.         s=s->next;  
  51.         if(0 == count%10)  
  52.             printf("/n");  
  53.     }  
  54.     printf("/n");  
  55.     return plk;  
  56. }  
  57. plink input_num2(plink plk, int n2)  
  58. {  
  59.     int i, count;  
  60.     plink p, s;  
  61.       
  62.     p=plk;  
  63.       
  64.     for(i=1; i<=n2; i++)  
  65.     {  
  66.         s=(plink)malloc(sizeof(link));  
  67.         if(!s) /* if(p == NULL) */  
  68.         {  
  69.             printf("Error. malloc fail.../n");  
  70.             return NULL;  
  71.         }  
  72.         s->data=i;  
  73.         s->next=NULL;  
  74.         p->next=s;  
  75.         p=p->next;  
  76.     }             
  77.       
  78.     count=0;  
  79.     s=plk->next;  
  80.     while(s)  
  81.     {  
  82.         count++;  
  83.         printf("%5d", s->data);  
  84.         s=s->next;  
  85.         if(0 == count%10)  
  86.             printf("/n");  
  87.     }  
  88.     printf("/n");  
  89.     return plk;  
  90. }  
  91. void output_num3(plink plk1, plink plk2, plink plk3)  
  92. {  
  93.     int count;  
  94.     plink p1, p2, p3;  
  95.     p1=plk1->next;  
  96.     p2=plk2->next;  
  97.     p3=plk3;  
  98.     while(p1 && p2)  
  99.     {         
  100.         if(p1->data < p2->data)  
  101.         {  
  102.             p3->next=p1;  
  103.             p3=p3->next;  
  104.             p1=p1->next;  
  105.         }  
  106.         else  
  107.         {  
  108.             p3->next=p2;  
  109.             p3=p3->next;  
  110.             p2=p2->next;  
  111.         }  
  112.     }  
  113.     p3->next = p1 ? p1 : p2; /* NOTE: directly link to not NULL address, OK */  
  114.     count=0;  
  115.     p3=plk3->next;  
  116.     while(p3)  
  117.     {  
  118.         count++;  
  119.         printf("%5d", p3->data);  
  120.         p3=p3->next;  
  121.         if(0 == count%10)  
  122.             printf("/n");  
  123.     }  
  124.     printf("/n");  
  125. }  
  126. void main()  
  127. {  
  128.     plink plk1, plk2, plk3;  
  129.       
  130.     plk1=init_link();  
  131.     plk2=init_link();  
  132.     plk3=init_link();  
  133.     printf("num 1.../n");  
  134.     plk1=input_num1(plk1, 10);  
  135.     printf("num 2.../n");  
  136.     plk2=input_num2(plk2, 20);  
  137.       
  138.     printf("num 3.../n");  
  139.     output_num3(plk1, plk2, plk3);  
  140. }  

運行結果:

=======================================================

 

高級排序算法

 

 

1、 快速排序

測試環境:VC 6.0 (C)

  1. #include <stdio.h>  
  2. #include <stdlib.h>  
  3. #include <time.h>  
  4. #define MAX 21  
  5. void input(int num[])  
  6. {  
  7.     int i;  
  8.       
  9.     srand(time(NULL));  
  10.     for(i=0; i<MAX; i++)  
  11.         num[i]=rand()%100;  
  12. }  
  13. void output(int num[])  
  14. {  
  15.     int i;  
  16.       
  17.     for(i=1; i<MAX; i++)  
  18.     {  
  19.         printf("%5d", num[i]);  
  20.         if(0 == i%10)  
  21.             printf("/n");  
  22.     }  
  23. }  
  24. void sort(int num[], int low, int high)  
  25. {  
  26.     int l, h;  
  27.     l=low;  
  28.     h=high;  
  29.     if(low < high)  
  30.     {  
  31.         num[0]=num[l]; /* num[0] save pivot */  
  32.           
  33.         while(l<h)  
  34.         {  
  35.             while(l<h && num[h]>=num[0]) h--;  
  36.             num[l]=num[h];  
  37.             while(l<h && num[l]<=num[0]) l++;  
  38.             num[h]=num[l];  
  39.         }  
  40.         num[l]=num[0];  
  41.         sort(num, low, l-1);  
  42.         sort(num, l+1, high);  
  43.     }     
  44. }  
  45. void main()  
  46. {  
  47.     int num[MAX];  
  48.     input(num);  
  49.     printf("/nsort before.../n");  
  50.     output(num);  
  51.     sort(num, 1, MAX-1);  
  52.     printf("/nsort before.../n");  
  53.     output(num);  
  54. }  

運行結果:

=======================================================

2、 希爾排序

說明:本示例僅測試10或11個數的3趟希爾排序

由於希爾排序的增量step至今尚無精準的數學論證,無法給出科學、高效的序列函數

據嚴蔚敏的《數據結構(C語言版)》介紹說:希爾排序的分析是一個複雜的問題,因爲它的時間是所取“增量”序列的函數,這涉及一些數學上尚未解決的難題(P272).

 

因此,本示例僅是實際問題實際解決的一個特例。

本算法基本思想仍是上述直接排序算法的改進,僅僅步長由1變成了step而已

如果大家想需要增添或減少數組元素個數,請一併修改input()函數中的step等趟數序列

如果大家對希爾排序算法有更好的改進,或有較好步長的函數和通用模板,希望能拿出來共同學習交流分享,謝謝!

 

測試環境:VC 6.0 (C)

  1. #include <stdio.h>  
  2. #include <stdlib.h>  
  3. #include <time.h>  
  4. #define MAX 11   /* num[] */  
  5. #define STEP 4   /* jump[] */  
  6. void input(int num[], int jump[])  
  7. {  
  8.     int i;  
  9.     srand((unsigned)time(NULL));  
  10.     for(i=1; i<MAX; i++)  
  11.         num[i]=rand()%100;    
  12.     for(i=1; i<STEP; i++)  
  13.         jump[i]=7-2*i;   /* 1->5; 2->3; 3->1 */  
  14. }  
  15. void output(int num[])  
  16. {  
  17.     int i;  
  18.       
  19.     for(i=1; i<MAX; i++)  
  20.     {  
  21.         printf("%5d", num[i]);  
  22.         if(0 == i%10)  
  23.             printf("/n");  
  24.     }  
  25. }  
  26. void sort(int num[], int jump[])  
  27. {  
  28.     int i, j, pos, step;  
  29.     for(i=1; i<STEP; i++)  
  30.     {  
  31.         step=jump[i];  
  32.         for(j=1+step; j<MAX; j++)  
  33.         {  
  34.             pos=j;  
  35.             num[0]=num[pos]; /* save num[j] where (i+step)<j<MAX */  
  36.             while(num[0]<num[pos-step])  
  37.             {  
  38.                 num[pos]=num[pos-step];           
  39.                 pos=pos-step; /* shell: jump step */  
  40.             }  
  41.             num[pos]=num[0];  
  42.         }  
  43.     }  
  44. }  
  45. void main()  
  46. {  
  47.     int num[MAX];  
  48.     int jump[STEP];  
  49.       
  50.     input(num, jump);  
  51.     printf("sort before.../n");  
  52.     output(num);  
  53.     sort(num, jump);  
  54.       
  55.     printf("sort after.../n");  
  56.     output(num);  
  57. }  

運行結果:

=======================================================

2、 希爾排序(網摘)

在學習希爾排序算法時,看到網上有如下一段希爾排序代碼,也可以直接運行

但看代碼來真得很費解,感覺變量定義不夠直觀,算法設計也不太簡潔

因此,在最大程度保留源代碼時,僅對變量名和算法邏輯簡單修改

力爭做到變量名清晰,邏輯順暢,達到不用註釋讀者也能看明白

希望對大家學習有點幫助

 

測試環境:VC 6.0 (C)

摘錄原代碼:http://apps.hi.baidu.com/share/detail/5669244(百度空間)

  1. #include <iostream.h>  
  2. void ShellSort(int* pData,int Count)  
  3. {  
  4.    int step[4];  
  5.    step[0] = 9;  
  6.    step[1] = 5;  
  7.    step[2] = 3;  
  8.    step[3] = 1;  
  9.    int iTemp;  
  10.    int k,s,w;  
  11.    for(int i=0;i<4;i++)  
  12.    {  
  13.      k = step[i];  
  14.      s = -k;  
  15.      for(int j=k;j<Count;j++)  
  16.      {  
  17.        iTemp = pData[j];  
  18.        w = j-k;//求上step個元素的下標  
  19.        if(s ==0)  
  20.        {  
  21.          s = -k;  
  22.          s++;  
  23.          pData[s] = iTemp;  
  24.        }  
  25.        while((iTemp<pData[w]) && (w>=0) && (w<=Count))  
  26.        {  
  27.          pData[w+k] = pData[w];  
  28.          w = w-k;  
  29.        }  
  30.        pData[w+k] = iTemp;  
  31.      }  
  32.    }  
  33. }  
  34. void main()  
  35. {  
  36.    int data[] = {10,9,8,7,6,5,4,3,2,1,-10,-1};  
  37.    ShellSort(data,12);  
  38.    for (int i=0;i<12;i++)  
  39.      cout<<data[i]<<" ";  
  40.    cout<<"/n";  
  41. }  
 

修改後代碼:

  1. #include <iostream.h>   
  2. void ShellSort(int* pData,int Count)   
  3. {     
  4.     int iTemp;   
  5.     int steplen, pos;  
  6.     int step[4];   
  7.     step[0] = 9;   
  8.     step[1] = 5;   
  9.     step[2] = 3;   
  10.     step[3] = 1;   
  11.       
  12.     for(int i=0;i<4;i++)   
  13.     {   
  14.         steplen = step[i];   
  15.         for(int j=0+steplen; j<Count; j++)   
  16.         {   
  17.             iTemp = pData[j];   
  18.             pos=j;  
  19.             while(iTemp<pData[pos-steplen] && pos>0)   
  20.             {   
  21.                 pData[pos] = pData[pos-steplen];   
  22.                 pos=pos-steplen;  
  23.             }   
  24.             pData[pos] = iTemp;   
  25.         }   
  26.     }   
  27. }   
  28. void main()   
  29. {   
  30.     int data[] = {10,9,8,7,6,5,4,3,2,1,-10,-1};   
  31.     cout<<endl<<"sort before..."<<endl;   
  32.     for (int i=0;i<12;i++)   
  33.         cout<<data[i]<<" ";   
  34.     cout<<endl;   
  35.     ShellSort(data,12);   
  36.     cout<<endl<<"sort before..."<<endl;   
  37.     for (i=0;i<12;i++)   
  38.         cout<<data[i]<<" ";   
  39.     cout<<endl;   
  40. }  

運行結果:

=======================================================

3、 堆排序

測試環境:VC 6.0 (C)

  1. #include <stdio.h>  
  2. #include <stdlib.h>  
  3. #include <time.h>  
  4. #define MAX 11  
  5. void input(int num[])  
  6. {  
  7.     int i;  
  8.       
  9.     srand((unsigned)time(NULL));  
  10.     for(i=1; i<MAX; i++)  
  11.         num[i]=rand()%100;  
  12. }  
  13. void output(int num[])  
  14. {  
  15.     int i;  
  16.       
  17.     for(i=1; i<MAX; i++)  
  18.     {  
  19.         printf("%5d", num[i]);  
  20.         if(0 == i%10)  
  21.             printf("/n");  
  22.     }  
  23.     printf("/n");  
  24. }  
  25. void heapadjust(int num[], int s, int len) /* build large heap */  
  26. {  
  27.     int j;  
  28.     num[0]=num[s];  /* save temp data */  
  29.       
  30.     for(j=2*s; j<=len; j*=2)  
  31.     {  
  32.         if(j<len && num[j]<num[j+1]) /* num[j+1] is limited by j<len beyond the border */  
  33.             j++;  
  34.         if(num[0]>num[j])  
  35.             break;  
  36.         num[s]=num[j];  
  37.         s=j;  
  38.     }  
  39.     num[s]=num[0];  
  40. }  
  41. void heapsort(int num[], int len)  
  42. {  
  43.     int i, tmp;  
  44.     for(i=len/2; i>0; i--) /* build heap */  
  45.         heapadjust(num, i, len);  
  46.       
  47.     for(i=len; i>1; i--)   /* sort heap */  
  48.     {  
  49.         tmp=num[1];    /* change largest data to end */  
  50.         num[1]=num[i];  
  51.         num[i]=tmp;  
  52.         heapadjust(num, 1, i-1); /* rebuild large heap for (i-1) data */  
  53.     }  
  54. }  
  55. int main()  
  56. {  
  57.     int num[MAX]; /* 1 - len is num, 0->null */  
  58.     input(num);  
  59.     printf("sort before.../n");  
  60.     output(num);  
  61.       
  62.     heapsort(num, MAX-1);  
  63.     printf("sort after.../n");  
  64.     output(num);  
  65.       
  66.     return 0;  
  67. }  

運行結果:

=======================================================

4、 歸併排序

測試環境:VC 6.0 (C)

  1. #include <stdio.h>  
  2. #include <stdlib.h>  
  3. #include <time.h>  
  4. #define MAX 11  
  5. int num2[MAX]; /* copy array */  
  6. void input(int num[])  
  7. {  
  8.     int i;  
  9.       
  10.     srand((unsigned)time(NULL));  
  11.     for(i=1; i<MAX; i++)  
  12.         num[i]=rand()%100;  
  13. }  
  14. void output(int num[])  
  15. {  
  16.     int i;  
  17.       
  18.     for(i=1; i<MAX; i++)  
  19.     {  
  20.         printf("%5d", num[i]);  
  21.         if(0 == i%10)  
  22.             printf("/n");  
  23.     }  
  24.     printf("/n");  
  25. }  
  26. void merge(int num[], int low, int mid, int high)  
  27. {  
  28.     int l, h, i, j;  
  29.     l=low;  
  30.     h=high;  
  31.     for(i=mid+1, j=low; low<=mid && i<=high; j++)  
  32.     {  
  33.         if(num[low]<num[i])  
  34.             num2[j]=num[low++];  
  35.         else  
  36.             num2[j]=num[i++];  
  37.     }  
  38.     if(low<=mid)  
  39.         for(; j<=high; j++, low++)  
  40.             num2[j]=num[low];  
  41.     if(i<=high)  
  42.         for(; j<=high; j++, i++)  
  43.             num2[j]=num[i];  
  44.     for(i=l; i<=h; i++)  
  45.         num[i]=num2[i];  
  46. }  
  47. void mergesort(int num[], int low, int high)  
  48. {  
  49.     int mid;  
  50.     if(low==high)  
  51.         num2[low]=num[low];  
  52.     else  
  53.     {  
  54.         mid=(low+high)/2;  
  55.         mergesort(num, low, mid);     /* to low */  
  56.         mergesort(num, mid+1, high);  /* to high */  
  57.         merge(num, low, mid, high);   /* recursion */  
  58.     }  
  59. }  
  60. int main()  
  61. {  
  62.     int num[MAX]; /* 1 - len is num, 0->null */  
  63.     input(num);  
  64.     printf("sort before.../n");  
  65.     output(num);  
  66.       
  67.     mergesort(num, 1, MAX-1);  
  68.     printf("sort after.../n");  
  69.     output(num);  
  70.       
  71.     return 0;  
  72. }  

運行結果:

=======================================================

排序算法的知識擴展(網摘)

 

內部排序算法的比較和實現
引用網址:http://www.cppblog.com/feosun/archive/2008/10/12/63831.html(直接摘錄,尚未測試)

參考網址:http://sjjp.tjuci.edu.cn/sjjg/DataStructure/DS/web/paixu/paixu8.1.1.1.htm(數據結構)


排序是數據處理中經常使用的一種重要運算,在計算機及其應用系統中,花費在排序上的時間在系統運行時間中佔有很大比重;並且排序本身對推動算法分析的發展 也起很大作用。目前已有上百種排序方法,但尚未有一個最理想的盡如人意的方法,本文介紹常用的如下排序方法的C/C++實現,並對它們進行分析和比較。

 

選擇排序、快速排序、希爾排序、堆排序不是穩定的排序算法,而冒泡排序、插入排序、歸併排序和基數排序是穩定的排序算法。

首先,排序算法的穩定性大家應該都知道,通俗地講就是能保證排序前2個相等的數其在序列的前後位置順序和排序後它們兩個的前後位置順序相同。在簡單形式化一下,如果Ai = Aj, Ai原來在位置前,排序後Ai還是要在Aj位置前。

其次,說一下穩定性的好處。排序算法如果是穩定的,那麼從一個鍵上排序,然後再從另一個鍵上排序,第一個鍵排序的結果可以爲第二個鍵排序所用。基數排序就 是這樣,先按低位排序,逐次按高位排序,低位相同的元素其順序再高位也相同時是不會改變的。另外,如果排序算法穩定,對基於比較的排序算法而言,元素交換 的次數可能會少一些(個人感覺,沒有證實)。

回到主題,現在分析一下常見的排序算法的穩定性,每個都給出簡單的理由。

(1)冒泡排序
        冒泡排序就是把小的元素往前調或者把大的元素往後調。比較是相鄰的兩個元素比較,交換也發生在這兩個元素之間。所以,如果兩個元素相等,我想你是不會再無 聊地把他們倆交換一下的;如果兩個相等的元素沒有相鄰,那麼即使通過前面的兩兩交換把兩個相鄰起來,這時候也不會交換,所以相同元素的前後順序並沒有改 變,所以冒泡排序是一種穩定排序算法。

(2)選擇排序
      選擇排序是給每個位置選擇當前元素最小的,比如給第一個位置選擇最小的,在剩餘元素裏面給第二個元素選擇第二小的,依次類推,直到第n-1個元素,第n個 元素不用選擇了,因爲只剩下它一個最大的元素了。那麼,在一趟選擇,如果當前元素比一個元素小,而該小的元素又出現在一個和當前元素相等的元素後面,那麼 交換後穩定性就被破壞了。比較拗口,舉個例子,序列5 8 5 2 9,我們知道第一遍選擇第1個元素5會和2交換,那麼原序列中2個5的相對前後順序就被破壞了,所以選擇排序不是一個穩定的排序算法。

(3)插入排序
     插入排序是在一個已經有序的小序列的基礎上,一次插入一個元素。當然,剛開始這個有序的小序列只有1個元素,就是第一個元素。比較是從有序序列的末尾開 始,也就是想要插入的元素和已經有序的最大者開始比起,如果比它大則直接插入在其後面,否則一直往前找直到找到它該插入的位置。如果碰見一個和插入元素相 等的,那麼插入元素把想插入的元素放在相等元素的後面。所以,相等元素的前後順序沒有改變,從原無序序列出去的順序就是排好序後的順序,所以插入排序是穩 定的。

(4)快速排序
    快速排序有兩個方向,左邊的i下標一直往右走,當a[i] <= a[center_index],其中center_index是中樞元素的數組下標,一般取爲數組第0個元素。而右邊的j下標一直往左走,當a[j] > a[center_index]。如果i和j都走不動了,i <= j, 交換a[i]和a[j],重複上面的過程,直到i>j。交換a[j]和a[center_index],完成一趟快速排序。在中樞元素和a[j]交 換的時候,很有可能把前面的元素的穩定性打亂,比如序列爲 5 3 3 4 3 8 9 10 11,現在中樞元素5和3(第5個元素,下標從1開始計)交換就會把元素3的穩定性打亂,所以快速排序是一個不穩定的排序算法,不穩定發生在中樞元素和 a[j] 交換的時刻。

(5)歸併排序
    歸併排序是把序列遞歸地分成短序列,遞歸出口是短序列只有1個元素(認爲直接有序)或者2個序列(1次比較和交換),然後把各個有序的段序列合併成一個有 序的長序列,不斷合併直到原序列全部排好序。可以發現,在1個或2個元素時,1個元素不會交換,2個元素如果大小相等也沒有人故意交換,這不會破壞穩定 性。那麼,在短的有序序列合併的過程中,穩定是是否受到破壞?沒有,合併過程中我們可以保證如果兩個當前元素相等時,我們把處在前面的序列的元素保存在結 果序列的前面,這樣就保證了穩定性。所以,歸併排序也是穩定的排序算法。

(6)基數排序
   基數排序是按照低位先排序,然後收集;再按照高位排序,然後再收集;依次類推,直到最高位。有時候有些屬性是有優先級順序的,先按低優先級排序,再按高優 先級排序,最後的次序就是高優先級高的在前,高優先級相同的低優先級高的在前。基數排序基於分別排序,分別收集,所以其是穩定的排序算法。

(7)希爾排序(shell)
    希爾排序是按照不同步長對元素進行插入排序,當剛開始元素很無序的時候,步長最大,所以插入排序的元素個數很少,速度很快;當元素基本有序了,步長很小, 插入排序對於有序的序列效率很高。所以,希爾排序的時間複雜度會比o(n^2)好一些。由於多次插入排序,我們知道一次插入排序是穩定的,不會改變相同元 素的相對順序,但在不同的插入排序過程中,相同的元素可能在各自的插入排序中移動,最後其穩定性就會被打亂,所以shell排序是不穩定的。

(8)堆排序
   我們知道堆的結構是節點i的孩子爲2*i和2*i+1節點,大頂堆要求父節點大於等於其2個子節點,小頂堆要求父節點小於等於其2個子節點。在一個長爲n 的序列,堆排序的過程是從第n/2開始和其子節點共3個值選擇最大(大頂堆)或者最小(小頂堆),這3個元素之間的選擇當然不會破壞穩定性。但當爲n /2-1, n/2-2, ...1這些個父節點選擇元素時,就會破壞穩定性。有可能第n/2個父節點交換把後面一個元素交換過去了,而第n/2-1個父節點把後面一個相同的元素沒 有交換,那麼這2個相同的元素之間的穩定性就被破壞了。所以,堆排序不是穩定的排序算法。

/*
   冒泡排序  插入排序 二路插入排序 希爾排序   快速排序 選擇排序 歸併排序  堆排序算法的
   C/C++實現。
   
   作者:feosun

   日期:2008年10月12日

   參考資料:數據結構(C語言版) 清華大學出版社

*/

#include <iostream>
using namespace std;


//交換兩個數的值
void swap(int &a,int &b)
{
    int tmp;
    tmp=a;
    a=b;
    b=tmp;
}

//屏幕輸出數組
void display(int array[],int len)
{
    cout<<"the result is:"<<endl;
    for (int i = 0 ;i < len;i++ )
    {
        cout<<array[i]<<"  ";
    }
    cout<<endl;
}

/*
冒泡排序

算法思想:將被排序的記錄數組R[1..n]垂直排列,每個記錄R[i]看作是重量爲R[i].key的氣泡。
          根據輕氣泡不能在重氣泡之下的原則,從下往上掃描數組 R:凡掃描到違反本原則的
          輕氣泡,就使其向上"飄浮"。如此反覆進行,直到最後任何兩個氣泡都是輕者在上,
          重者在下爲止。

時間複雜度 o(n^2)

空間複雜度 o(1)

比較次數 n(n+1)/2
*/
void bubble_sort(int array[],int len)
{
    
    for (int i = len-1 ;i >= 0;i-- )
    {
        for(int j = 0;j < i;j++)
            if(array[j] > array[j+1])
                swap(array[j],array[j+1]);
    }
}

/*
直接插入排序

算法思想:把n個待排序的元素看成爲一個有序表和一個無序表,開始時有序表中只包含一個元
          素,無序表中包含有n-1個元素,排序過程中每次從無序表中取出第一個元素,將它
          插入到有序表中的適當位置,使之成爲新的有序表,重複n-1次可完成排序過程。

時間複雜度 o(n^2)

空間複雜度 o(1)

比較次數 n(n+1)/2
*/
void insert_sort(int array[],int len)
{
    int tmp,i,j;

    for(i = 1;i < len;i++)
    {
        if (array[i] < array[i-1])
        {
            tmp = array[i];
            array[i] = array[i-1];

            //插入到相應位置
            for (j = i-2;j >= 0;j--)
            {
                //往後移
                    if (array[j] > tmp )
                        array[j+1] = array[j];
                    else
                    {
                        array[j+1] = tmp;
                        break;
                    }
            }
            if(j == -1)
            array[j+1] = tmp;
        }
    }
}

/*
2-路插入排序

算法思想:增加一個輔助空間d,把r[1]賦值給d[1],並將d[1]看成是排好序後處於中間
          位置的記錄。然後從r[2]開始依次插入到d[1]之前或之後的有序序列中。

時間複雜度 o(n^2)

空間複雜度 o(1)

比較次數 n(n+1)/2
*/

void bi_insert_sort(int array[],int len)
{
    int* arr_d = (int *)malloc(sizeof(int) * len);

    arr_d[0] = array[0];
    int head = 0,tail = 0;
    for (int i = 1;i < len; i++ )
    {
        if (array[i] > arr_d[0])
        {
            int j;
            for ( j= tail;j>0;j--)
            {
                if (array[i] < arr_d[j])
                    arr_d[j+1] = arr_d[j];
                else
                    break;
            }
            arr_d[j+1] = array[i];
            tail += 1;
        }

        else
        {
            if (head ==0)
            {
                arr_d[len-1] = array[i];
                head =len-1;
            }
            else
            {
                int j;
                for (j = head;j <= len-1;j++)
                {
                    if (array[i] > arr_d[j])
                        arr_d[j-1] = arr_d[j];
                    else
                        break;
                }
                arr_d[j-1] = array[i];
                head -= 1;
            }
        }

    }

    for (int i = 0;i < len; i++)
    {
        int pos = (i + head );
        if(pos >= len) pos -= len;
        array[i] = arr_d[pos];
    }

    free(arr_d);
}

/*
希爾排序

算法思想:先將整個待排序記錄分割成若干子序列分別進行直接插入排
          序,待整個序列中的記錄基本有序時,再對全體記錄進行一
          次直接插入排序

時間複雜度 o(n^2)

空間複雜度 o(1)

比較次數 ?
*/

void shell_insert(int array[],int d,int len)
{
    int tmp,j;

    for (int i = d;i < len;i++)
    {
        if(array[i] < array[i-d])
        {
            tmp = array[i];
            j = i - d;
            do 
            {
                array[j+d] = array[j];
                j = j - d;
            } while (j >= 0 && tmp < array[j]);

            array[j+d] = tmp; 
        }
    }
}
void shell_sort(int array[],int len)
{
    int inc = len;

    do 
    {
        inc = inc/2;
        shell_insert(array,inc,len);
    } while (inc > 1);
}

/*
快速排序

算法思想:將原問題分解爲若干個規模更小但結構與原問題相似的子問題。遞
          歸地解這些子問題,然後將這些子問題的解組合成爲原問題的解。

時間複雜度 o(nlogn)

空間複雜度 o(logn)

比較次數  ?
*/

int partition(int array[],int low,int high)
{
    int  pivotkey = array[low];

    while (low < high)
    {
        while(low < high && array[high] >= pivotkey)
            --high;
        swap(array[low],array[high]);

        while(low < high && array[low] <= pivotkey)
            ++low;
        swap(array[low],array[high]);
    }

    array[low] = pivotkey;

    return low;
}

void quick_sort(int array[],int low,int high)
{
    if (low < high)
    {
        int pivotloc = partition(array,low,high);
        quick_sort(array,low,pivotloc-1);
        quick_sort(array,pivotloc+1,high);
    }
}

/*
直接選擇排序

算法思想:每一趟在n-i+1個記錄中選取關鍵字最小的記錄作爲有序序列中的第i個記錄

時間複雜度 o(n^2)

空間複雜度 o(1) ?

比較次數  n(n+1)/2
*/

int SelectMinKey(int array[],int iPos,int len)
{
    int ret = 0;

    for (int i = iPos; i < len; i++)
    {
        if (array[ret] > array[i])
        {
            ret = i;
        }
    }
    return ret;
}

void select_sort(int array[],int len)
{
    for (int i = 0; i < len; i++)
    {
        int j = SelectMinKey(array,i,len);
        if (i != j)
        {
            swap(array[i],array[j]);
        }
    }
}

/*
歸併排序

算法思想:設兩個有序的子文件(相當於輸入堆)放在同一向量中相鄰的位置上:R[low..m],R[m+1..high],先
          將它們合併到一個局部的暫存向量R1(相當於輸出堆)中,待合併完成後將R1複製回R[low..high]中。

時間複雜度 o(nlogn)

空間複雜度 o(n) 

比較次數  ?
*/

void merge(int array[],int i,int m, int n)
{
    int j,k;

    int iStart = i, iEnd = n;

    int arrayDest[256];

    for ( j = m + 1,k = i; i <= m && j <= n; ++k)
    {
        if (array[i] < array[j])
            arrayDest[k] = array[i++];
        else
            arrayDest[k] = array[j++];
    }

    if (i <= m)
        for (;k <= n; k++,i++)
            arrayDest[k] = array[i];
    if(j <= n)
        for (;k <= n; k++,j++)
            arrayDest[k] = array[j];

    for(j = iStart; j <= iEnd; j++)
        array[j] = arrayDest[j];
}

void merge_sort(int array[],int s,int t)
{
    int m;

    if (s < t) 
    {
        m = (s + t )/2;
        merge_sort(array,s,m);
        merge_sort(array,m+1,t);
        merge(array,s,m,t);
    }
}

/*
堆排序

算法思想:堆排序(Heap Sort)是指利用堆(heaps)這種數據結構來構造的一種排序算法。
          堆是一個近似完全二叉樹結構,並同時滿足堆屬性:即子節點的鍵值或索引總是
          小於(或者大於)它的父節點。
時間複雜度 o(nlogn)
空間複雜度 o(1) 
比較次數  較多
*/

void heap_adjust(int array[],int i,int len)
{
    int rc = array[i];

    for(int j = 2 * i; j <len; j *= 2)
    {
        if(j < len && array[j] < array[j+1]) j++;
        if(rc >= array[j]) break;

        array[i] = array[j]; i = j;
    }
    array[i] = rc;
}

void heap_sort(int array[],int len)
{
    int i;
    for(i = (len-1)/2; i >= 0; i--)
        heap_adjust(array,i,len);
    for(  i = (len-1); i > 0; i--)
    {
        swap(array[0],array[i]);   //彈出最大值,重新對i-1個元素建堆
        heap_adjust(array,0,i-1);
    }
}

int main() {

    int array[] = {45,56,76,234,1,34,23,2,3,55,88,100};

    int len = sizeof(array)/sizeof(int);

    //bubble_sort(array,len);           //冒泡排序

    /*insert_sort(array,len);*/         //插入排序

    /*bi_insert_sort(array,len);*/      //二路插入排序
    
    /*shell_sort(array,len);*/          //希爾排序 

    /*quick_sort(array,0,len-1);*/      //快速排序
    
    /*select_sort(array,len);*/         //選擇排序

    /*merge_sort(array,0,len-1);*/      //歸併排序
    
    heap_sort(array,len);               //堆排序
    display(array,len);

    return 0;
}


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章