归并排序
来源:互联网 发布:网络成瘾临床诊断标准 编辑:程序博客网 时间:2024/06/11 19:37
- 思想:将两个或两个以上的有序序列合并成一个新的有序序列。具体说来就是先把待排序的 n个元素序列分解成两个子序列, 每个子序列包括 n/2个元素,不断重复这个过程,直到分解成n个长度为1的子序列;再对每个子序列进行合并排序, 不断重复这个过程,直到整个序列有序。
- 时间复杂度:O(nlogn)
- 空间复杂度:O(n)
- 优化:1.在数组长度比较短时,不再进行递归,而是选择其他排序方案:如插入排序等,以达到最优时间复杂度;2.归并过程中,可以用记录数组下标的方式代替申请新内存空间,避免原数组和辅助数组频繁的数据读写,经此优化,空间复杂度能达到O(1)。
- 注意:1.归并排序的最好、最坏以及平均时间复杂度都是O(nlogn);2.归并排序算法比较占用内存,空间复杂度为O(n),但却是效率高且稳定的排序算法;3.归并排序是一种稳定的排序算法。
- 代码如下:
1.不含注释
public class MergeSort { public static void mergeSort(int [] a) { Sort(a, 0, a.length-1); } public static void Sort(int [] a, int left, int right) { if (left < right) { int mid = (left+right)/2; Sort(a, left, mid); Sort(a, mid+1, right); Merge(a, left, mid, right); } } public static void Merge(int [] a, int left, int mid, int right) { int [] temp = new int[a.length]; int i = left; int j = mid+1; int k = 0; while (i <= mid && j <= right) { if (a[i] < a[j]) { temp[k++] = a[i++]; } else { temp[k++] = a[j++]; } } while (i <= mid) { temp[k++] = a[i++]; } while (j <= right) { temp[k++] = a[j++]; } for (i = 0; i < k; i++) { a[left+i] = temp[i]; } } public static void print(int[] a) { for (int i = 0; i < a.length; i++) { System.out.print(a[i]+" "); } } public static void main(String[] args) { int [] data = {88,22,27,19,10,37,63,28,33,54}; System.out.println("归并排序前的数组:"); print(data); System.out.println(); mergeSort(data); System.out.println("归并排序后的数组:"); print(data); }}
2.含注释详解
/** * * @author artadonis * */public class MergeSort { public static void mergeSort(int [] a) { //归并排序,数组下标范围:0~a.length-1 Sort(a, 0, a.length-1); } public static void Sort(int [] a, int left, int right) { //分解条件:left<right时才分解,当left>=right的时候,说明已经分解到单个元素了 if (left < right) { //找出中间索引 int mid = (left+right)/2; //对左半部分数组递归进行分解与合并 Sort(a, left, mid); //对右半部分数组递归进行分解与合并 Sort(a, mid+1, right); //在递归外:在调用这条语句时,说明左右两边数组已经分别有序 //在递归内:已分解成单个元素,可视作有序,开始进行合并 Merge(a, left, mid, right); } } //left是数组中要排序的开始索引,排序不一定是从0开始 //Merge(a, left, mid, right),只是对数组的子数组a[left...right]排序 public static void Merge(int [] a, int left, int mid, int right) { //定义一个与带排序序列长度相同的临时数组 int [] temp = new int[a.length]; //i,j变量首先分别指向两数组的句首元素 int i = left; int j = mid+1; int k = 0; //i和j变量所指向的数组,到达尾端了,就跳出循环 //if...else语句中,哪个小就把哪个放在临时数组中 while (i <= mid && j <= right) { if (a[i] < a[j]) { temp[k++] = a[i++]; } else { temp[k++] = a[j++]; } } //将剩余部分依次放入临时数组中 while (i <= mid) { temp[k++] = a[i++]; } while (j <= right) { temp[k++] = a[j++]; } //不理解分解、治理、再合并这个递归过程的话,可以把以下三条语句的移出注释,打印输出结果,以助理解 // System.out.print("temp数组: "); // print(temp); // System.out.println(); //因为k在上面多加了一次,所以此时是i<k(就已经是原来数组的长度0~‘k’),而不是i<=k //合并完成后,把此时已经有的临时数组temp[],拷贝回原数组a[],i变量是初始化过的局部变量,需要更改的时候不要再加数据类型,直接更改就行 for (i = 0; i < k; i++) { a[left+i] = temp[i]; } //不理解分解、治理、再合并这个递归过程的话,可以把以下三条语句的移出注释,打印输出结果,以助理解 // System.out.print("a数组: "); // print(a); // System.out.println(); } //合并完成后,把此时已经有的临时数组temp[],拷贝回原数组a[],i变量是初始化过的局部变量, //需要更改的时候不要再加数据类型,直接更改就行 public static void print(int[] a) { for (int i = 0; i < a.length; i++) { System.out.print(a[i]+" "); } } public static void main(String[] args) { int [] data = {88,22,27,19,10,37,63,28,33,54}; System.out.println("归并排序前的数组:"); print(data); System.out.println(); mergeSort(data); System.out.println("归并排序后的数组:"); print(data); }}
1 0
- 归并排序-归并排序
- 归并和归并排序
- 归并与归并排序
- 归并排序
- 归并排序
- 归并排序
- 归并排序
- 归并排序
- 归并排序
- 排序::归并
- 归并排序
- 归并排序
- 归并排序
- 归并排序
- 归并排序
- 归并排序
- 归并排序
- 归并排序
- 白话面向智能体编程(Agent Oriented Programmig, AOP)之三
- oracle函数及type
- 采用usb线刷linux固件的原理
- Android应用性能优化之使用SparseArray替代HashMap
- php 安装及自定义模块
- 归并排序
- spring中props,list,set,map元素的用法
- 基于Websocket的实时数据看板
- 正则判断身份证,电话号码,邮箱等格式是否正确
- 字节流复制文件
- 32 通道填边
- Android NDK环境搭建
- 强连通Tarjan NYOJ 120 校园网络
- HDU1005 Number Sequence