背景
归并排序,时间复杂度O(NlogN)
,具有方便、易懂的特点,且属于稳定排序
,使用场景颇多。
下面总结介绍一些魔改用法,比如升序、降序和参数压缩等。
代码与思路
升序降序的Merge排序实现:
下面代码中,a为实际参与排序比较的,b为跟随变化的关系,是a的关联值。temp1, temp2为与a, b等效长度的中转数组。
// 合并 :将两个序列a[first-middle], a[middle+1-end]合并
static void MergeArray(int16_t a[], uint16_t b[], int first, int middle, int end, int16_t temp1[], uint16_t temp2[])
{
int i = first;
int m = middle;
int j = middle + 1;
int n = end;
int k = 0;
while (i <= m && j <= n) {
// if (a[i] <= a[j]) { // 升序 orig
if (a[i] < a[j]) { // 升序 为求稳定,相等时不交换
// if (a[i] > a[j]) { // 降序
temp1[k] = a[i];
temp2[k] = b[i];
k++;
i++;
} else {
temp1[k] = a[j];
temp2[k] = b[j];
k++;
j++;
}
}
while (i <= m) {
temp1[k] = a[i];
temp2[k] = b[i];
k++;
i++;
}
while (j <= n) {
temp1[k] = a[j];
temp2[k] = b[j];
k++;
j++;
}
int ii;
for (ii = 0; ii < k; ii++) {
a[first + ii] = temp1[ii];
b[first + ii] = temp2[ii];
}
}
// 闭区间 [first, last]
static void MergeSortAlg(int16_t a[], uint16_t b[], int first, int last, int16_t temp1[], uint16_t temp2[])
{
if (first < last) {
int middle = (first + last) / 2;
MergeSortAlg(a, b, first, middle, temp1, temp2); //左半部分排好序
MergeSortAlg(a, b, middle + 1, last, temp1, temp2); //右半部分排好序
MergeArray(a, b, first, middle, last, temp1, temp2); //合并左右部分
}
}
以上版本未做参数打包压缩。
// 合并 :将两个序列a[first-middle],a[middle+1-end]合并
typedef struct MergeSort {
int16_t *a;
uint16_t *b;
int16_t *temp1;
uint16_t *temp2;
} AgsMergeSortStru;
static void MergeArray(AgsMergeSortStru *mergSortParam, int first, int middle, int end)
{
int16_t *a = mergSortParam->a;
uint16_t *b = mergSortParam->b;
int16_t *temp1 = mergSortParam->temp1;
uint16_t *temp2 = mergSortParam->temp2;
int i = first;
int m = middle;
int j = middle + 1;
int n = end;
int k = 0;
while (i <= m && j <= n) {
if (a[i] < a[j]) { // 升序 为求稳定,相等时不交换
// if (a[i] >= a[j]) { // 降序,等于时取前面a[i]
temp1[k] = a[i];
temp2[k] = b[i];
k++;
i++;
} else {
temp1[k] = a[j];
temp2[k] = b[j];
k++;
j++;
}
}
while (i <= m) {
temp1[k] = a[i];
temp2[k] = b[i];
k++;
i++;
}
while (j <= n) {
temp1[k] = a[j];
temp2[k] = b[j];
k++;
j++;
}
int ii;
for (ii = 0; ii < k; ii++) {
a[first + ii] = temp1[ii];
b[first + ii] = temp2[ii];
}
}
// 闭区间 [first, last]
static void MergeSortAlg(AgsMergeSortStru *mergSortParam, int first, int last)
{
if (first < last) {
int middle = (first + last) / 2;
MergeSortAlg(mergSortParam, first, middle); //左半部分排好序
MergeSortAlg(mergSortParam, middle + 1, last); //右半部分排好序
MergeArray(mergSortParam, first, middle, last); //合并左右部分
}
}
以上版本已做参数打包压缩。
细节
注意升降序的调节
保证稳定性的关键在于,if (a[i] >= a[j]) {
语句。
- 升序时,用 <
- 降序时,用 >=
举例:
- arr a, i: 3, 2 (左侧)
- arr b, j: 2(s), 1 (右侧)
- merge: 3, 2, 2(s), 1
- 保证数值相同时,先放左侧子数组元素