合并排序 | 分而治之

来源:互联网 发布:苹果手机主题软件 编辑:程序博客网 时间:2024/06/05 06:09

分治的设计思想

按我以前的一个老板的说法,就是“把它敲成一个一个小块,再逐块吃掉”。

敲,是一步;吃掉,是一步;整合,是另一步

参考下图:
图片来自网络

合并排序

用分治的套路,不断地递归,直到只有一个元素,也就是,只要元素个数大于1时就递归。

写代码实现时只需考虑把n个元素分成两部分,左右两部分分别递归合并排序,再把两部分合并(排序)。

图片来自网络

基础概念

  • 合并排序的重点在于合并,在合并时需要比较大小。
  • 合并的时间复杂度为O(n),因为只需要一个循环,把两部分(各自已经排好序)从小到大整合在一起即可。
  • 合并操作的两部分元素,肯定是连续的,所以只需要知道起始点、中间点与结束点(分成连续的两部分)。
  • 合并排序时间复杂度为O(nlgn),而且为稳定排序(最好与最坏的情况一样)。
  • 合并排序需要额外的空间来完成合并。

强化信息

  • 对于递归,只要考虑好当前层即可(最多把下一层也考虑上),因为当前层能保证有序,那其它层(同样的操作)也肯定可以保证有序。
  • 对递归,要有信心。
  • 以一种专业的心态去做事,未必是好的选择。有时候抽离成一个非专业人员,可能会更有利于思考。

#include <stdio.h>#include <stdlib.h>void merge(int* arr, int f, int m, int l, int* tmparr) {    int i=f, j=m+1;    int k=0;    while (i<=m && j<=l) {        if (arr[i] > arr[j]) {            tmparr[k++]=arr[j++];        }        else {            tmparr[k++]=arr[i++];        }    }    while (i<=m) {        tmparr[k++]=arr[i++];    }    while (j<=l) {        tmparr[k++]=arr[j++];    }    for (i=0; i<k; i++) {        arr[f++]=tmparr[i];    }}void _sort_merge(int* arr, int f, int l, int* tmparr) {    if (f < l) {        int m=(f+l)>>1;        _sort_merge(arr, f, m, tmparr);        _sort_merge(arr, m+1, l, tmparr);        merge(arr, f, m, l, tmparr);    }}void sort_merge(int* arr, int size) {    int* tmparr=(int*)malloc(sizeof(int) * size);    _sort_merge(arr, 0, size-1, tmparr);    free(tmparr);}int main(int argc, char *argv[]){    int arr[] = {4, 2, 5, 1, 6, 6, 8, 9, 8, 3};    int size=sizeof arr/sizeof *arr;    for (int i = 0; i < size; i ++) {        printf("%d, ", arr[i]);    }    sort_merge(arr, size);    printf("\nafter_sort:\n");    for (int i = 0; i < size; i ++) {        printf("%d, ", arr[i]);    }    printf("\n");    return 0;}

欢迎关注我们