[整活]QYT归并排序(从二路归并到三路归并)
前言
闲大发了属于是。
不过过年就是要整点让人开心的(?)
归并排序
归并排序以分治的思维处理一个无序的序列。
- 将序列均分为两份,若不能再分则直接进入步骤 3
- 分别排序均分后的两序列
- 现在得到的两个序列都是有序的,每次取出两个序列中较大/较小的那个放在新有序序列最前的位置即可合并两个序列
通过主定理分析可得,其平均复杂度及最劣复杂度均为 \(\mathcal{O} (n \log n)\)。
void MergeSort(int *a,int l,int r) {
if(l == r) return ;
int mid = (l + r) >> 1;static int t[N];
MergeSort(a,l,mid),MergeSort(a,mid + 1,r);
int p1 = l,p2 = mid + 1,p = l;
while(p1 <= mid && p2 <= r) {
if(a[p1] <= a[p2]) t[p++] = a[p1++];
else t[p++] = a[p2++];
}
while(p1 <= mid) t[p++] = a[p1++];
while(p2 <= r) t[p++] = a[p2++];
rep(i,l,r) a[i] = t[i];
}
三路归并
在上面的过程中,我们将序列分成两份。
但是我们知道,如果能将序列分成自然对数的底数 \(e\) 份所得的效率是这类分治然后合并的排序能得到的最好效率,但是 \(e \approx 2.718281828459\),相对于 \(2\),其与 \(3\) 更接近。那么尝试将序列均分为三段然后合并三个有序序列。
复杂度分析
考虑合并的过程,每个元素只被加入临时数组一次,为 \(\mathcal{O} (n)\) 的。
利用主定理 :
\[\large
T(n) = 3T(\frac{n}{3}) + \mathcal{O}(n) = \mathcal{O}(n \log_3 n)
\]
然后你就可以发现这个玩意大常数。
但是这不妨碍它和二路归并差不多快,于是我们将其命名为 QYT 归并排序。
这个排序的优点是码量比归并大,可以锻炼你输入的速度(?)
以下是乱写的代码。
void QytMergeSort(int *a,int l,int r) {
if(l >= r) return ;
static int t[N];
int mid1 = l + (r - l) / 3,mid2 = r - (r - l) / 3;
QytMergeSort(a,l,mid1);
QytMergeSort(a,mid1 + 1,mid2);
QytMergeSort(a,mid2 + 1,r);
int p = l,p1 = l,p2 = mid1 + 1,p3 = mid2 + 1;
while(p1 <= mid1 && p2 <= mid2 && p3 <= r) {
if(a[p1] <= a[p2] && a[p1] <= a[p3])
t[p++] = a[p1++];
else if(a[p2] <= a[p1] && a[p2] <= a[p3])
t[p++] = a[p2++];
else
t[p++] = a[p3++];
}
while(p1 <= mid1 && p2 <= mid2) {
if(a[p1] < a[p2]) t[p++] = a[p1++];
else t[p++] = a[p2++];
}
while(p1 <= mid1 && p3 <= r) {
if(a[p1] < a[p3]) t[p++] = a[p1++];
else t[p++] = a[p3++];
}
while(p2 <= mid2 && p3 <= r) {
if(a[p2] < a[p3]) t[p++] = a[p2++];
else t[p++] = a[p3++];
}
while(p1 <= mid1) t[p++] = a[p1++];
while(p2 <= mid2) t[p++] = a[p2++];
while(p3 <= r) t[p++] = a[p3++];
rep(i,l,r) a[i] = t[i];
}
作者:AstatineAi
本文为 作者 AstatineAi 的原创,遵循CC BY-NC-SA 4.0 版权协议,转载请附上原文出处链接及本声明。