算法竞赛——归并排序算法

算法竞赛——归并排序算法

分治法
划分问题:把序列分成元素个数尽量相等的两半
递归求解:把两半元素分别排序
合并问题:把两个有序表合并成一个

借鉴RuJia的精妙的合并过程

void merges2(int *a, int lef, int righ) {
    // 递归边界
    if(lef == righ) {
        return ;
    }

    // 取中值
    int center = lef + (righ - lef) / 2;

    // 递归左半
    merges2(a, lef, center);
    // 递归右半
    merges2(a, center + 1, righ);

    // 合并左半和右半
    // 该大小为左半右半大小之和
    int totalSize = righ - lef + 1;
    int tmp[totalSize];
    int n = lef;
    int m = center + 1;
    int i = 0;
    // 左半右半其一不为空
    while(n <= center || m <= righ) {
        // 右半为空 或者 左半不为空且左半值小于右半值
        if(m > righ || (n <= center && a[n] <= a[m])) {
            // 从左半数组复制到临时空间
            tmp[i++] = a[n++];
        } else {
            // 从右半数组复制到临时空间
            tmp[i++] = a[m++];
        }
    }

    n = lef;
    // 将临时数组的值放入原数组
    for(int i = 0; i < totalSize; i++) {
        a[n++] = tmp[i];
    }
}

自己写的,合并过程没那么精妙,但是非常直观

void merges(int *a, int lef, int righ) {
    // 递归边界
    if(lef == righ) {
        return ;
    }

    // 取中值
    int center = lef + (righ - lef) / 2;

    // 递归左半
    merges(a, lef, center);
    // 递归右半
    merges(a, center + 1, righ);

    // 合并左半和右半
    // 该大小为左半右半大小之和
    int totalSize = righ - lef + 1;
    int tmp[totalSize];
    int n = lef;
    int m = center + 1;
    int i;
    for(i = 0; i < totalSize; i++) {
        // 左半为空,或右半为空
        if(n > center || m > righ) {
            break;
        }
        // 左边的值
        int leftV = a[n];
        // 右边的值
        int rightV = a[m];
        if(leftV <= rightV) {
            tmp[i] = leftV;
            n++;
        } else {
            tmp[i] = rightV;
            m++;
        }
    }
    // 如果左半不为空
    for(int j = n; j <= center; j++) {
        tmp[i++] = a[j];
    }

    // 如果右半不为空
    for(int j = m; j <= righ; j++) {
        tmp[i++] = a[j];
    }

    n = lef;
    // 将临时数组的值放入原数组
    for(int i = 0; i < totalSize; i++) {
        a[n++] = tmp[i];
    }
}

测试主程序

#include <iostream>

using namespace std;

// 归并排序
// 分治法
// 划分问题:把序列分成元素个数尽量相等的两半
// 递归求解:把两半元素分别排序
// 合并问题:把两个有序表合并成一个
void merges(int *a, int lef, int righ) {
    // 递归边界
    if(lef == righ) {
        return ;
    }

    // 取中值
    int center = lef + (righ - lef) / 2;

    // 递归左半
    merges(a, lef, center);
    // 递归右半
    merges(a, center + 1, righ);

    // 合并左半和右半
    // 该大小为左半右半大小之和
    int totalSize = righ - lef + 1;
    int tmp[totalSize];
    int n = lef;
    int m = center + 1;
    int i;
    for(i = 0; i < totalSize; i++) {
        // 左半为空,或右半为空
        if(n > center || m > righ) {
            break;
        }
        // 左边的值
        int leftV = a[n];
        // 右边的值
        int rightV = a[m];
        if(leftV <= rightV) {
            tmp[i] = leftV;
            n++;
        } else {
            tmp[i] = rightV;
            m++;
        }
    }
    // 如果左半不为空
    for(int j = n; j <= center; j++) {
        tmp[i++] = a[j];
    }

    // 如果右半不为空
    for(int j = m; j <= righ; j++) {
        tmp[i++] = a[j];
    }

    n = lef;
    // 将临时数组的值放入原数组
    for(int i = 0; i < totalSize; i++) {
        a[n++] = tmp[i];
    }
}


void merges2(int *a, int lef, int righ) {
    // 递归边界
    if(lef == righ) {
        return ;
    }

    // 取中值
    int center = lef + (righ - lef) / 2;

    // 递归左半
    merges2(a, lef, center);
    // 递归右半
    merges2(a, center + 1, righ);

    // 合并左半和右半
    // 该大小为左半右半大小之和
    int totalSize = righ - lef + 1;
    int tmp[totalSize];
    int n = lef;
    int m = center + 1;
    int i = 0;
    // 左半右半其一不为空
    while(n <= center || m <= righ) {
        // 右半为空 或者 左半不为空且左半值小于右半值
        if(m > righ || (n <= center && a[n] <= a[m])) {
            // 从左半数组复制到临时空间
            tmp[i++] = a[n++];
        } else {
            // 从右半数组复制到临时空间
            tmp[i++] = a[m++];
        }
    }

    n = lef;
    // 将临时数组的值放入原数组
    for(int i = 0; i < totalSize; i++) {
        a[n++] = tmp[i];
    }
}


void mergeSort(int *a, int n) {
// merges(a, 0, n - 1);
    merges(a, 0, n - 1);
}

int main() {
    int a[] = {-1, 3, 3, 5, 5, 41, 5435, -11, 3423, 4432, -4421, 34432};
    int n =12;
    cout << "排序前: ";
    for(int i = 0; i < n; i++) {
        cout << a[i] << " ";
    }
    cout << endl;

    mergeSort(a, n);

    cout << "排序后: ";
    for(int i = 0; i < n; i++) {
        cout << a[i] << " ";
    }
    cout << endl;


    return 0;
}

输出结果

排序前: -1 3 3 5 5 41 5435 -11 3423 4432 -4421 34432
排序后: -4421 -11 -1 3 3 5 5 41 3423 4432 5435 34432

Process returned 0 (0x0)   execution time : 0.177 s
Press any key to continue.

你可能感兴趣的:(算法,归并排序,ACM,算法竞赛)