归并排序(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];
		}
	}
非递归实现
public void mergeSort(int[] sr) {
		int n = sr.length; // 待排记录长度n
		for (int sz = 1; sz < n; sz = sz + sz) // 参与合并子数组的大小sz
			for (int lo = 0; lo < n - sz; lo += sz + sz) // 合并的两个子数组的起始位置lo
				merge(sr, lo, lo + sz - 1, Math.min(lo + sz + sz - 1, n - 1));
	}

	// 优秀的归并方式(O(∩_∩)O哈哈~)
	private void merge(int[] sr, int lo, int mid, int hi) { // 待排记录sr[],起始位置lo,分隔位置mid,结束位置hi
		int i = lo, j = mid + 1;
		int[] aux = Arrays.copyOf(sr, sr.length);
		for (int k = lo; k <= hi; k++)
			if (i > mid)
				sr[k] = aux[j++];
			else if (j > hi)
				sr[k] = aux[i++];
			else if (aux[j] < aux[i])
				sr[k] = aux[j++];
			else
				sr[k] = aux[i++];
	}
  • 6
    点赞
  • 23
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值