归并排序
归并排序(MERGE-SORT)是建立在归并操作上的一种有效的排序算法,该算法是采用分治法(Divide and Conquer)的一个非常典型的应用。将已有序的子序列合并,得到完全有序的序列;即先使每个子序列有序,再使子序列段间有序。若将两个有序表合并成一个有序表,称为二路归并。归并排序是一种稳定的排序方法。
归并排序的时间复杂度是O(nlogn)。
归并操作(merge),也叫归并算法,指的是将两个顺序序列合并成一个顺序序列的方法。
如 设有数列{6,202,100,301,38,8,1}
初始状态:6,202,100,301,38,8,1
第一次归并后:{6,202},{100,301},{8,38},{1}
第二次归并后:{6,100,202,301},{1,8,38}
第三次归并后:{1,6,8,38,100,202,301}
算法代码实现
#include <stdio.h>
int a[100005];
int b[100005];
void sort(int low, int mid, int high)
{
int i = low;
int j = mid + 1;
int k = 0;
while(i <= mid && j <= high)
{
if(a[i] <= a[j])
b[k++] = a[i++];
else
b[k++] = a[j++];
}
while(i <= mid)
b[k++] = a[i++];
while(j <= high)
b[k++] = a[j++];
for(i = low; i <= high; i++)
a[i] = b[i - low];
}
void merge(int low, int high)
{
if(low < high)
{
int mid = (low + high) / 2;
merge(low, mid);
merge(mid + 1, high);
sort(low, mid, high);
}
}
int main()
{
int n;
scanf("%d", &n);
for(int i = 0; i < n; i++)
scanf("%d", a + i);
printf("排序前:");
for(int i = 0; i < n; i++)
{
printf("%d ", a[i]);
}
printf("\n\n");
merge(0, n - 1);
printf("排序后:");
for(int i = 0; i < n; i++)
{
printf("%d ", a[i]);
}
printf("\n");
}
运用归并求逆序数
如 设有数列{6,202,100,301,38,8,1}
初始状态:6,202,100,301,38,8,1
第一次归并后:{6,202},{100,301},{8,38},{1},比较次数:3;
第二次归并后:{6,100,202,301},{1,8,38},比较次数:4;
第三次归并后:{1,6,8,38,100,202,301},比较次数:4;
总的比较次数为:3+4+4=11;
逆序数为14;
代码实现
#include <stdio.h>
int a[100005];
int b[100005];
long long cnt = 0;
void sort(int low, int mid, int high)
{
int i = low;
int j = mid + 1;
int k = 0;
while(i <= mid && j <= high)
{
if(a[i] <= a[j])
b[k++] = a[i++];
else
{
cnt += mid - i + 1;
b[k++] = a[j++];
}
}
while(i <= mid)
b[k++] = a[i++];
while(j <= high)
b[k++] = a[j++];
for(i = low; i <= high; i++)
a[i] = b[i - low];
}
void merge(int low, int high)
{
if(low < high)
{
int mid = (low + high) / 2;
merge(low, mid);
merge(mid + 1, high);
sort(low, mid, high);
}
}
int main()
{
int n;
scanf("%d", &n); //输入n个数
for(int i = 0; i < n; i++)
scanf("%d", a + i);
merge(0, n - 1);
printf("%lld\n", cnt);
}