归并排序

1 篇文章 0 订阅

归并排序(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 MB
Submit: 557   Solved: 114
[ Submit][ Status][ Web Board]

Description

在一个排列中,如果一对数的前后位置与大小顺序相反,即前面的数不小于后面的数,那么它们就称为一个逆序。一个排列中逆序的总数就称为这个排列的逆序数。

如2 4 3 1中,2 1,4 3,4 1,3 1是逆序,逆序数是4。给出一个整数序列,求该序列的逆序数。

Input

多组测试数据

每组测试数据分两行,第一行一个正整数n(n <= 50000)

第二行有n个元素( 0 <= A[i] <= 10^9)

Output

每组测试数据输出一行表示逆序数

Sample Input

4
2 4 3 1
3
1 1 1

Sample Output

4
3

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 MB
Submit: 256   Solved: 82
[ Submit][ Status][ Web Board]

Description

在一个排列中,如果一对数的前后位置与大小顺序相反,即前面的数大于后面的数,那么它们就称为一个逆序。一个排列中逆序的总数就称为这个排列的逆序数。

如2 4 3 1中,2 1,4 3,4 1,3 1是逆序,逆序数是4。
**相对于逆序数而言,当然有正序数,即:在一个排列中,如果一对数的前后位置与大小顺序相同,即前面的数小于后面的数,那么它们就称为一个正序。一个排列中正序的总数就称为这个排列的正序数。
如2 4 3 1中,2 4,2 3是正序,正序数是2。

Input

多组测试数据

每组测试数据分两行,第一行一个正整数n(n <= 50000)

第二行有n个元素( 0 < A[i] <= 500000)

Output

每组测试数据输出一行表示逆序数

Sample Input

4
2 4 3 1

Sample Output

2

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;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值