归并排序以及逆序对个数

#include<iostream>

using namespace std;

void Merge(int arr[],int r[],int start,int mid,int end)
{
	int i = start, j = mid+1,k=start;
	while(i<=mid && j<= end)
	{
		if(arr[i]>arr[j])
		{
			r[k++] = arr[j++];
		}
		else{
			r[k++] = arr[i++];
		}	
	}
	while(i<=mid)
	{
		r[k++]=arr[i++];
	}
	while(j<=end)
	{
		r[k++] = arr[j++];
	}
}

void MergeSort(int arr[],int start,int end)
{
	int r[10000];
	if(start==end) return ;
	int mid = (start+end)/2;
	MergeSort(arr,start,mid);
	MergeSort(arr,mid+1,end);
	Merge(arr,r,start,mid,end);
	for(int i=start;i<=end;i++)
	{
		arr[i] = r[i];
	}
}

int main()
{
	int arr[]={9,7,3,6,5,8,1,4,2,10};
	MergeSort(arr,0,9);
	for(int i=0;i<10;i++)
	{
		cout<<arr[i]<<" ";
	}
	
	return 0;
}

很多小白不知道为什么函数中这么多参数。我来一一讲解:

void MergeSort(int arr[],int start,int end)

首先看这个MergeSort函数。主函数中首先调用它。它是归并排序的主入口。参数arr[]是要排序的数组。start是开始位置,end是结束位置。

void MergeSort(int arr[],int start,int end)
{
	int r[10000];  //这个是一个辅助数组,现在不知道要用它,看到后面在回来看这个。
	if(start==end) return ;  //想一下,一直“二分”,总要有个结束的位置,位置就是只要一个元素(即这二者相等)
	int mid = (start+end)/2;//这是来计算中间位置的
	MergeSort(arr,start,mid);//调用自身,注意这里真正有用的是调用到最下面一层的“start、mid”的数值
	MergeSort(arr,mid+1,end);//当执行完这个时就会出现下面一个图(1)
	Merge(arr,r,start,mid,end);//进行合并,这里用到了辅助数组,因为要把合并的数据放在辅助数组中,所以要另开一个辅助数组。
	for(int i=start;i<=end;i++)//我们想要的是原数组排好序,所以讲辅助数组赋值给原数组。
	{
		arr[i] = r[i];
	}
}

仔细看已知两个有序数组,如何合并成一个大的数组呢?

void Merge(int arr[], int r[], int start, int mid, int end)
{
    // 合并两个已排序的子数组到数组 r 中。
    int i = start, j = mid + 1, k = start; 
    // 初始化三个指针:i 指向第一个子数组的起始位置,j 指向第二个子数组的起始位置(mid+1),k 指向结果数组的起始位置。

    while (i <= mid && j <= end)
    {
        // 循环条件:两个子数组都没有遍历完。
        if (arr[i] > arr[j])
        {
            // 如果第一个子数组的当前元素大于第二个子数组的当前元素,
            r[k++] = arr[j++];
            // 将第二个子数组的元素放入结果数组中,并移动 j 和 k 指针。
        }
        else
        {
            // 否则,将第一个子数组的当前元素放入结果数组中。
            r[k++] = arr[i++];
            // 并移动 i 和 k 指针。
        }
    }

    while (i <= mid)
    {
        // 将第一个子数组剩余的元素复制到结果数组中。
        r[k++] = arr[i++];
        // 移动 i 和 k 指针。
    }

    while (j <= end)
    {
        // 将第二个子数组剩余的元素复制到结果数组中。
        r[k++] = arr[j++];
        // 移动 j 和 k 指针。
    }
}
  1. void Merge(int arr[], int r[], int start, int mid, int end):

    • 声明了一个名为 Merge 的函数,接受五个参数:待合并的数组 arr,结果数组 r,起始索引 start,中间索引 mid 和结束索引 end
  2. int i = start, j = mid + 1, k = start;:

    • 初始化三个指针:i 指向第一个子数组的起始位置 startj 指向第二个子数组的起始位置 mid + 1k 指向结果数组的起始位置 start
  3. while (i <= mid && j <= end):

    • 当 i 指针未超过第一个子数组的结束位置 mid 且 j 指针未超过第二个子数组的结束位置 end 时,执行循环。
  4. if (arr[i] > arr[j]):

    • 如果第一个子数组的当前元素 arr[i] 大于第二个子数组的当前元素 arr[j]
  5. r[k++] = arr[j++];:

    • 将第二个子数组的当前元素 arr[j] 赋值给结果数组 r 的当前位置 k,然后将 j 和 k 向后移动一位。
  6. else { r[k++] = arr[i++]; }:

    • 否则,将第一个子数组的当前元素 arr[i] 赋值给结果数组 r 的当前位置 k,然后将 i 和 k 向后移动一位。
  7. while (i <= mid):

    • 将第一个子数组中剩余的元素复制到结果数组 r 中。
  8. r[k++] = arr[i++];:

    • 将 arr[i] 赋值给 r[k],然后将 i 和 k 向后移动一位。
  9. while (j <= end):

    • 将第二个子数组中剩余的元素复制到结果数组 r 中。
  10. r[k++] = arr[j++];:

    • 将 arr[j] 赋值给 r[k],然后将 j 和 k 向后移动一位。

接下来看一个由归并排序推导出来的题目:

对于给定的数组A,计算其逆序对的总数。即:

【输入形式】

输入包含1组测试用例。

一个测试用例占一行,第一个整数表示数组的长度,后面紧跟者数组中的各个整数元素,中间都用一个空格分开。

数组的长度

范围

每个数字A[i]的范围为

【输出形式】

输出一个整数,表示逆序对的个数。

【样例输入】

5

4 5 1 3 2

【样例输出】

7

其实只要加一行代码就OK了:

要统计数组中的逆序对数量,可以在合并两个子数组的过程中,当发现左子数组的当前元素大于右子数组的当前元素时,增加逆序对的计数。具体来说,如果 arr[i] > arr[j],则 arr[i] 与 arr[j] 及其之后的所有元素形成逆序对,因为子数组是有序的

#include<iostream>

using namespace std;
int res=0;
void Merge(int arr[],int r[],int start,int mid,int end)
{
	int i = start, j = mid+1,k=start;
	while(i<=mid && j<= end)
	{
		if(arr[i]>arr[j])
		{
			r[k++] = arr[j++];
			res += (mid - i + 1); // 增加逆序对的数量
		}
		else{
			r[k++] = arr[i++];
		}	
	}
	while(i<=mid)
	{
		r[k++]=arr[i++];
	}
	while(j<=end)
	{
		r[k++] = arr[j++];
	}
}

void MergeSort(int arr[],int start,int end)
{
	int r[10000];
	if(start==end) return ;
	int mid = (start+end)/2;
	MergeSort(arr,start,mid);
	MergeSort(arr,mid+1,end);
	Merge(arr,r,start,mid,end);
	for(int i=start;i<=end;i++)
	{
		arr[i] = r[i];
	}
}

int main()
{
	int arr[10000];
	int n;
	cin>>n;
	for(int i=1;i<=n;i++) cin>>arr[i];
	MergeSort(arr,1,n);
	for(int i=1;i<=n;i++)
	{
		cout<<arr[i]<<" ";
	}
	cout<<endl;
	cout<<"逆序对数量:"<<res<<endl;
	
	return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

背水

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值