《数据结构与算法》之排序算法(归并排序)

 5、归并排序

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

归并排序算法的工作原理如下:

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

(2)设定两个指针或下标,最初位置分别为两个已经排序序列的起始位置

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

(4)重复步骤3直到某一指针或下标超出序列尾,将另一序列剩下的所有元素直接复制到合并序列尾

下面是一个二路归并排序的简单程序:

public class MergeSort {

	// 二路归并
	// 原理:将两个有序表合并和一个有序表

	public static void main(String[] args) {
		int[] array = { 4, 2, 8, 9, 5, 7, 6, 1, 3 };
		// 未排序数组顺序为
		System.out.println("未排序数组顺序为:");
		display(array);
		mergeSort(array, 0, 1);
		System.out.println("经过排序后的数组顺序为:");
		display(array);
	}

	// 遍历显示数组
	public static void display(int[] array) {
		for (int i = 0; i < array.length; i++) {
			System.out.print(array[i] + " ");
		}
		System.out.println();
	}

	public static void mergeSort(int[] a, int s, int len) {
		// a 数组
		// s 第一个有序表的起始下标
		// len 每次归并的有序集合的长度
		int size = a.length;
		int mid = size / (len * 2);
		
		int c = size & ((len * 2) - 1);
		// 归并到只剩一个有序集合的时候结束算法
		if (mid == 0)
			return;
		// 进行一趟归并排序
		for (int i = 0; i < mid; ++i) {
			s = i * 2 * len;
			merge(a, s, s + len, (len << 1) + s - 1);
		}
		// 将剩下的数和倒数一个有序集合归并
		if (c != 0)
			merge(a, size - c - 2 * len, size - c, size - 1);
		// 递归执行下一趟归并排序
		mergeSort(a, 0, 2 * len);
	}

	private static void merge(int[] a, int s, int m, int t) {
		// a 数组
		// s 第一个有序表的起始下标
		// m 第二个有序表的起始下标
		// t 第二个有序表的结束下标
		int[] tmp = new int[t - s + 1];
		int i = s, j = m, k = 0;
		while (i < m && j <= t) {
			if (a[i] <= a[j]) {
				tmp[k] = a[i];
				k++;
				i++;
			} else {
				tmp[k] = a[j];
				j++;
				k++;
			}
		}
		while (i < m) {
			tmp[k] = a[i];
			i++;
			k++;
		}
		while (j <= t) {
			tmp[k] = a[j];
			j++;
			k++;
		}
		System.arraycopy(tmp, 0, a, s, tmp.length);
	}

}

猜你喜欢

转载自blog.csdn.net/manbulaiyinhepan/article/details/83924709