zoukankan      html  css  js  c++  java
  • 算法学习记录-排序——归并排序

    归并排序

      利用了完全二叉树的堆排序在效率上提高了不少。但是堆排序主要耗费时间在调整堆上,算法效率也不够稳定。

    对于二叉树的应用,还有没有其他方法能够保持算法的效率,也能够使其是一个稳定的算法。(堆排序不够稳定)

    具体效率可以查看《算法导论》、《数据结构与算法》(严蔚敏)

      想想二叉树的结构,如果我们比较两个数,我们想想将两个树作为叶子,比较结果存放在根中。

    如果是四个数呢?

    四个数分别为四个叶子,通过两两比较形成一个小集合,然后小集合再比较最后形成最终的结果。

    这就是归并的思想。开始不理解为什么叫归并,后来看到有人写过:

    先递分解,再合成数组

    归并算法用了 分治法(Divide and Conquer)的一个非常典型的应用。值得注意的是归并排序是一种稳定的排序方法。(算法比较稳定)

     

    理解了,代码就好写了。

    两个关键:

    分解数组mergeDiv

    合并数组mergeIn

    看上图分解,我们以左边 9 1为例,最终分解为 9  和 1结点后再开始排序,

    mergeDiv(左) 得到的起始序号是0,终止序号是0,得到实际的数==> 9

    mergeDiv(右) 得到的起始序号是1,终止序号是1,得到实际的数==> 1

    mergeIn(左右)排序,返回==> 1 9

    想想在二叉树一章,这有点像后续遍历

    对于 19 5

    mergeDiv(左) 得到的起始序号是0,终止序号是1,得到实际序列==>1 9(之前已经排好了)

    mergeDiv(右) 得到的起始序号是2,终止序号是2,得到实际序列==>2

    mergeIn(左右)  对上面两个序列 起始0,中间1,终止2 返回  ==>1 2 9 

    依次类推。。。

    代码:

     1 void mergeIn(myDataType *ary,int s,int m,int e)
     2 {
     3     int i,j;
     4     int len1 = (m-s)+1;
     5     int len2 = e-m;
     6 
     7     myDataType *list1 = (myDataType *)malloc(sizeof(myDataType)*len1);
     8     myDataType *list2 = (myDataType *)malloc(sizeof(myDataType)*len2);
     9     
    10     for (i=0;i<len1;i++)
    11     {
    12         list1[i] = ary[s+i];
    13     }
    14 
    15     for (i=0;i<len2;i++)
    16     {
    17         list2[i] = ary[m+1+i];
    18     }
    19 
    20     i=0;
    21     j=0;
    22     while(i < len1 && j < len2)
    23     {
    24         if (list1[i] >= list2[j])
    25         {
    26             ary[s+i+j] = list2[j];
    27             j++;
    28         }
    29         else
    30         {
    31             ary[s+i+j] = list1[i];
    32             i++;
    33         }
    34     }
    35     while(i<len1)
    36     {
    37         ary[s+i+j] = list1[i];
    38         i++;
    39     }
    40     while(j<len2)
    41     {
    42         ary[s+i+j] = list2[j];
    43         j++;
    44     }
    45 
    46 }
    47 
    48 void mergeDiv(myDataType *ary,int sIdx,int eIdx)
    49 {
    50     if (sIdx >= eIdx)
    51     {
    52         return ;
    53     }
    54     int mid = (sIdx+eIdx)/2;
    55 
    56     mergeDiv(ary,sIdx,mid);
    57     mergeDiv(ary,mid+1,eIdx);
    58     //printf("s=%d,mid=%d,e=%d
    ",sIdx,mid,eIdx);
    59     mergeIn(ary,sIdx,mid,eIdx);
    60 }
    61 
    62 
    63 
    64 void mergeSort(myDataType *ary,int len)
    65 {
    66     mergeDiv(ary,0,len-1);
    67 }

    按照之前那幅图,绘制了一个函数间调用关系

    这里写到了9,后面基本一样。排完左子树,再排右子树,最终返回后,调用mergeIn,完成左右子树排序。

    完整代码:

      1 #include "stdlib.h"
      2 
      3 typedef int myDataType;
      4 myDataType src_ary[10] = {9,1,5,8,3,7,6,0,2,4};
      5 //myDataType src_ary[10] = {1,2,3,4,5,6,7,8,9,10};
      6 //myDataType src_ary[10] = {10,9,8,7,6,5,4,3,2,1};
      7 void prt_ary(myDataType *ary,int len)
      8 {
      9     int i=0;
     10     while(i < len)
     11     {
     12         printf(" %d ",ary[i++]);
     13     }
     14     printf("
    ");
     15 }
     16 
     17 void mergeIn(myDataType *ary,int s,int m,int e)
     18 {
     19     int i,j;
     20     //获取两个序列长度
     21     int len1 = (m-s)+1;
     22     int len2 = e-m;
     23     
     24     //开辟新空间,为排序做准备。
     25     myDataType *list1 = (myDataType *)malloc(sizeof(myDataType)*len1);
     26     myDataType *list2 = (myDataType *)malloc(sizeof(myDataType)*len2);
     27     
     28     //准备两个待比较序列数据
     29     for (i=0;i<len1;i++)
     30     {
     31         list1[i] = ary[s+i];
     32     }
     33 
     34     for (i=0;i<len2;i++)
     35     {
     36         list2[i] = ary[m+1+i];
     37     }
     38 
     39     //比较,因为用来其他空间来存放数据,最后比较后的数据直接给原数据
     40     i=0;
     41     j=0;
     42     while(i < len1 && j < len2)
     43     {
     44         if (list1[i] >= list2[j])
     45         {
     46             ary[s+i+j] = list2[j];
     47             j++;
     48         }
     49         else
     50         {
     51             ary[s+i+j] = list1[i];
     52             i++;
     53         }
     54     }
     55     while(i<len1)
     56     {
     57         ary[s+i+j] = list1[i];
     58         i++;
     59     }
     60     while(j<len2)
     61     {
     62         ary[s+i+j] = list2[j];
     63         j++;
     64     }
     65 
     66 }
     67 
     68 void mergeDiv(myDataType *ary,int sIdx,int eIdx)
     69 {
     70     if (sIdx >= eIdx)
     71     {
     72         return ;
     73     }
     74     int mid = (sIdx+eIdx)/2;
     75 
     76     mergeDiv(ary,sIdx,mid);
     77     mergeDiv(ary,mid+1,eIdx);
     78     printf("s=%d,mid=%d,e=%d
    ",sIdx,mid,eIdx);
     79     mergeIn(ary,sIdx,mid,eIdx);
     80 }
     81 
     82 
     83 
     84 void mergeSort(myDataType *ary,int len)
     85 {
     86     mergeDiv(ary,0,len-1);
     87 }
     88 
     89 int _tmain(int argc, _TCHAR* argv[])
     90 {
     91     printf("before sort:
    ");
     92     prt_ary(src_ary,10);
     93 
     94     //bubble_sort(src_ary,10);
     95     //bubble_sort_modify1(src_ary,10);
     96     //bubble_sort_opt(src_ary,10);
     97     //selectionSort(src_ary,10);
     98     //insertionSort(src_ary,10);
     99     //shellSort(src_ary,10);
    100     //heapSort(src_ary,10);
    101     mergeSort(src_ary,10);
    102     printf("after sort:
    ");
    103     prt_ary(src_ary,10);
    104 
    105 
    106 
    107     getchar();
    108     return 0;
    109 }


    归并排序用了其他内存空间,是一个耗费空间排序,但是其稳定性高。

    结果:

    中间的就是 每次访问时候的序号。

  • 相关阅读:
    EAX、ECX、EDX、EBX寄存器的作用
    MFC VS2005 添加Override 和 Message
    ActiveX添加测试工程, 出现的问题[非选择性参数][找不到成员]
    两种应该掌握的排序方法--------2.quick Sort
    关于I/O的那点事
    整理一下 编码、解码库
    VC一些经验系列: 《分享泄漏检测工具:内存、DC、GDI、Handle... 》
    golang安装卸载 linux+windows+raspberryPI 平台
    (转)如何正确使用C++多重继承
    单播、多播(也称组播)、广播
  • 原文地址:https://www.cnblogs.com/jsgnadsj/p/3458052.html
Copyright © 2011-2022 走看看