八大排序算法

八大排序算法_第1张图片

【冒泡排序】

 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\n" : "%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\n" : "%2d ", A[i]);
23         }
24         //printf("\n");
25     }
26 }

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

希尔排序步骤:

八大排序算法_第2张图片

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

 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\n", 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合并两个有序数组的调用次序:

八大排序算法_第3张图片

八大排序算法_第4张图片

【基数排序】

 


 

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

测试结果:

八大排序算法_第5张图片

排序算法的比较:

八大排序算法_第6张图片

你可能感兴趣的:(排序算法)