码迷,mamicode.com
首页 > 编程语言 > 详细

归并排序

时间:2020-01-07 22:57:08      阅读:97      评论:0      收藏:0      [点我收藏+]

标签:new   完成   com   lse   一段   递归循环   初始   util   bsp   

 归并排序(Merging Sort)就是将两个或两个以上的有序表合并成一个有序表的过程。将两个有序表合并成一个有序表的过程称为2-路归并,2-路归并最为简单和常用。下面以2-路归并为例,介绍归并排序算法

归并排序算法的思想

  假设初始序列含有n个记录,则可看成是n个有序的子序列,每个子序列的长度为1,然后两两归并,得到[n/2]个长度为2或1的有序子序列;再两两归并,……,如此重复,直至得到一个长度为n的有序序列为止。

  2-路归并排序的过程如图所示

 技术图片

  2-路归并排序中的核心操作是,将待排序序列中前后相邻的两个有序序列归并为一个有序序列。


归并排序的两种实现策略

递归法

原理如下(假设序列共有n个元素):

1、将原始序列从中间分为左、右两个子序列,此时序列数为2

2、将左序列和右序列再分别从中间分为左、右两个子序列,此时序列数为4

3、重复以上步骤,直到每个子序列都只有一个元素,可认为每一个子序列都是有序的

4、最后依次进行归并操作,直到序列数变为1

代码实现

package com.hxy.sort;


import java.util.Arrays;

public class MergeSort1{

    public static void main(String[] args) {
        int[] arr= {2,5,7,4,9,3,4,};
        System.out.println("未排序前的顺序");
        System.out.println(Arrays.toString(arr));
        mergeSort(arr,new int[arr.length],0,arr.length-1);
        System.out.println("排序之后的顺序");
        System.out.println(Arrays.toString(arr));
    }

    public static void merge(int[] arr,int[] temp, int low , int mid, int high){
       int i = low, j = mid+1;
        int k = 0;

        while(i<=mid&&j<=high){
            if(arr[i]<=arr[j]){
                temp[k]=arr[i];
                k++;
                i++;
            }else{
                temp[k]=arr[j];
                k++;
                j++;
            }
        }
        //如果左边有剩余而右边已经添加完 直接把左边剩余的按着顺序添加到临时数组temp中
        while (i<=mid){
            temp[k]=arr[i];
            k++;
            i++;
        }
        //如果右边有剩余而左边已经添加完 直接把右边剩余的按着顺序添加到临时数组temp中
        while (j<=high){
            temp[k]=arr[j];
            k++;
            j++;
        }

        //将临时序列中有序的序列赋给原序列
        for(int t = 0; t<k;t++){
            arr[low+t]= temp[t];
        }

    }


    public static void mergeSort(int[] arr, int[] temp ,int low ,int high){
        if(low<high){
            //将序列分为左右两部分
            int mid  = (low+high)/2;
            //将左边的序列进行归并排序
            mergeSort(arr,temp,low,mid);
            //将右边的序列进行归并排序
            mergeSort(arr,temp,mid+1,high);
            //将两段有序的序列合为一段有序的序列
            merge(arr,temp,low,mid,high);
        }

    }

}

 

迭代法

原理如下(假设序列共有n个元素):

1、将序列每相邻两个数进行归并操作,形成ceil(n/2)个序列,排序后每个序列包含两/一个元素

2、将序列每相邻的两个有序子序列进行归并操作,形成ceil(n/4)个序列,每个序列包含四/三个元素

3、重复步骤2,直到所有元素排序完毕,即序列数为1个

void Merge(int*a,int low,int mid,int high)

{

    inti=low,j=mid+1,k=0;

    int *temp=(int*)malloc((high-low+1)*sizeof(int));

    while(i<=mid&&j<=high)

        a[i]<=a[j]?(temp[k++]=a[i++]):(temp[k++]=a[j++]);

    while(i<=mid)

        temp[k++]=a[i++];

    while(j<=high)

        temp[k++]=a[j++];

    memcpy(a+low,temp,(high-low+1)*sizeof(int));

    free(temp);

}

void MergeSort(int*a,int n)

{

    int length;

    for(length=1; length<n; length*=2)

    {

        int i;

        for(i=0; i+2*length-1<=n-1; i+=2*length)

            Merge(a,i,i+length-1,i+2*length-1);

        if(i+length<=n-1)

             Merge(a,i,i+length-1,n-1);

    }

}

递归和迭代的区别


递归和迭代都是循环的一种。简单地说,递归是重复调用函数自身实现循环。迭代是函数内某段代码实现循环,而迭代与普通循环的区别是:循环代码中参与运算的变量同时是保存结果的变量,当前保存的结果作为下一次循环计算的初始值。

递归循环中,遇到满足终止条件的情况时逐层返回来结束。迭代则使用计数器结束循环。当然很多情况都是多种循环混合采用,这要根据具体需求。

递归与迭代都是基于控制结构:迭代用重复结构,而递归用选择结构。 递归与迭代都涉及重复:迭代显式使用重复结构,而递归通过重复函数调用实现重复。 递归与迭代都涉及终止测试:迭代在循环条件失败时终止,递归在遇到基本情况时终止。 使用计数器控制重复的迭代和递归都逐渐到达终止点:迭代一直修改计数器,直到计数器值使循环条件失败;递归不断产生最初问题的简化副本,直到达到基本情况。迭代和递归过程都可以无限进行:如果循环条件测试永远不变成false,则迭代发生无限循环;如果递归永远无法回推到基本情况,则发生无穷递归。 递归函数是通过调用函数自身来完成任务,而且在每次调用自身时减少任务量。而迭代是循环的一种形式,这种循环不是由用户输入而控制,每次迭代步骤都必须将剩余的任务减少;.

动图展示.

技术图片

算法分析

  ①时间复杂度

  当有n个记录时,需进行log2n趟归并排序,每一趟归并,其关键字比较 次数不超过n,元素移动次数都是n,因此归并排序的时间复杂度为O(nlog2n)

  ②

  用顺序表实现归并排序时,需要和待排序记录个数相等的辅助存储空间,所以空间复杂度为O(n)

算法特点

  (1)      是稳定排序

  (2)      可用于链式结构,且不需要附加存储空间,但递归实现时仍需要开辟相应的递归工作栈

归并排序

标签:new   完成   com   lse   一段   递归循环   初始   util   bsp   

原文地址:https://www.cnblogs.com/huxiaoyang/p/12058011.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!