Java排序算法之归并排序

Java排序算法之归并排序

算法概述

归并排序(Merge)是将两个(或两个以上)有序表合并成一个新的有序表,即把待排序序列分为若干个子序列,每个子序列是有序的。然后再把有序子序列合并为整体有序序列。

归并排序是建立在归并操作上的一种有效的排序算法。该算法是采用分治法(Divide and Conquer)的一个非常典型的应用。 将已有序的子序列合并,得到完全有序的序列;即先使每个子序列有序,再使子序列段间有序。若将两个有序表合并成一个有序表,称为两路归并排序算法。

算法思想

归并排序就是利用归并的思想实现的排序方法。而且充分利用了完全二叉树的深度是的特性,因此效率比较高。其基本原理如下:对于给定的一组记录,利用递归与分治技术将数据序列划分成为越来越小的半子表,在对半子表排序,最后再用递归方法将排好序的半子表合并成为越来越大的有序序列。 经过第一轮比较后得到最小的记录,然后将该记录的位置与第一个记录的位置交换;接着对不包括第一个记录以外的其他记录进行第二次比较,得到最小记录并与第二个位置记录交换;重复该过程,知道进行比较的记录只剩下一个为止。
两路归并排序算法思想:
①把 n 个记录看成 n 个长度为1的有序子表;
②进行两两归并使记录关键字有序,得到 n/2 个长度为 2 的有序子表;
③重复第②步直到所有记录归并成一个长度为 n 的有序表为止。
详细步骤:
1、申请空间,使其大小为两个已经排序序列之和,该空间用来存放合并后的序列(申请的内存空间大小必须大于等于待排序数组的长度)。
2、设定两个指针,最初位置分别为两个已经排序序列的起始位置。
3、比较两个指针所指向的元素,选择相对小的元素放入到合并空间,并移动指针到下一位置。
4、重复步骤3直到某一指针达到序列尾。
5、将另一序列剩下的所有元素直接复制到合并序列尾。

算法源码

/**
 * 归并排序
 * 
 * @author Administrator
 *
 */
public class MergeSort {
    public static void merge_sort(int a[],int first,int last,int temp[]){

          if(first < last){//使用递归算法将左、右两部分排好序。
              int middle = (first + last)/2;
              merge_sort(a,first,middle,temp);//左半部分排好序
              System.out.print("左半部分排序结果:");
              for (int i = 0; i < a.length; i++) {
                System.out.print(a[i] + "\t");
              }
              System.out.println(""); 
              merge_sort(a,middle+1,last,temp);//右半部分排好序
              System.out.print("右半部分排序结果:");
              for (int j = 0; j < a.length; j++) {
                System.out.print(a[j] + "\t");
              }
              System.out.println("");
              mergeArray(a,first,middle,last,temp); //合并左右部分     
          }
        }
    //合并 :将两个序列a[first-middle],a[middle+1-end]合并
    public static void mergeArray(int a[],int first,int middle,int end,int temp[]){     
      int i = first;//要排序数组的第一个数下标
      int m = middle;//要排序数组的中间数下标
      int j = middle+1;
      int n = end;//要排序数组的最后一个数下标
      int k = 0; 
      while(i<=m && j<=n){
          if(a[i] <= a[j]){
              temp[k] = a[i];
              k++;
              i++;
          }else{
              temp[k] = a[j];
              k++;
              j++;
          }
      }     
      while(i<=m){
          temp[k] = a[i];
          k++;
          i++;
      }     
      while(j<=n){
          temp[k] = a[j];
          k++;
          j++; 
      }

      for(int ii=0;ii<k;ii++){
          a[first + ii] = temp[ii];
      }
    }

    public static void main(String[] args) {

        int array[]={100,30, 111,46,99,-1,53,20}; 
        int temp[]=new int[8];//申请分配内存>=array.length
        merge_sort(array, 0, array.length-1, temp);
         System.out.print("最终排序结果:");
        for (int a = 0; a < array.length; a++) {
        System.out.print(array[a] + "\t");
    }


    }
}

测试效果:

左半部分排序结果:100    30  111 46  99  -1  53  20  
右半部分排序结果:100    30  111 46  99  -1  53  20  
左半部分排序结果:30 100 111 46  99  -1  53  20  
左半部分排序结果:30 100 111 46  99  -1  53  20  
右半部分排序结果:30 100 111 46  99  -1  53  20  
右半部分排序结果:30 100 46  111 99  -1  53  20  
左半部分排序结果:30 46  100 111 99  -1  53  20  
左半部分排序结果:30 46  100 111 99  -1  53  20  
右半部分排序结果:30 46  100 111 99  -1  53  20  
左半部分排序结果:30 46  100 111 -1  99  53  20  
左半部分排序结果:30 46  100 111 -1  99  53  20  
右半部分排序结果:30 46  100 111 -1  99  53  20  
右半部分排序结果:30 46  100 111 -1  99  20  53  
右半部分排序结果:30 46  100 111 -1  20  53  99  
最终排序结果:-1   20  30  46  53  99  100 111 

这样效果不是很好,把左半部分排序和右半部分排序分开:
左半部分排序

左半部分排序结果:100    30  111 46  99  -1  53  20  
左半部分排序结果:30 100 111 46  99  -1  53  20  
左半部分排序结果:30 100 111 46  99  -1  53  20  
左半部分排序结果:30 46  100 111 99  -1  53  20  
左半部分排序结果:30 46  100 111 99  -1  53  20  
左半部分排序结果:30 46  100 111 -1  99  53  20  
左半部分排序结果:30 46  100 111 -1  99  53  20      

右半部分排序

右半部分排序结果:100    30  111 46  99  -1  53  20  
右半部分排序结果:30 100 111 46  99  -1  53  20  
右半部分排序结果:30 100 46  111 99  -1  53  20  
右半部分排序结果:30 46  100 111 99  -1  53  20  
右半部分排序结果:30 46  100 111 -1  99  53  20  
右半部分排序结果:30 46  100 111 -1  99  20  53  
右半部分排序结果:30 46  100 111 -1  20  53  99  

其排序过程完全按照其算法步骤来实现。

算法分析

(1)稳定性
归并排序是一种稳定的排序。
(2)存储结构要求
可用顺序存储结构。也易于在链表上实现。
(3)时间复杂度
对长度为n的文件,需进行趟二路归并,每趟归并的时间为O(n),故其时间复杂度无论是在最好情况下还是在最坏情况下均是O(nlgn)
(4)空间复杂度
需要一个辅助向量来暂存两有序子文件归并的结果,故其辅助空间复杂度为O(n),显然它不是就地排序。
注意:若用单链表做存储结构,很容易给出就地的归并排序。

总结

归并排序 (merge sort) 是一类与插入排序、交换排序、选择排序不同的另一种排序方法。归并排序是一种比较占内存,但却效率高且稳定的算法。归并的含义是将两个或两个以上的有序表合并成一个新的有序表。归并排序有多路归并排序、两路归并排序 , 可用于内排序,也可以用于外排序。

发布了276 篇原创文章 · 获赞 47 · 访问量 12万+
展开阅读全文

没有更多推荐了,返回首页

©️2019 CSDN 皮肤主题: 技术黑板 设计师: CSDN官方博客

分享到微信朋友圈

×

扫一扫,手机浏览