图解 归并排序 C Java实现

归并排序

简介:

归并排序是成功应用分治技术的一个完美例子。

对于一个需要排序的数组 A [ 0.. n − 1 ] A[0..n-1] A[0..n1],归并排序把它一分为二: A [ 0.. n 2 − 1 ] A[0..\frac{n}{2}-1] A[0..2n1] A [ n 2 . . n − 1 ] A[\frac{n}{2}..n-1] A[2n..n1],

并对每个子数组队规排序,然后把这两个排好序的子数组合并为一个有序数组。

演示:

通过归并排序对数组 8 , 3 , 2 , 9 , 7 , 1 , 5 , 4 8,3,2,9,7,1,5,4 8,3,2,9,7,1,5,4进行排序的操作过程。

归并排序

C

//  2-路归并
void Merge(RcdType SR[], RcdType TR[], int i, int m, int n) {
    //  将相邻的有序区间SR[i..m]和SR[m+1..n]归并为有序的TR[i..n]
    int k, j;   //  i是最左边向右,j是中间向右,k是新数组整体从左到右填写
    for (j = m + 1, k = i; i <= m && j <= n; ++k) {
        //  将SR中记录按关键字从小到大地复制到TR中
        if (SR[i].key <= SR[j].key) //  "<="归并排序稳定,"<"归并排序不稳定
            TR[k] = SR[i++];
        else
            TR[k] = SR[j++];
    }
    while (i <= m) TR[k++] = SR[i++];   //  将剩余的SR[i..m]复制到TR
    while (j <= n) TR[k++] = SR[j++];   //  将剩余的SR[j..n]复制到TR
}

//  递归归并排序
void MSort(RcdType R1[], RcdType R2[], int i, int left, int right) {
    //  对R1[left..right]归并排序,若i % 2 == 1,则排序后的记录存入R2[left..right],否则存入R1[left..right]
    int middle;
    if (left == right) {
        if (i % 2)
            R2[left] = R1[left];
    } else {
        middle = (left + right) / 2;   //  将区间[left..right]平分为[left..m]和[m+1..right]
        MSort(R1, R2, i + 1, left, middle);    //  对区间[left..m]递归
        MSort(R1, R2, i + 1, middle + 1, right);//  对区间[m+1..right]递归
        if (i % 2)  //  将R1[left..m]和R1[m+1..right]归并到R2[left..right]
            Merge(R1, R2, left, middle, right);
        else        //  将R2[left..m]和R2[m+1..right]归并到R1[left..right]
            Merge(R2, R1, left, middle, right);
    }
}

//  对顺序表L作2-路归并排序
void MergeSort(RcdSqList &L) {
    RcdType *R;
    R = (RcdType *) malloc((L.length + 1) * sizeof(RcdType));   //  分配辅助空间
    MSort(L.rcd, R, 0, 1, L.length);        //  对L.rcd[1..L.length]归并排序
    free(R);
}

Java

package sortdemo;

import java.util.Arrays;

/**
 * Created by chengxiao on 2016/12/8.
 */
public class MergeSort {
    public static void main(String []args){
        int []arr = {9,8,7,6,5,4,3,2,1};
        sort(arr);
        System.out.println(Arrays.toString(arr));
    }
    public static void sort(int []arr){
        int []temp = new int[arr.length];//在排序前,先建好一个长度等于原数组长度的临时数组,避免递归中频繁开辟空间
        sort(arr,0,arr.length-1,temp);
    }
    private static void sort(int[] arr,int left,int right,int []temp){
        if(left<right){
            int mid = (left+right)/2;
            sort(arr,left,mid,temp);//左边归并排序,使得左子序列有序
            sort(arr,mid+1,right,temp);//右边归并排序,使得右子序列有序
            merge(arr,left,mid,right,temp);//将两个有序子数组合并操作
        }
    }
    private static void merge(int[] arr,int left,int mid,int right,int[] temp){
        int i = left;//左序列指针
        int j = mid+1;//右序列指针
        int t = 0;//临时数组指针
        while (i<=mid && j<=right){
            if(arr[i]<=arr[j]){
                temp[t++] = arr[i++];
            }else {
                temp[t++] = arr[j++];
            }
        }
        while(i<=mid){//将左边剩余元素填充进temp中
            temp[t++] = arr[i++];
        }
        while(j<=right){//将右序列剩余元素填充进temp中
            temp[t++] = arr[j++];
        }
        t = 0;
        //将temp中的元素全部拷贝到原数组中
        while(left <= right){
            arr[left++] = temp[t++];
        }
    }
}
小结:

归并排序是稳定排序,它也是一种十分高效的排序,能利用完全二叉树特性的排序一般性能都不会太差。java中Arrays.sort()采用了一种名为TimSort的排序算法,就是归并排序的优化版本。从上文的图中可看出,每次合并操作的平均时间复杂度为 O ( n ) O(n) O(n),而完全二叉树的深度为 ∣ l o g 2 n ∣ |log2n| log2n。总的平均时间复杂度为 O ( n l o g n ) O(nlogn) O(nlogn)

而且,归并排序的最好,最坏,平均时间复杂度均为 O ( n l o g n ) O(nlogn) O(nlogn)

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值