Bootstrap

C 选择排序

#include <stdio.h>

void SelectionSort(int a[], size_t length) {
    for (size_t i = 0; i < length - 1; i++) {
        // 找出从当前位置到最后中的最小元素及其索引
        int min = a[i];
        int min_index = i;
        for (int j = i; j < length; j++) {
            if (min > a[j]) {
                min = a[j];
                min_index = j;
            }
        }
        // 将最小值放到当前段的首位
        int temp = a[i];
        a[i] = min;
        a[min_index] = temp;
    }
}

void Print(const int a[], size_t length) {
    for (size_t i = 0; i < length; i++) {
        printf("%d", a[i]);
        if (i < length - 1)
            printf(", ");
    }
    printf("\n");
}

int main(void) {
    int a[] = { 5,4,6,1,3,2 };
    size_t length = sizeof(a) / sizeof(a[0]);
    Print(a, length);
    SelectionSort(a, length);
    Print(a, length);

    return 0;
}

/* PSEUDO CODE
SELECTION-SORT(A)
for i = 1 to A.length - 1
    // 找出从当前位置到最后中的最小元素及其索引
    min = A[i]
    min_index = i
    for j = i to A.length
        if min > A[j]
            min = A[j]
            min_index = j
    // 将最小值放到当前段的首位
    temp = A[i]
    A[i] = min
    A[min_index] = temp
*/

/* OUTPUTS
5, 4, 6, 1, 3, 2
1, 2, 3, 4, 5, 6
*/

/* 排序过程
5, 4, 6, 1, 3, 2  // 原数组
1, 4, 6, 5, 3, 2  // i=0 迭代完成后, 1 与 5 交换了
1, 2, 6, 5, 3, 4  // i=1 迭代完成后, 2 与 4 交换了
1, 2, 3, 5, 6, 4  // i=2 迭代完成后, 3 与 6 交换了
1, 2, 3, 4, 6, 5  // i=3 迭代完成后, 4 与 5 交换了
1, 2, 3, 4, 5, 6  // i=4 迭代完成后, 5 与 6 交换了
数组有 6 个元素,但是只需完成 5 次迭代,数组就排好序了。
原因是当迭代到第 n-1 次时,要在其中找最小值的元素只剩两个,
所以完成这次迭代之后,这两个元素就排好序了,不需要再继续。
*/

/* 循环不变式
当完成每次迭代时,从开头到第 i 个元素这部分是排好序的;剩余元素不会小于前面的任意一个元素。
*/

/* 选择排序的执行时间分析
void SelectionSort(int a[], size_t length) {
    for (size_t i = 0; i < length - 1; i++) {    // c1, 1; c2, n; c3, n-1
        // 找出从当前位置到最后中的最小元素及其索引
        int min = a[i];                          // c4, n-1
        int min_index = i;                       // c5, n-1
        for (int j = i; j < length; j++) {       // c6, n-1; c7, ∑(n-i+1),i:0->n-2; c8, ∑(n-i),i:0->n-2
            if (min > a[j]) {                    // c9, ∑(n-i),i:0->n-2
                min = a[j];                      // c10, ∑(n-i),i:0->n-2
                min_index = j;                   // c11, ∑(n-i),i:0->n-2
            }
        }
        // 将最小值放到当前段的首位
        int temp = a[i];                         // c12, n-1
        a[i] = min;                              // c13, n-1
        a[min_index] = temp;                     // c14, n-1
    }
}

外层 for 循环头典型执行次数:
              // n=1                      // n=2                      // 
for(int i=0;  // 1                        // 1                        // c1, 1
        i<n;  // 2, 1 passed, 1 notpassed // 3, 2 passed, 1 notpassed // c2, n+1, n passed, 1 not passed
		i++)  // 1,                       // 2                        // c3, n

内层 for 循环头典型执行次数:
如果 j 从 0 开始,则 j<length 执行 n+1 次,j++ 执行 n 次
如果 j 从 1 开始,则 j<length 执行 n   次,j++ 执行 n-1 次
如果 j 从 2 开始,则 j<length 执行 n-1 次,j++ 执行 n-2 次
...
j<length 的执行次数是 n-i+1 次
j++      的执行次数是 n-i   次
其中 j 是从 i 到 n-1, i 是从 0 到 n-2

执行时间计算:
c1 + c2*n + c3*(n-1) + c4*(n-1) + c5*(n-1) + c6*(n-1) + c7*(n^2-n) + c8*(n^2-3n/2) + c9*(n^2-3n/2) + c10*(n^2-3n/2) + c11*(n^2-3n/2) + c12*(n-1) + c13*(n-1) + c14*(n-1)
c1 + c2*n + (c3+c4+c5+c6+c12+c13+c14)(n-1) + c7*n^2 - c7*n + c8*n^2 - c8*3n/2 + c9*n^2 - c9*3n/2 + c10*n^2 - c10*3n/2 + c11*n^2 - c11*3n/2
c1 + c2*n + (c3+c4+c5+c6+c12+c13+c14)n - (c3+c4+c5+c6+c12+c13+c14) + (c7+c8+c9+c10+c11)n^2 + (-c7-c8*3/2-c9*3/2-c10*3/2-c11*3/2)n
(c7+c8+c9+c10+c11)n^2 + (c2+c3+c4+c5+c6+c12+c13+c14-c7-c8*3/2-c9*3/2-c10*3/2-c11*3/2)n + c1 - (c3+c4+c5+c6+c12+c13+c14)
a*n^2 + b*n + c

结果:
执行时间是输入规模的二次函数。

最好情况:数组是已排好序的。这时,算式中要去掉 c10 和 c11 两行。其他不变。
最坏情况:数组是已反向排好序的。这时就是上面的计算。
*/

;