归并排序(2路归并)

要点
  • 时间复杂度:平均情况O(nlogn);最好情况(nlogn);最坏情况O(nlogn)
  • 空间复杂度:O(n)
  • 归并排序是一种稳定的排序方式
  • 基本思想:假设初始序列含有n个记录,则可以看成是n个有序的子序列,每个子序列的长度为1,然后两两归并,得到[n/2]([x]表示不小于x的最小整数)个长度为2或1的有序子序列;再两两归并,如此重复,直至得到一个长度为n的有序序列为止,这种排序方法称为2路归并排序
基本思路
  1. 待排记录一分为二(直到待排记录只剩下一个,返回本身)
  2. 对前半部分归并排序
  3. 对后半部分归并排序
  4. 合并前后两部分有序序列:定义两个指针p1,p2分别指向前后两部分的起始位置,再新建一个能够容下两部分的数组,比较两个指针指向的关键字,较小的关键字依序存储到新建数组中,并且该关键字的指针向后移动,另一指针保持不变,直到所有记录存储到新建数组中
  5. 新建数组中的关键字依序存储回原数组的对应位置
    2路归并演示图
递归实现
public void mergeSort(int sr[], int s, int t) { // sr[]待排记录;s要排序部分的起始位置,t(包含t)要排序部分的结束位置
		if (s == t) // 如果起始位置s和结束位置t相等,则待排记录只剩单独一个,默认为有序序列
			return;
		else {
			int m = (s + t) / 2; // 对待排记录取中,一分为二
			mergeSort(sr, s, m); // 对前半部分排序
			mergeSort(sr, m + 1, t); // 对后半部分排序
			merge(sr, s, m, t); // 合并两部分
		}
	}

	// 合并
	private void merge(int sr[], int s, int m, int t) { // sr待排记录,s起始位置,m分界线,t结束位置
		int trp = 0, lp = s, rp = m + 1; // 为新建数组定义指针trp,前半部分指针lp,后半部分指针rp
		int[] tr = new int[t - s + 1]; // 新建数组tr[]
		while (lp <= m && rp <= t) { // 关键字比较,放入新建数组对应位置
			if (sr[lp] < sr[rp]) {
				tr[trp++] = sr[lp++];
			} else {
				tr[trp++] = sr[rp++];
			}
		}
		if (lp <= m) { // 后半部分以全部加入新建数组tr[],则前半部分剩余关键字依序加入新建数组tr[]
			for (int i = 0; i <= m - lp; i++)
				tr[trp++] = sr[lp++];
		}
		if (rp <= t) { // 前半部分以全部加入新建数组tr[],则后半部分剩余关键字依序加入新建数组tr[]
			for (int i = 0; i <= t - rp; i++)
				tr[trp++] = sr[rp++];
		}
		// 排好序的有序序列(在新建数组tr[]中),依序存储回待排记录sr[]的对应位置
		for (int i = 0; i < tr.length; i++) {
			sr[i + s] = tr[i];
		}
	}
非递归实现

猜你喜欢

转载自blog.csdn.net/sinat_32469267/article/details/82883234