Loading

「学习笔记」归并排序的空间优化

归并排序的时间复杂度为 \(O_{n \log n}\),一般的空间复杂度为 \(O_n\),但事实上我们可以将这个空间复杂度优化到 \(O_1\)


对于 \(a_i\)\(a_j\) 这两个元素,我们要把他们都存到 \(a_k\) 这个位置里,我们可以这样操作
找一个比 \(\max(a_i, a_j)\) 大的数 \(maxx\),让 \(a_k = a_k + \max(a_i, a_j) \times maxx\)
这样,我们可以通过这个式子来表示出原本的 \(a_k\)\(\max(a_i, a_j)\)

\[\begin{aligned} &a_k = a_k \bmod maxx\\ &a_j = \lfloor \frac{a_k}{maxx} \rfloor \end{aligned} \]

这样,我们就不必再开一个和原数组长度一样的辅助数组了,但是由于会多次取模,所以时间上会比空间复杂度为 \(O_n\) 的归并排序慢


代码:

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
#define mid ((l + r) >> 1)

const int N = 1e5 + 5;

int n;
ll _max;
ll a[N];

void mergearray(int l, int mi, int r, ll maxn) {
	int i = l, j = mi + 1, k = l;
	while (i <= mi && j <= r) {
		if (a[i] % maxn <= a[j] % maxn) {
			// a[i] % maxn 与 a[j] % maxn 是 a[i] 与 a[j] 原本的值
			a[k] = a[k] + (a[i] % maxn) * maxn;
			++ k, ++ i;
		}
		else {
			a[k] = a[k] + (a[j] % maxn) * maxn;
			++ k, ++ j;
		}
	}
	while (i <= mi) {
		a[k] = a[k] + (a[i] % maxn) * maxn;
		++ k, ++ i;
	}
	while (j <= r) {
		a[k] = a[k] + (a[j] % maxn) * maxn;
		++ k, ++ j;
	}
	for (int i = l; i <= r; ++ i) {
		a[i] /= maxn;
	}
}

void mergesort(int l, int r, ll maxn) {
	if (l < r) {
		mergesort(l, mid, maxn);
		mergesort(mid + 1, r, maxn);
		mergearray(l, mid, r, maxn);
	}
}

int main() {
	scanf("%d", &n);
	for (int i = 1; i <= n; ++ i) {
		scanf("%lld", &a[i]);
		_max = max(_max, a[i]);
	}
	_max += 1;
	mergesort(1, n, _max);
	for (int i = 1; i <= n; ++ i) {
		printf("%d%c", a[i], " \n"[i == n]);
	}
	return 0;
}
posted @ 2023-04-02 11:29  yi_fan0305  阅读(64)  评论(0编辑  收藏  举报