根据Merge Sort原理, 自己实现的归并排序算法+详细注释+代码(C#,C/C++) [分享]

本文是受前面的一篇《C#实现所有经典排序算法》飛雪飄寒 影响,应邀请,把我曾经实现的归并排序算法拿出来分享,欢迎改善:

归并操作(merge),也叫归并算法,指的是将两个已经排序的序列合并成一个序列的操作。

1. 不多废话,我已经把注释写得很详细了,C#实现的分享如下:

         ///   <summary>
        
///  归并排序之归:归并排序入口 
        
///  Updated by Lihua at 05/06/2009
        
///   </summary>
        
///   <param name="data"> 无序数组 </param>
        
///   <returns> 有序数组 </returns>
        
///   <author> lihua </author>
        
///   <copyright> www.zivsoft.com </copyright>
         int [] Sort( int [] data)
        {
            
// 若data为null,或只剩下1 or 0个元素,返回,不排序
             if  ( null   ==  data  ||  data.Length  <=   1 )
            {
                
return  data;
            }

            
// 取数组中间下标
            
// int middle = data.Length / 2;  // 方法一:除2取整数
             int  middle  =  data.Length  >>   1 ;   // 方法二:位移 (感谢读者hyper给出的这个效率稍高的方法)

            
// 初始化临时数组let,right,并定义result作为最终有序数组,若数组元素奇数个,将把多余的那元素空间预留在right临时数组
             int [] left  =   new   int [middle], right  =   new   int [data.Length  -  middle], result  =   new   int [data.Length];
            
            
// 下面这句对性能有些影响,所以在上面有了改进,直接用data.Length-middle初始化right数组
            
// if (data.Length % 2 != 0) right = new int[middle + 1]; 

            
// int i = 0, j = 0;
            
// foreach (int x in data) // 开始排序
            
// {
            
//     if (i < middle) // 填充左数组
            
//     {
            
//         left[i] = x;
            
//         i++;
            
//     }
            
//     else // 填充右数组
            
//     {
            
//         right[j] = x;
            
//         j++;
            
//     }
            
// }

            
// 上面的foreach被改成了for循环
            
// for (int i = 0; i < data.Length; i++)
            
// {
            
//     if (i < middle) // 用middle,不用left.Length
            
//     {
            
//         left[i] = data[i];
            
//     }
            
//     else
            
//     {
            
//         right[i - middle] = data[i];  // 此处i-middle,让我省掉定义一个j,性能有所提高
            
//     }
            
// }
            
            
// 经调查,用Array.Copy的确比上面的for循环优化很多
            Array.Copy(data,  0 , left,  0 , middle); // 拷贝左数组
            Array.Copy(data, left.Length, right,  0 , right.Length);  // 拷贝右数组

            left 
=  Sort(left); // 递归左数组
            right  =  Sort(right); // 递归右数组
            result  =  Merge(left, right); // 开始排序
            
// this.Write(result); // 输出排序,测试用(lihua debug)
             return  result;
        }
        
///   <summary>
        
///  归并排序之并:排序在这一步
        
///   </summary>
        
///   <param name="a"> 左数组 </param>
        
///   <param name="b"> 右数组 </param>
        
///   <returns> 合并左右数组排序后返回 </returns>
         int [] Merge( int [] a,  int [] b)
        {
            
// 定义结果数组,用来存储最终结果
             int [] result  =   new   int [a.Length  +  b.Length];
            
int  i  =   0 , j  =   0 , k  =   0 ;
            
while  (i  <  a.Length  &&  j  <  b.Length)
            {
                
if  (a[i]  <  b[j]) // 左数组中元素小于右数组中元素
                {
                    result[k
++ =  a[i ++ ]; // 将小的那个放到结果数组
                }
                
else // 左数组中元素大于右数组中元素
                {
                    result[k
++ =  b[j ++ ]; // 将小的那个放到结果数组
                }
            }
            
while  (i  <  a.Length) // 这里其实是还有左元素,但没有右元素
            {
                result[k
++ =  a[i ++ ];
            }
            
while  (j  <  b.Length) // 右右元素,无左元素
            {
                result[k
++ =  b[j ++ ];
            }
            
return  result; // 返回结果数组
        }

 

2. C/C++实现如下

// 归并排序中之并
// Updated by zivsoft at 05/06/2009
int   * Merge( int   * a, int  aLength, int   * b, int  bLength){
    
// 合并结果指针
     int   * result;
    
// 初始化结果指针
    result = new   int [aLength + bLength];

    
int  i = 0 ,j = 0 ,k = 0 ;

    
// 定义左指针
    a = new   int [aLength];
    
// 定义右指针
    b = new   int [bLength];

    
// 元素排序,左右比较
     while (i < aLength && j < bLength){
        
if (a[i] < b[j]){ // 左元素小于右元素
            result[k ++ ] = a[i ++ ]; // 将小的赋值到结果
        }
        
else { // 左元素大于右元素
            result[k ++ ] = b[j ++ ]; // 将小的赋值到结果
        }
    }
    
while (i < aLength){ // 将最后一个元素赋值到结果
        result[k ++ ] = a[i ++ ];
    }
    
while (j < bLength){ // 将最后一个元素赋值到结果
        result[k ++ ] = b[j ++ ];
    }
    
return  result;
}

// 归并排序中之归拆分
// Updated by zivsoft at 05/06/2009
int   * Split( int   * data, int  length){
    
int  i = 0 ,j = 0 ,k = 0 ;
    
int   * left, * right, * result;
    
// 取中间下标
     int  middle = length / 2 ;
    left
= new   int [middle];
    right
= new   int [middle];
    
// 初始化有序结果数组
    result = new   int [length];
    
// 如果数组只有一个元素,直接返回,无需排序
     if (length <= 1 ){
        
return  data;
    }
    
int  rightLength = 0 ;

    
// 奇数个元素的话,重新分配右数组长度
     if (length % 2 != 0 ){
        delete[] right;
        rightLength
= middle + 1 ;
        right
= new   int [rightLength];
    }
    
// 拆分数组
     for (k = 0 ;k < length;k ++ ){
        
if (i < middle){
            left[i
++ ] = data[k];
        }
        
else {
            right[j
++ ] = data[k];
        }
    }
    left
= Split(left,i); // 递归拆分左数组
    right = Split(right,rightLength); // 递归拆分右数组
    result = Merge(left,i,right,rightLength); // 排序并合并
    
// printarray(result,k);  // 输出,供lihua(zorywa)侧使用(zivsoft)
     return  result;
}

 

感言:

这个算法是我在XX的一个面试题,问如何高效率将两个链表合并,并使之有序。很快想到归并排序(Merge Sort),想了想原理,把它实现了,不过现在又把它拿出来加了很多注释,应该没什么大问题了吧,重要是理解算法的精髓,用什么实现应该差不多,目前写了C#和C/C++两个版本,便于理解Merge Sort的原理,欢迎提建议,共同提高。 :-)

 

本文链接:http://www.cnblogs.com/architect/archive/2009/05/06/1450489.html
关于作者:http://www.zivsoft.com/

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值