• 归并排序


      #返回上一级

    @Author: 张海拔

    @Update: 2014-01-14

    @Link: http://www.cnblogs.com/zhanghaiba/p/3518324.html

     1 /*
     2  *Author: ZhangHaiba
     3  *Date: 2014-1-13
     4  *FIle: merge_sort.c
     5  *
     6  *merge sort demo
     7  */
     8 
     9 #include <stdio.h>
    10 #define N 512
    11 #define INF 0x7fffffff //sentinel
    12 
    13 void merge_sort(int *, int, int);
    14 void set_array(int *, int);
    15 void show_array(int *, int);
    16 
    17 int array[N];
    18 int left_tmp[N/2 + 10]; //save INF to a[array_len] as sentinel
    19 int right_tmp[N/2 + 10];
    20 
    21 int main(void)
    22 {
    23     int n;
    24 
    25     scanf("%d", &n);
    26     set_array(array, n);
    27     merge_sort(array, 0, n-1);
    28     show_array(array, n);
    29     return 0;
    30 }
    31 
    32 
    33 void merge_sort(int *a, int l, int r)
    34 {
    35     if (l >= r) return;
    36     else {
    37         int m = l + (r-l)/2; //partition
    38         merge_sort(a, l, m);
    39         merge_sort(a, m+1, r);
    40         int left_len = m-l+1, right_len = r-m, i, j = l;
    41         for (i = 0; i < left_len; ++i, ++j)
    42             left_tmp[i] = a[j];
    43         left_tmp[i] = INF;
    44         for (i = 0; i < right_len; ++i, ++j)
    45             right_tmp[i] = a[j];
    46         right_tmp[i] = INF;
    47         for (i = j = 0; l <= r; ++l) //merge order list    
    48             a[l] = left_tmp[i] <= right_tmp[j] ? left_tmp[i++] : right_tmp[j++];
    49     }
    50 }
    51 
    52 void set_array(int *a, int n)
    53 {
    54     int i;
    55 
    56     for (i = 0; i < n; ++i)
    57         scanf("%d", a+i);
    58 }
    59 
    60 
    61 void show_array(int *a, int n)
    62 {
    63     int i;
    64 
    65     for (i = 0; i < n; ++i)
    66         printf(i == n-1 ? "%d
    " : "%d ", a[i]);
    67 }

    归并排序,是分治法的典范。

    如果你理解了二叉树的前序遍历和后序遍历,就不难写出归并排序。

    归并和快排一样,有一个划分过程。不过这里的归并完全是二分的。划分在前序遍历过程中(边划分边处理子数组),而归并体现在后序遍历过程中。

    归并过程:首先复制左右子数组分别放在left_tmp和right_tmp数组中,然后通过有序表的合并算法放回根数组[l, r]中。

    显然归并过程是从叶子数组开始的(回溯开始于前进的结束),而叶子数组只有一个元素,必定是有序的。所以说归并的过程核心是有序表的合并算法。

    有序表的合并算法其时间复杂度显然是O(n),从整个二分归并树来看,横向看子数组的连起来的长度肯定是n,纵向看树高为lgn。

    所以算法的时间复杂度相当稳定,就是O(n*lgn)。

    上述实现中,注意:

    (1)引入INF存入临时数组有效数据的下一个位置作为哨兵,这样方便简单实现有序表合并算法,因此临时数组长度应该略大于N/2,防止极端情况数组越界。

    (2)归并排序一大特征就是:该算法是稳定的。所以在有序表合并时,注意要用"<="而非"<",这样才能确保相同关键字排序后相对前后位置不会改变。

      #返回上一级

  • 相关阅读:
    vue-cli 中stylus写样式莫名报错?
    Github桌面端安装慢问题
    firefox无法使用yslow的解决方案
    vue安装找不到命令
    css解惑
    vs2015中ctrl+shift+F进行“在文件中查找”,有时候无效?
    WebStrom安装了angularjs插件,但是没有语法提示
    jq版本更新后无live函数的处理.
    word每次打开都要选择文档类型
    百度编辑器1.4.3 .net版在vs2008的使用方法
  • 原文地址:https://www.cnblogs.com/zhanghaiba/p/3518324.html
Copyright © 2020-2023  润新知