Merge sort and reverse order pair quantity template questions

merge sort

Merge sort template questions

You are given an array of integers of length n.

Please use merge sort to sort this array from smallest to largest.

And output the sorted array in order.

Input format
The input consists of two lines, the first line contains the integer n.

The second line contains n integers (all integers are in the range of 1∼109), representing the entire array.

Output format
The output is a total of one line, containing n integers, representing the sorted sequence.

Data range
1≤n≤100000
Input example:
5
3 1 2 4 5
Output example:
1 2 3 4 5

analyze

Merge sort adopts the idea of ​​​​divide and conquer. If you understand the recursive code for the first time, you can understand the next steps as: the problem has been divided into the most initial state, that is, only the comparison and merging of two numbers.

1、有数组 q, 左端点 l, 右端点 r

2、确定划分边界 mid

3、递归处理子问题 q[l..mid], q[mid+1..r]

insert image description here
4. Merge sub-problems

1、主体合并:至少有一个小数组添加到 tmp 数组中

2、剩余处理:可能存在的剩下的一个小数组的尾部直接添加到 tmp 数组中

3、物归原主:tmp 数组覆盖原数组

insert image description here

code template

The code has been written with comments as much as possible, and I believe that I will be able to understand how the code is obtained after watching it patiently.

#include <iostream>


using namespace std;

const int N = 100010;

int a[N],tmp[N];

 // 归并排序
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)
    {
    //如果前一半的值小于后一半的值的话,将前一半的这个值放入tmp中,指针i向后挪动1位
        if (q[i] <= q[j]) tmp[k ++ ] = q[i ++ ];
        //否则指针j向后挪动一位
        else tmp[k ++ ] = q[j ++ ];
    }
    //当不满足i <= mid && j <= r后,说明有一半的已经走向了尽头,剩下的就全部放入tmp中就可以了
    while (i <= mid) tmp[k ++ ] = q[i ++ ];
    while (j <= r) tmp[k ++ ] = q[j ++ ];
    //将tmp按顺序全部放回q中
    for (i = l, j = 0; i <= r; i ++, j ++ ) q[i] = tmp[j];
}

int main()
{
    int n;
    scanf("%d", &n);
    for (int i = 0; i < n; i ++ ){
        scanf("%d", &a[i]);
    }
    merge_sort(a,0,n-1);
    
    for (int i = 0; i < n; i ++ )
        printf("%d ", a[i]);
    return 0;
}

Reverse Pair Quantity Statistics

The principle is still merge and sort. After the problem is continuously disassembled and narrowed down, it is divided into two sections. First, analyze the left and right sections, and calculate whether there are reverse pairs in the respective numbers of each section. If so, record the number in res. Finally, special circumstances, compare the two segments together. Calculate whether the LEFT segment has a number of A and RIGHT sections. B forming a counter-order pair. If it exists, the number is MID-I+1. The reason is that our code is based on merger and sorting. Of course, it should be noted that this will not change the number of counter-order pairs and ensure that if there is existence, The B of the Right paragraph is the inverse order of the A of the left paragraph, so the left segment from i to MID is the reverse order pair of B, so

res += mid-i+1

Title Description
Given a sequence of integers of length n, please count the number of reversed pairs in the sequence.

The definition of reverse pair is as follows: for the i-th and j-th elements of the sequence, if i<j and a[i]>a[j], then it is a reverse pair; otherwise, it is not.

Input format
The first line contains the integer n, indicating the length of the sequence.

The second line contains n integers representing the entire sequence.

Output format
Output an integer, indicating the number of reversed pairs.

The data range
is 1≤n≤100000, and
the value range of the elements in the array is [1,109].

Input sample:
6
2 3 4 5 6 1
Output sample:
5

#include <iostream>


using namespace std;

typedef long long LL;

const int N = 100010;

int q[N],tmp[N];


LL merge_sort(int l, int r)  // 归并排序
{
    if (l >= r) return 0;

    int mid = l + r >> 1;//从中间划分
    //结果用res存
    LL res =  merge_sort(l, mid)+merge_sort(mid + 1, r);

    //归并排序,依旧是分成两段进行比较
    int k= 0, i = l, j = mid + 1;
    //二路归并,用两个指针
    //这一次要找的是大于的位置,所以依旧是当左边小于右边时,就i++
    while (i <= mid && j <= r)
    //如果前一半的值小于后一半的值的话,将前一半的这个值放入tmp中,指针i向后挪动1位
        if (q[i] <= q[j]) tmp[k++] = q[i++];
        //否则指针j向后挪动一位,并且此时可以将res的结果得出
        //说明从i开始到mid结束的数的个数都是符合res结果的,所以res = mid -i+ 1
        else 
        {
            tmp[k++] = q[j++];
            res += mid - i + 1 ;
        } 
    //当不满足i <= mid && j <= r后,说明有一半的已经走向了尽头,剩下的就全部放入tmp中就可以了
    while(i<= mid)
        tmp[k++] = q[i++];
    while(j<= r)
        tmp[k++] = q[j++];
    //物归原主
    for (int i = l,j = 0; i <=r; i ++, j++){
        q[i] = tmp[j];
    }
    return res ;
}

int main()
{
    int n;
    //输出序列长度
    cin >> n;
    //输入序列
    for (int i = 0; i < n; i ++ ){
        cin >> q[i];
    }
    
    cout << merge_sort(0,n-1) <<endl;
    return 0;
}

Guess you like

Origin blog.csdn.net/sand_wich/article/details/128555988