【算法与数据结构】分治策略与归并排序

分治策略

对于所求的问题域,每次将其分为大小相似的两部分,然后再把每一部分当作最初的问题域再次分割,依次递归,直到得到基本问题(递归基),求解。然后,再逐步合并直到完成最初的问题域。

通常用递归的方式分割问题,例如这里的归并排序,每次将数组一分为二,然后分别判断分割动作是否到不可再分割了(数组中仅剩最后一个元素),否则继续对左右两个子数组进行分割:

void merge_sort(int arr[], int lo, int hi) {
    if (lo + 1 >= hi) {
        return;
    }
    int mi = (hi + lo) / 2;
    merge_sort(arr, lo, mi);
    merge_sort(arr, mi, hi);
    merge(arr, lo, mi, hi);
}

归并排序的合并操作

每次要合并两个子数组时,同时判断两个数组的开头位置的元素大小,取小的元素,直到有一个数组为空时,把非空数组的所有元素复制过来:

void merge(int arr[], int lo, int mi, int hi) {
    if (lo + 1 == hi) {
        return;
    }
    // 原数组 lo 至 hi 之间的元素已经有序,分别复制出来到两个新数组
    int llen, rlen;
    int i, j, k;
    llen = mi - lo;
    rlen = hi - mi;
    int larr[llen];
    int rarr[rlen];
    for (i = 0; i < llen; i++) {
        larr[i] = arr[lo + i];
    }
    for (i = 0; i < rlen; i++) {
        rarr[i] = arr[mi + i];
    }
    // 依次判断两个新数组的开头元素,把小的放到原数组
    i = 0;
    j = 0;
    k = lo;
    while(i < llen && j < rlen) {
        if (larr[i] <= rarr[j]) {
            arr[k++] = larr[i++];
        } else {
            arr[k++] = rarr[j++];
        }
    }
    // 新数组有一个为空时,把另一个完整的复制到原数组
    while(i < llen) {
        arr[k++] = larr[i++];
    }
    while(j < rlen) {
        arr[k++] = rarr[j++];
    }
}

完整示例代码

#include <stdio.h>

void merge(int arr[], int lo, int mi, int hi) {
    if (lo + 1 == hi) {
        return;
    }
    int llen, rlen;
    int i, j, k;
    llen = mi - lo;
    rlen = hi - mi;
    int larr[llen];
    int rarr[rlen];
    for (i = 0; i < llen; i++) {
        larr[i] = arr[lo + i];
    }
    for (i = 0; i < rlen; i++) {
        rarr[i] = arr[mi + i];
    }
    i = 0;
    j = 0;
    k = lo;
    while(i < llen && j < rlen) {
        if (larr[i] <= rarr[j]) {
            arr[k++] = larr[i++];
        } else {
            arr[k++] = rarr[j++];
        }
    }
    while(i < llen) {
        arr[k++] = larr[i++];
    }
    while(j < rlen) {
        arr[k++] = rarr[j++];
    }
}

void merge_sort(int arr[], int lo, int hi) {
    if (lo + 1 >= hi) {
        return;
    }
    int mi = (hi + lo) / 2;
    merge_sort(arr, lo, mi);
    merge_sort(arr, mi, hi);
    merge(arr, lo, mi, hi);
}

int main(void) {
    int arr[] = {10, 9, 8, 7, 6, 5, 4, 3, 2, 1};
    int n = 10;
    int i;
    
    for (i = 0; i < n; i++) {
        printf("%4d", arr[i]);
    }
    printf("\n");
    merge_sort(arr, 0, n);
    
    for (i = 0; i < n; i++) {
        printf("%4d", arr[i]);
    }

    return 0;
}
发布了295 篇原创文章 · 获赞 158 · 访问量 101万+

猜你喜欢

转载自blog.csdn.net/kikajack/article/details/101616731