算法分析(二)归并排序原理及java实现

来源:互联网 发布:自身投资知乎 编辑:程序博客网 时间:2024/05/21 17:11

一、归并排序概念

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

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

归并排序算法稳定,数组需要O(n)的额外空间,链表需要O(log(n))的额外空间,时间复杂度为O(nlog(n)),算法不是自适应的,不需要对数据的随机读取。

二、工作原理:

1、申请空间,使其大小为两个已经排序序列之和,该空间用来存放合并后的序列

2、设定两个指针,最初位置分别为两个已经排序序列的起始位置

3、比较两个指针所指向的元素,选择相对小的元素放入到合并空间,并移动指针到下一位置

4、重复步骤3直到某一指针达到序列尾

5、将另一序列剩下的所有元素直接复制到合并序列

三、归并排序过程及操作

1.分治的实现 :
把整个集合的元素一直除2化分,一直化为到没有两个元素开始合并,分治的时候比较简单,一直除2递归就行了,合并的时候为了方便就借助另一个变化的数组来接收交换的数组;

2.合并的实现 :
          合并的时候,两个指标i、j,把值比较小的放入temp数组中,然后放入那个值的那一边的指标自加,继续比          较。一直把值合部排完合并为一个数组,然后把temp数组复制回到原来数组就可以进入下一个递归。

3.归并操作(merge),也叫归并算法,指的是将两个顺序序列合并成一个顺序序列的方法。
          如:设有数列{6,202,100,301,38,8,1}
          初始状态:6,202,100,301,38,8,1
          第一次归并后:{6,202},{100,301},{8,38},{1},比较次数:3;
          第二次归并后:{6,100,202,301},{1,8,38},比较次数:4;
          第三次归并后:{1,6,8,38,100,202,301},比较次数:4;
          总的比较次数为:3+4+4=11,;
          逆序数为14;

四、java代码实现

package com.deppon.tps.module;public class MergeSortTest {public static void main(String[] args) {int[] data = new int[] { 5, 3, 6, 2, 1, 9, 4, 8, 7 };print(data);mergeSort(data);System.out.println("排序后的数组:");print(data);}public static void mergeSort(int[] data) {sort(data, 0, data.length - 1);}public static void sort(int[] data, int left, int right) {if (left >= right)return;// 找出中间索引int center = (left + right) / 2;// 对左边数组进行递归sort(data, left, center);// 对右边数组进行递归sort(data, center + 1, right);// 合并merge(data, left, center, right);print(data);}/** * 将两个数组进行归并,归并前面2个数组已有序,归并后依然有序 * @param data 数组对象 * @param left 左数组的第一个元素的索引 * @param center 左数组的最后一个元素的索引,center+1是右数组第一个元素的索引 * @param right 右数组最后一个元素的索引 */public static void merge(int[] data, int left, int center, int right) {// 临时数组int[] tmpArr = new int[data.length];// 右数组第一个元素索引int mid = center + 1;// third 记录临时数组的索引int third = left;// 缓存左数组第一个元素的索引int tmp = left;while (left <= center && mid <= right) {// 从两个数组中取出最小的放入临时数组if (data[left] <= data[mid]) {tmpArr[third++] = data[left++];} else {tmpArr[third++] = data[mid++];}}// 剩余部分依次放入临时数组(实际上两个while只会执行其中一个)while (mid <= right) {tmpArr[third++] = data[mid++];}while (left <= center) {tmpArr[third++] = data[left++];}// 将临时数组中的内容拷贝回原数组中// (原left-right范围的内容被复制回原数组)while (tmp <= right) {data[tmp] = tmpArr[tmp++];}}public static void print(int[] data) {for (int i = 0; i < data.length; i++) {System.out.print(data[i] + "\t");}System.out.println();}}



0 0