Java排序算法之归并排序

来源:互联网 发布:linux 驱动 usleep 编辑:程序博客网 时间:2024/06/05 09:27

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

原创粉丝点击
热门问题 老师的惩罚 人脸识别 我在镇武司摸鱼那些年 重生之率土为王 我在大康的咸鱼生活 盘龙之生命进化 天生仙种 凡人之先天五行 春回大明朝 姑娘不必设防,我是瞎子 婴儿拉白色粘液怎么办 宝宝不肯吃鱼肝油怎么办 婴儿不肯吃鱼肝油怎么办 宝宝吃鱼肝油吐怎么办 五个月婴儿夏天怎么办 厌奶期宝宝瘦了怎么办 二个月的宝宝不喝夜奶怎么办 婴儿不喝奶粉怎么办 小孩整天不吃饭怎么办 婴儿不吃不喝怎么办 断奶后不吃奶瓶怎么办 小孩早上不吃饭怎么办 新生儿不认乳头怎么办 宝宝不吸奶嘴怎么办 孩子不会吸奶瓶怎么办 宝宝突然不吃奶瓶怎么办 换了奶瓶不喝奶怎么办 新生儿不喝奶粉怎么办 7个月小婴儿磨牙怎么办 宝宝出生四天不喝母乳怎么办 我的奶水不足怎么办 乳牙长得不整齐怎么办 新生儿只吃奶粉怎么办 小孩不肯吸母乳怎么办 三个月宝宝不吃奶粉怎么办 宝宝不爱喝水怎么办 崔玉涛 小孩身体铅过高怎么办 疫苗引起的发烧怎么办 婴儿不吃米糊怎么办 宝宝米糊不吃怎么办 换奶瓶宝宝不吃怎么办 小孩不会吃奶瓶怎么办 百天不吃奶瓶怎么办 1岁宝宝积食怎么办 宝宝退烧后流汗怎么办 宝宝高烧后出汗怎么办 发烧出汗不退烧怎么办 婴儿发烧不出汗怎么办 婴幼儿发烧不退怎么办 宝宝突然不吃饭怎么办 宝宝吃饭到处跑怎么办