归并排序(Merge sort)是建立在归并操作上的一种有效的排序算法。该算法是采用分治法(Divide and Conquer)的一个非常典型的应用。
算法步骤:
1. 申请空间,使其大小为两个已经排序序列之和,该空间用来存放合并后的序列
2. 设定两个指针,最初位置分别为两个已经排序序列的起始位置
3. 比较两个指针所指向的元素,选择相对小的元素放入到合并空间,并移动指针到下一位置
4. 重复步骤3直到某一指针达到序列尾
5. 将另一序列剩下的所有元素直接复制到合并序列尾
#include <stdlib.h>
#include <stdio.h>
void Merge(int sourceArr[],int tempArr[], int startIndex, int midIndex, int endIndex)
{
int i = startIndex, j=midIndex+1, k = startIndex;
while(i != midIndex + 1 && j != endIndex + 1)
{
if(sourceArr[i] >= sourceArr[j])
tempArr[k++] = sourceArr[j++];
else
tempArr[k++] = sourceArr[i++];
}
while(i != midIndex+1)
tempArr[k++] = sourceArr[i++];
while(j != endIndex+1)
tempArr[k++] = sourceArr[j++];
for(i = startIndex; i <= endIndex; i++)
sourceArr[i] = tempArr[i];
}
//内部使用递归
void MergeSort(int sourceArr[], int tempArr[], int startIndex, int endIndex)
{
int midIndex;
if(startIndex < endIndex)
{
midIndex = (startIndex + endIndex) / 2;
MergeSort(sourceArr, tempArr, startIndex, midIndex);
MergeSort(sourceArr, tempArr, midIndex+1, endIndex);
Merge(sourceArr, tempArr, startIndex, midIndex, endIndex);
}
}
int main(int argc, char * argv[])
{
int a[8] = {50, 10, 20, 30, 70, 40, 80, 60};
int i, b[8];
MergeSort(a, b, 0, 7);
for(i=0; i<8; i++)
printf("%d ", a[i]);
printf("\n");
return 0;
}
补上两题例题:
ZMUC-1203逆序数
1203: 逆序数
Time Limit: 1 Sec Memory Limit: 128 MBSubmit: 557 Solved: 114
[ Submit][ Status][ Web Board]
Description
在一个排列中,如果一对数的前后位置与大小顺序相反,即前面的数不小于后面的数,那么它们就称为一个逆序。一个排列中逆序的总数就称为这个排列的逆序数。
Input
多组测试数据
每组测试数据分两行,第一行一个正整数n(n <= 50000)
第二行有n个元素( 0 <= A[i] <= 10^9)
Output
每组测试数据输出一行表示逆序数
Sample Input
Sample Output
HINT
Source
【解析】
用一个全局变量ans保存逆序数的值,当前半个数组(记为A)的第一个值大于后半个数组(记为B)的第一个值时,A数组所有剩余元素个数。
#include <bits/stdc++.h>
using namespace std;
int ans, a[50010], b[50010];
void hebing(int a[], int first, int mid, int last, int temp[])
{
int i = first, j = mid + 1;
int k = 0;
while (i <= mid && j <= last)
{
if (a[i] < a[j])
temp[k++] = a[i++];
else
{
ans += j - k - first;
temp[k++] = a[j++];
}
}
while (i <= mid)
temp[k++] = a[i++];
while (j <= last)
temp[k++] = a[j++];
for (int i = 0; i < k; i++)
a[first + i] = temp[i];
}
void mersort(int a[], int first, int last, int temp[])
{
if (first < last)
{
int mid = (first + last) / 2;
mersort(a, first, mid, temp);
mersort(a, mid + 1, last, temp);
hebing(a, first, mid, last, temp);
}
}
int main()
{
int n;
while (~scanf("%d", &n))
{
for (int i = 0; i < n; i++)
scanf("%d", &a[i]);
ans = 0;
mersort(a, 0, n - 1, b);
printf("%d\n", ans);
}
return 0;
}
ZCMU-1205正序数
1205: 正序数
Time Limit: 1 Sec Memory Limit: 128 MBSubmit: 256 Solved: 82
[ Submit][ Status][ Web Board]
Description
在一个排列中,如果一对数的前后位置与大小顺序相反,即前面的数大于后面的数,那么它们就称为一个逆序。一个排列中逆序的总数就称为这个排列的逆序数。
Input
多组测试数据
每组测试数据分两行,第一行一个正整数n(n <= 50000)
第二行有n个元素( 0 < A[i] <= 500000)
Output
每组测试数据输出一行表示逆序数
Sample Input
Sample Output
HINT
Source
【解析】
同理
#include <bits/stdc++.h>
using namespace std;
int ans, a[50010], b[50010];
void hebing(int a[], int first, int mid, int last, int temp[])
{
int i = first, j = mid + 1;
int k = 0;
while (i <= mid && j <= last)
{
if (a[i] < a[j])
{
ans += last - j + 1;
temp[k++] = a[i++];
}
else
{
//ans += j - k - first;
temp[k++] = a[j++];
}
}
while (i <= mid)
temp[k++] = a[i++];
while (j <= last)
temp[k++] = a[j++];
for (int i = 0; i < k; i++)
a[first + i] = temp[i];
}
void mersort(int a[], int first, int last, int temp[])
{
if (first < last)
{
int mid = (first + last) / 2;
mersort(a, first, mid, temp);
mersort(a, mid + 1, last, temp);
hebing(a, first, mid, last, temp);
}
}
int main()
{
int n;
while (~scanf("%d", &n))
{
for (int i = 0; i < n; i++)
scanf("%d", &a[i]);
ans = 0;
mersort(a, 0, n - 1, b);
printf("%d\n", ans);
}
return 0;
}