zoukankan      html  css  js  c++  java
  • 数据结构排序算法之归并排序

      最近一段时间一直在做项目,没有时间(好吧,我也承认最近有点懒,晚上回去什么都不想干了)。不过最近这两天晚上还是看了一点,就写下来备忘吧。

      排序算法之归并排序:看资料都介绍说这是一种效率非常高的算法,看有的大神进行的测试,在200000个随机数的情况下排序速度比快排还要快。

      其实主要原理也非常简单,看资料中的专业术语都是说采用分治法,分治法的要求是左右两边的数据都要有序(其实当我们左右两边只剩余一个的时候就是有序的)。

      其实所谓的分治法也就是把这堆数据划分开,左边一堆,右边一堆,然后在对左边这堆进行归并排序,也就是把左边这堆在分治划分,也就是在分成左左一堆,左右一堆,然后在往下进行分治划分,直到每个小堆都只有一个数据的时候,划分就完成了,因为只剩下一个数据,所以我们默认这个小堆的数据是有序的(这其实也是废话,就一个数,怎么看当然都是有序的了)。

      光分开肯定不行,因为我们要排序,所以我们还要在合起来,这就是我们的重点了,怎么合起来?这就需要进行数字大小的比较了,我们将两个指针分别放在两个左右小堆的开头处(最左端),然后我们进行两个指针下标对应数据的大小比较,若left[i]<=right[j],则我们将数字小的(即left[i])放在临时数组temp[k]处,然后我们将i,k都进行加1操作,这样的目的是将左边的比较数据往下移动一位,将临时数组的下标往下移动一位,以免被覆盖,这样我们将数据不断进行比较,当有一个小序列已经到头的时候,说明另外一个序列的剩余所有数据都比已经没有的序列的数据大,我们将剩余的数字全部赋值给临时数组。这样就完成了合起来的操作。

      这面就是划分和合并的图示。

      下面就是代码,里面都有注释。

     1 #include <stdio.h>
     2 
     3 void cutTwo(int sourceArr[],int *tempArr[],int start,int end);
     4 void merge(int sourceArr[],int *tempArr[],int start,int mid,int end);
     5 
     6 int main(int argc, char *argv[])
     7 {
     8     int a[8]={
     9         50, 10, 20, 30, 70, 40, 80, 60
    10     };
    11     int *b[8]={
    12     };
    13     int i;
    14     cutTwo(a,b,0,8);
    15     for(i=0;i<8;i++){
    16         printf("%d ",a[i]);
    17     }
    18     return 0;
    19 }
    20 
    21 
    22 /*
    23 归并排序算法: 
    24 */
    25 void merge(int sourceArr[],int *tempArr[],int start,int mid,int end){
    26     //当前我们有一个源数组,我们在比较时将这个源数组一分为二进行比较归并排序
    27     /*
    28     因为我们要进行归并排序,所以我们需要两个指针分别指向两个子序列的开始位置,即start指向左边部分的开始位置,
    29     mid+1指向右边部分的开始位置,我们还需要一个k的下标,用于存储我们交换过来的数组到临时数组tempArr[] 
    30     */ 
    31     int i=start;  //定义一个i下标,用于表示左边部分开始的位置下标
    32     int j=mid+1;  //定义一个j下标,用于表示右边部分开始的位置下标
    33     int k=0;  
    34     
    35     /*
    36     因为我们在比较时是不断的比较,直到一个子序列到达最后,所以我们应该用while循环来做,结束条件:无非就是左边序列到头了
    37     或者是右边序列到头了,即:i<=mid&&j<=end  只有在这两个条件都成立的条件下说明两个子序列都没有到头 
    38     */
    39     while(i<=mid&&j<=end){  //当i=mid+1或者j=end+1时说明子序列中有一个到头了,则跳出循环 
    40         if(sourceArr[i]<=sourceArr[j]){  //表示当前i比较小,那么我们就将小的值赋给k 
    41             tempArr[k]=sourceArr[i];
    42             k=k+1;
    43             i=i+1;
    44         }
    45         else{
    46             tempArr[k]=sourceArr[j];
    47             k=k+1;
    48             j=j+1;            
    49         }
    50         /*
    51         不能将k,i,j的加1操作放在if else判断的外面,因为我们在进行比较的时候,只是将下标所指的数字小的放在左边,将下标所指的数字
    52         大的不动,因为我们小的下标加1后还要和刚才下标所指的数字再次进行比较,如果放在外面,那么我们的比较的对象不对了(
    53         因为的大的数字的下标加1了,前面的一个数字没有进行比较) 
    54         */
    55     }
    56     
    57     /*
    58     当有一个子序列到头以后,我们就要将剩余没到头的子序列的剩余元素放到k的右边,因为剩余的肯定是已经有序的,且肯定比已经
    59     到头的子序列的全部元素都要大的。 
    60     */
    61     while(j<=end){  //i==mid+1&&    因为左边序列i跳出循环的条件肯定是当前i=mid+1了,则我们移动右边j的子序列就好了 
    62         tempArr[k]=sourceArr[j];
    63         k++;
    64         j++;
    65     }
    66     while(i<=mid){  // &&j==end+1   则此时表示当前跳出循环的是j右边的子序列,则我们移动左边的i的子序列 
    67         tempArr[k]=sourceArr[i];
    68         k++;
    69         i++;
    70     }
    71     int m;
    72     for(m=0;m<k;m++){
    73         sourceArr[start+m]=tempArr[m];
    74     }
    75     
    76     
    77 } 
    78 
    79 
    80 /*
    81 上述操作完成仅仅是完成了对一个大的序列中一部分的排列,因为我们的做法是对整个的序列进行二分,二分之后对子序列进行归并排序 
    82 */
    83 void cutTwo(int sourceArr[],int *tempArr[],int start,int end){    
    84     
    85     if(start<end){
    86         int mid;  //设置一个取中间的变量
    87         mid=(start+end)/2;
    88         
    89         cutTwo(sourceArr,tempArr,start,mid);
    90         cutTwo(sourceArr,tempArr,mid+1,end);
    91         merge(sourceArr,tempArr,start,mid,end);
    92     }
    93      
    94 }

      该博客系博主自主原创,转载请标明出处哟。

  • 相关阅读:
    前端性能优化总结
    Vue style 深度作用选择器 >>> 与 /deep/(sass/less)
    NPM依赖包版本号~和^的区别及最佳实践
    umi部分使用总结
    FIS 插件机制
    从0到1发布一个npm包
    页面性能监控之performance
    1和new Number(1)有什么区别
    实现一个hoverDelay延迟hover
    触发浏览器回流的属性方法一览表
  • 原文地址:https://www.cnblogs.com/WuNaiHuaLuo/p/5446449.html
Copyright © 2011-2022 走看看