• 八大排序算法


    【冒泡排序】

     1 void Bubble_sort(int A[], int N)
     2 {
     3     int i, P;
     4     int flag;
     5 
     6     for(P = N-1; P >= 0; P--)
     7     {
     8         flag = 0;
     9         for(i = 0; i < P; i++) /* 一趟 */
    10         {
    11             if(A[i] > A[i+1])
    12             {
    13                 swap(&A[i], &A[i+1]);
    14                 flag = 1;
    15             }
    16         }
    17         if(flag == 0)   break; /* 全程无交换 */
    18     }
    19 }

    【快速排序】

     1 int quick_partition(int a[], int left, int right)
     2 {
     3     int tmp;
     4     int mid = (left + right) / 2;
     5     
     6     if(a[left] > a[mid])
     7         swap(&a[left], &a[mid]);
     8     if(a[left] > a[right])
     9         swap(&a[left], &a[right]);
    10     if(a[mid] > a[right])
    11         swap(&a[mid], &a[right]);
    12     swap(&a[left], &a[mid]);
    13     
    14     tmp = a[left]; // 取中位数作为第一个坑
    15     
    16     while(left < right)
    17     {
    18         while(left < right && a[right] >= tmp)
    19             right--;
    20         if(left < right)
    21             a[left++] = a[right]; // 挖坑right, 填坑left
    22 
    23         while(left < right && a[left] <= tmp)
    24             left++;
    25         if(left < right)
    26             a[right--] = a[left]; // 挖坑left, 填坑right
    27     }
    28     a[left] = tmp;
    29 
    30     return left;
    31 }
    32 
    33 void quick_sort(int a[], int left, int right)
    34 {
    35     int pivot;
    36     if(left < right)
    37     {
    38         pivot = quick_partition(a, left, right);
    39         quick_sort(a, left, pivot-1);
    40         quick_sort(a, pivot+1, right);
    41     }
    42 }
    43 
    44 void Quick_sort(int A[], int N)
    45 {
    46     quick_sort(A, 0, N-1);
    47 }

    【直接插入排序】

     1 void Insertion_sort(int A[], int N)
     2 {
     3     int i, P;
     4     int tmp;
     5 
     6     for(P = 1; P < N; P++)
     7     {
     8         tmp = A[P]; /* 摸下一张牌 */
     9         for(i = P; i > 0 && A[i-1] > tmp; i--)
    10         {
    11             A[i] = A[i-1]; /* 移出空位 */
    12         }
    13 
    14         A[i] = tmp; /* 新牌落位 */
    15     }
    16 }

     【希尔排序】

    希尔排序的实质就是分组插入排序,又称为缩小增量排序。

    该方法的基本思想是:先将整个待排元素序列分割成若干个子序列(由相隔某个“增量”的元素组成)分别进行直接插入排序,然后依次缩减增量再进行排序,待整个序列中的元素基本有序(增量足够小)时,再对全体元素进行一次直接插入排序。因为直接插入排序在元素基本有效的情况下(接近最好情况),效率是很高的,因此希尔排序在时间效率上比直接插入排序有较大提高。

     1 void Shell_sort(int A[], int N)
     2 {
     3     int D, P;
     4     int i, tmp;
     5 
     6     //printf("xxx,xxx : ");
     7     //for(i = 0; i < N; i++)
     8     //    printf(i == N-1 ? "%2d
    " : "%2d ", A[i]);
     9 
    10     for(D = N/2; D > 0; D /= 2) /* 希尔增量序列 */
    11     {
    12         for(P = D; P < N; P++) /* 插入排序 */
    13         {
    14             tmp = A[P];
    15             // 按照增量序列插入 
    16             for(i = P; i >= D && A[i-D] > tmp; i -= D)
    17                 A[i] = A[i-D];
    18             A[i] = tmp;
    19 
    20             //printf("D=%d,P=%d : ", D, P);
    21             //for(i = 0; i < N; i++)
    22             //    printf(i == N-1 ? "%2d
    " : "%2d ", A[i]);
    23         }
    24         //printf("
    ");
    25     }
    26 }

    逆序序列:10,9,8,7,6,5,4,3,2,1

    希尔排序步骤:

    按照自定义增量序列进行的希尔排序:

     1 // 一趟按照增量D进行的插入排序
     2 void shell_insert(int A[], int N, int D)
     3 {
     4     int i, P;
     5     int tmp; 
     6 
     7     for(P = D; P < N; P++)
     8     {
     9         tmp = A[P];
    10         for(i = P; i >= D && A[i-D] > tmp; i -= D)
    11             A[i] = A[i-D];
    12         A[i] = tmp;
    13     }
    14 }
    15 
    16 void Shell_sort(int A[], int N)
    17 {
    18     int D[] = {9, 5, 3, 1}; // 自定义增量序列
    19     int i;
    20     for(i = 0; i < sizeof(D)/sizeof(D[0]); i++)
    21         shell_insert(A, N, D[i]);
    22 }

     【简单选择排序】

    首先,选出数组中最小的元素,将它与数组中第一个元素进行交换。然后找出次小的元素,并将它与数组的第二个元素进行交换。按照这种方法一直进行下去,直到整个数组排完序。它是通过不断选出剩余元素中最小元素来实现的。

    选择排序有一个缺点,它的运行时间对文件中已有序的部分依赖较少。从文件中选出最小元素的每遍操作过程,并没有给出下一遍要找的最小元素的位置的相关信息。因此,该程序对已排好的文件或各元素都相同的文件排序所花的时间与对随机排序的文件排序所花的时间基本相同。

     1 void Selection_sort(int A[], int N)
     2 {
     3     int i, j, tmp;
     4     int min;
     5 
     6     for(i = 0; i < N-1; i++)
     7     {
     8         min = i;
     9         for(j = i+1; j < N; j++)
    10         {
    11             if(A[min] > A[j])
    12                 min = j;
    13         }
    14         if(min != i)
    15         {
    16             swap(&A[min], &A[i]);
    17         }
    18     }
    19 }

    选择排序的另一种写法:

     1 int ScanForMin(int A[], int start, int end)
     2 {
     3     int i, min;
     4     min = start;
     5     for(i = start+1; i <= end; i++)
     6     {
     7         if(A[min] > A[i])
     8             min = i;
     9     }
    10     return min;
    11 }
    12 
    13 void Selection_sort_x(int A[], int N)
    14 {
    15     int i, MinPosition;
    16 
    17     for(i = 0; i < N; i++)
    18     {
    19         // 从A[i]到A[N-1]中找到最小元素,并将其位置赋给MinPosition
    20         MinPosition = ScanForMin(A, i, N-1);
    21         // 将未排序部分的最小元素换到有序部分的最后位置
    22         swap(&A[i], &A[MinPosition]);
    23     }
    24 }

    从以上的思路中考虑,如何快速找到最小元素,是提高效率的方法。

    【堆排序】

     1 void perc_down(int a[], int i, int n) // i:下标号从0开始, n:结点总数
     2 {
     3     int child;
     4     int tmp;
     5     for(tmp = a[i]; (i+1)*2 <= n; i = child) // (i+1)*2<=n: 至少有一个孩子
     6     {
     7         child = i * 2 + 1;
     8         // child != n-1 : 该结点还有右孩子
     9         if((child != n-1) && (a[child+1] > a[child]))
    10             child++;
    11 
    12         // 已取得左右儿子中较大的那个
    13         if(tmp < a[child])
    14             a[i] = a[child];
    15         else
    16             break;
    17     }
    18     a[i] = tmp;
    19 }
    20 void Heap_sort(int A[], int N)
    21 {
    22     int i;
    23 
    24     for(i = N/2-1; i >= 0; i--) /* build heap */
    25         perc_down(A, i, N);
    26 
    27     for(i = N; i >= 2; i--)
    28     {
    29         swap(&A[0], &A[i-1]); /* delete max */
    30         perc_down(A, 0, i-1);
    31     }
    32 }

    【归并排序】

    // 有序子列的归并
    // L : 左边起始位置
    // R : 右边起始位置
    // RightEnd: 右边终点位置
    void Merge(int A[], int TmpA[], int L, int R, int RightEnd)
    {
        int i;
        int LeftEnd = R - 1; // 左边终点位置,假设左右两列挨着
        int Tmp = L; // 存放结果的数组的初始位置
        int NumElements = RightEnd - L + 1;
        static int iCnt = 1;
    
        //printf("Merge<%02d> : L=%2d, R=%2d, RightEnd=%2d : ", iCnt++, L, R, RightEnd);
    
        while(L <= LeftEnd && R <= RightEnd)
        {
            if(A[L] <= A[R])
                TmpA[Tmp++] = A[L++];
            else
                TmpA[Tmp++] = A[R++];
        }
        while(L <= LeftEnd)
            TmpA[Tmp++] = A[L++];
        while(R <= RightEnd)
            TmpA[Tmp++] = A[R++];
    
        // 把TmpA数组中的数据拷贝到原数组A中,TmpA只做临时空间使用
        for(i = 0; i < NumElements; i++, RightEnd--)
            A[RightEnd] = TmpA[RightEnd];
    }
    
    void MSort(int A[], int TmpA[], int L, int RightEnd)
    {
        int Center;
        
        //printf("Msort: L=%d, RightEnd:%d
    ", L, RightEnd);
        if(L < RightEnd)
        {
            Center = (L + RightEnd) / 2;
            MSort(A, TmpA, L, Center);
            MSort(A, TmpA, Center+1, RightEnd);
            Merge(A, TmpA, L, Center+1, RightEnd);
        }
    }
    
    void Merge_sort(int A[], int N)
    {
        int i;
        int *TmpA;
        TmpA = malloc(N * sizeof(int));
        if(TmpA != NULL)
        {
            MSort(A, TmpA, 0, N-1);
            free(TmpA);
        }
    }

    Merge合并两个有序数组的调用次序:

    【基数排序】


    PAT练习提交代码】:

      1 #include <stdio.h>
      2 #include <string.h>
      3 #include <stdlib.h>
      4 
      5 void swap(int *a, int *b)
      6 {
      7     int tmp;
      8     tmp = *a;
      9     *a  = *b;
     10     *b  = tmp;
     11 }
     12 // TODO: 1
     13 void Bubble_sort(int A[], int N)
     14 {
     15     int i, P;
     16     int flag;
     17 
     18     for(P = N-1; P >= 0; P--)
     19     {
     20         flag = 0;
     21         for(i = 0; i < P; i++) /* 一趟 */
     22         {
     23             if(A[i] > A[i+1])
     24             {
     25                 swap(&A[i], &A[i+1]);
     26                 flag = 1;
     27             }
     28         }
     29         if(flag == 0)   break; /* 全程无交换 */
     30     }
     31 }
     32 
     33 // TODO: 2
     34 int quick_partition(int a[], int left, int right)
     35 {
     36     int tmp;
     37     int mid = (left + right) / 2;
     38     
     39     if(a[left] > a[mid])
     40         swap(&a[left], &a[mid]);
     41     if(a[left] > a[right])
     42         swap(&a[left], &a[right]);
     43     if(a[mid] > a[right])
     44         swap(&a[mid], &a[right]);
     45     swap(&a[left], &a[mid]);
     46     
     47     tmp = a[left]; // 取中位数作为第一个坑
     48     
     49     while(left < right)
     50     {
     51         while(left < right && a[right] >= tmp)
     52             right--;
     53         if(left < right)
     54             a[left++] = a[right]; // 挖坑right, 填坑left
     55 
     56         while(left < right && a[left] <= tmp)
     57             left++;
     58         if(left < right)
     59             a[right++] = a[left]; // 挖坑left, 填坑right
     60     }
     61     a[left] = tmp;
     62 
     63     return left;
     64 }
     65 
     66 void quick_sort(int a[], int left, int right)
     67 {
     68     int pivot;
     69     if(left < right)
     70     {
     71         pivot = quick_partition(a, left, right);
     72         quick_sort(a, left, pivot-1);
     73         quick_sort(a, pivot+1, right);
     74     }
     75 }
     76 
     77 void Quick_sort(int A[], int N)
     78 {
     79     quick_sort(A, 0, N-1);
     80 }
     81 
     82 // TODO: 3
     83 void Selection_sort(int A[], int N)
     84 {
     85     int i, j, min;
     86 
     87     for(i = 0; i < N-1; i++)
     88     {
     89         min = i;
     90         for(j = i+1; j < N; j++)
     91         {
     92             if(A[min] > A[j])
     93                 min = j;
     94         }
     95         if(min != i)
     96         {
     97             swap(&A[min], &A[i]);
     98         }
     99     }
    100 }
    101 
    102 int ScanForMin(int A[], int start, int end)
    103 {
    104     int i, min;
    105     min = start;
    106     for(i = start+1; i <= end; i++)
    107     {
    108         if(A[min] > A[i])
    109             min = i;
    110     }
    111     return min;
    112 }
    113 
    114 void Selection_sort_x(int A[], int N)
    115 {
    116     int i, MinPosition;
    117 
    118     for(i = 0; i < N; i++)
    119     {
    120         // 从A[i]到A[N-1]中找到最小元素,并将其位置赋给MinPosition
    121         MinPosition = ScanForMin(A, i, N-1);
    122         // 将未排序部分的最小元素换到有序部分的最后位置
    123         swap(&A[i], &A[MinPosition]);
    124     }
    125 }
    126 // TODO: 4
    127 // 下标从0开始的堆排序
    128 void perc_down(int a[], int i, int n) // i:下标号从0开始, n:结点总数
    129 {
    130     int child;
    131     int tmp;
    132     for(tmp = a[i]; (i+1)*2 <= n; i = child) // (i+1)*2<=n: 至少有一个孩子
    133     {
    134         child = i * 2 + 1;
    135         // child != n-1 : 该结点还有右孩子
    136         if((child != n-1) && (a[child+1] > a[child]))
    137             child++;
    138 
    139         // 已取得左右儿子中较大的那个
    140         if(tmp < a[child])
    141             a[i] = a[child];
    142         else
    143             break;
    144     }
    145     a[i] = tmp;
    146 }
    147 void Heap_sort(int A[], int N)
    148 {
    149     int i;
    150 
    151     for(i = N/2-1; i >= 0; i--) /* build heap */
    152         perc_down(A, i, N);
    153 
    154     for(i = N; i >= 2; i--)
    155     {
    156         swap(&A[0], &A[i-1]); /* delete max */
    157         perc_down(A, 0, i-1);
    158     }
    159 }
    160 
    161 // TODO: 4
    162 // 下标从1开始的堆排序
    163 void perc_down_1(int a[], int i, int n) // n : 结点总数
    164 {
    165     int child;
    166     int tmp;
    167     for(tmp = a[i]; i*2 <= n; i = child)
    168     {
    169         child = i * 2;
    170         // child != n : 即可得该结点还有右孩子
    171         if((child != n) && (a[child+1] > a[child]))
    172             child++;
    173         // 已取得左右儿子中较大的那个
    174         if(tmp < a[child])
    175             a[i] = a[child];
    176         else
    177             break;
    178     }
    179     a[i] = tmp;
    180 }
    181 void Heap_sort_1(int A[], int N)
    182 {
    183     int i;
    184 
    185     for(i = N/2; i > 0; i--) /* build heap */
    186         perc_down_1(A, i, N);
    187 
    188     /* after build heap */
    189 
    190     for(i = N; i >= 2; i--)
    191     {
    192         swap(&A[1], &A[i]); /* delete max */
    193         perc_down_1(A, 1, i-1);
    194     }
    195 }
    196 
    197 // TODO: 5
    198 void Insertion_sort(int A[], int N)
    199 {
    200     int i, P;
    201     int tmp;
    202 
    203     for(P = 1; P < N; P++)
    204     {
    205         tmp = A[P]; /* 摸下一张牌 */
    206         for(i = P; i > 0 && A[i-1] > tmp; i--)
    207         {
    208             A[i] = A[i-1]; /* 移出空位 */
    209         }
    210 
    211         A[i] = tmp; /* 新牌落位 */
    212     }
    213 }
    214 
    215 // TODO: 6
    216 void Shell_sort(int A[], int N)
    217 {
    218     int D, P;
    219     int i, tmp;
    220 
    221     for(D = N/2; D > 0; D /= 2) /* 希尔增量序列 */
    222     {
    223         for(P = D; P < N; P++) /* 插入排序 */
    224         {
    225             tmp = A[P];
    226             // 按照增量序列插入 
    227             for(i = P; i >= D && A[i-D] > tmp; i -= D)
    228                 A[i] = A[i-D];
    229             A[i] = tmp;
    230         }
    231     }
    232 }
    233 
    234 // 一趟按照增量D进行的插入排序
    235 void shell_insert(int A[], int N, int D)
    236 {
    237     int i, P;
    238     int tmp; 
    239 
    240     for(P = D; P < N; P++)
    241     {
    242         tmp = A[P];
    243         // 以增量D插入
    244         for(i = P; i >= D && A[i-D] > tmp; i -= D)
    245             A[i] = A[i-D];
    246         A[i] = tmp;
    247     }
    248 }
    249 
    250 void Shell_sort_x(int A[], int N)
    251 {
    252     int D[] = {109, 41, 19, 5, 1}; // 自定义增量序列
    253     //int D[] = {9, 5, 3, 1};
    254     int i;
    255     for(i = 0; i < sizeof(D)/sizeof(D[0]); i++)
    256         shell_insert(A, N, D[i]);
    257 }
    258 
    259 // TODO: 7
    260 // 有序子列的归并
    261 // L : 左边起始位置
    262 // R : 右边起始位置
    263 // RightEnd: 右边终点位置
    264 void Merge(int A[], int TmpA[], int L, int R, int RightEnd)
    265 {
    266     int i;
    267     int LeftEnd = R - 1; // 左边终点位置,假设左右两列挨着
    268     int Tmp = L; // 存放结果的数组的初始位置
    269     int NumElements = RightEnd - L + 1;
    270 
    271     while(L <= LeftEnd && R <= RightEnd)
    272     {
    273         if(A[L] <= A[R])
    274             TmpA[Tmp++] = A[L++];
    275         else
    276             TmpA[Tmp++] = A[R++];
    277     }
    278     while(L <= LeftEnd)
    279         TmpA[Tmp++] = A[L++];
    280     while(R <= RightEnd)
    281         TmpA[Tmp++] = A[R++];
    282 
    283     // 把TmpA数组中的数据拷贝到原数组A中,TmpA只做临时空间使用
    284     for(i = 0; i < NumElements; i++, RightEnd--)
    285         A[RightEnd] = TmpA[RightEnd];
    286 }
    287 
    288 void MSort(int A[], int TmpA[], int L, int RightEnd)
    289 {
    290     int Center;
    291     
    292     if(L < RightEnd)
    293     {
    294         Center = (L + RightEnd) / 2;
    295         MSort(A, TmpA, L, Center);
    296         MSort(A, TmpA, Center+1, RightEnd);
    297         Merge(A, TmpA, L, Center+1, RightEnd);
    298     }
    299 }
    300 // 归并排序的递归算法
    301 void Merge_sort(int A[], int N)
    302 {
    303     int *TmpA;
    304     TmpA = malloc(N * sizeof(int));
    305     if(TmpA != NULL)
    306     {
    307         MSort(A, TmpA, 0, N-1);
    308         free(TmpA);
    309     }
    310 }
    311 
    312 // 归并排序的非递归算法
    313 void Merge_sort_x(int A[], int N)
    314 {
    315 
    316 }
    317 
    318 // TODO: 8
    319 void Radix_sort(int A[], int N)
    320 {
    321 
    322 }
    323 
    324 /*********************************************************/
    325 int main(void)
    326 {
    327     int i, N;
    328     int A[100000];
    329     
    330     scanf("%d", &N);
    331     for(i = 0; i < N; i++)
    332         scanf("%d", &A[i]);
    333     
    334 //    Bubble_sort(A, N);
    335     Quick_sort(A, N);
    336 //    Selection_sort(A, N);
    337 //    Heap_sort(A, N);
    338 //    Insertion_sort(A, N);
    339 //    Shell_sort(A, N);
    340 //      Shell_sort_x(A, N);
    341 //    Merge_sort(A, N);
    342 //    Radix_sort(A, N);
    343         
    344     for(i = 0; i < N; i++)
    345         printf(i == N-1 ? "%d" : "%d ", A[i]);
    346     
    347     return 0;
    348 }
    View Code

    测试结果:

    排序算法的比较:

  • 相关阅读:
    angular2+ 使用ant.design 的 select组件时(nz-select)下拉框没有脱离文档流,直接撑开页面展示的问题
    element 获取table组件的下标
    调幅调频调相位
    Mongoose基于MongoDB建模并设置关联
    Xavier上TensorRT和Pytorch运行时间对比
    理解vue实例的生命周期和钩子函数
    [Vue]组件——.sync 修饰符实现对prop 进行“双向绑定”(子组件向父组件传值)
    vm.$attrs 【Vue 2.4.0新增inheritAttrs,attrs详解】
    (转)vue v-on修饰符
    Vue中的computed属性
  • 原文地址:https://www.cnblogs.com/utank/p/4308512.html
Copyright © 2020-2023  润新知