一、归并排序原理
归并排序(Merge Sort)是一种基于分治法的高效、稳定排序算法。其原理是将数组不断地分割成两个子数组,直到每个子数组只包含一个元素为止;然后逐步合并这些子数组,在合并的过程中进行排序,最终得到完全有序的数组。
二、归并排序标准代码
void merge_sort(int q[], int l, int r)
{
if (l >= r) return;
int mid = l + r >> 1;
merge_sort(q, l, mid), merge_sort(q, mid + 1, r);
int k = 0, i = l, j = mid + 1;
while (i <= mid && j <= r)
if (q[i] <= q[j]) tmp[k++] = q[i++];
else tmp[k++] = q[j++];
while (i <= mid) tmp[k++] = q[i++];
while (j <= r) tmp[k++] = q[j++];
for (int i = 0, j = l; j <= r; i++, j++) q[j] = tmp[i];
}
三、代码解析
1.
void merge_sort(int q[], int l, int r)
传入数组,以及所需排序的区间
2.
if (l >= r) return;
递归结束的条件
3.
int mid = l + r >> 1;
merge_sort(q, l, mid), merge_sort(q, mid + 1, r);
l + r >> 1相当于(l + r)/2向下取整;程序先归并再执行其于程序,将整个数组两份两份的往下分,直到只剩一个元素,然后接下来就是个数数1,1比较,1,1比较,...,比较后的两个数有序,然后个数数2,2比较,2,2比较,...,比较后的4个数依然有序,以此类推直到全部结果有序
4.
int k = 0, i = l, j = mid + 1;
设定变量,k 初始化,i , j 为两个指针,i 为开头,j 为中间位置,将数组分为两部分
5.
while (i <= mid && j <= r)
if (q[i] <= q[j]) tmp[k++] = q[i++];
else tmp[k++] = q[j++];
循环条件:i 和 j 都没超过各自的结尾,
循环程序;比较 q[i] 和 q[j],将 i 和 j 所对应的数组元素较小的放入新数组 tmp,将放入新数组的指针+1指向下一个元素再次比较以此类推,最终会有一个指针结束而另一个指针有剩余
6.
while (i <= mid) tmp[k++] = q[i++];
while (j <= r) tmp[k++] = q[j++];
将两个指针中有剩余的数组元素全部放进新数组,注意排序是从两个开始,举个例子,a 和 b 比较然后排序 ,c 和 d 比较后排序,然后排好的 ab 和排好的 cd 比较后排序,因此排序之前的两部分数组都是有序的,所以直接放入新数组
7.
for (int i = 0, j = l; j <= r; i++, j++) q[j] = tmp[i];
将数组 q 更新,注意我们是在 l 到 r 范围内排序的,所以将此部分更新,设定两个变量,j 从 l 开始到 r 结束
四、总结
归并排序就是利用递归将整个问题精确到最小个数,再从小到大比较合并的过程
五、逆序数计算
1.代码
long long merge_sort(int q[], int l, int r)
{
if (l >= r) return 0;
int mid = l + r >> 1;
res=merge_sort(q, l, mid) + merge_sort(q, mid + 1, r);//归并求和
int k = 0, i = l, j = mid + 1;//起始指针
while (i <= mid && j <= r)//同时满足条件执行
if (q[i] <= q[j]) tmp[k++] = q[i++];//小的放新数组
else tmp[k++] = q[j++],res += mid - i + 1;//j较小的话放入后逆序数为剩余i的数量
while (i <= mid) tmp[k++] = q[i++];//剩余无法比较的放入新数组
while (j <= r) tmp[k++] = q[j++];
for (int i = 0, j = l; j <= r; i++, j++) q[j] = tmp[i];//更新数组q
return res;//返回值
}
2.解析
在归并排序的基础上进行改造,首先函数变为有返回值的函数,因为 j 在 i 右边,所以当 j 放进新数组后,逆序数即为 i 数组中剩余的元素个数 mid - i + 1,再将递归函数加起来即可