歸併排序和逆序對

歸併排序

歸併排序步驟的劃分
- 劃分問題:把序列分成元素個數儘量相等的兩半
- 遞歸求解:把兩邊的元素分別排序
- 合併問題:把兩半的有序表合併成一個
從第三步描述可以知道當執行到第三步的時候兩邊的元素已經局部有序了。接下來要做的就是合併兩邊的元素;

歸併排序代碼

    /*
    A 是待排序數組; x,y代表待排序的區間; T是輔助數組;區間表示:[x,y);
    */
    void merge_sort(int * A, int x, int y, int *T)
    {
        if (y - x > 1)//遞歸出口
        {
            int m = x + ((y - x) >> 1);//注意>>優先級
            int p = x, q = m, i = x;
            merge_sort(A, x, m, T);//遞歸左半部分
            merge_sort(A, m, y, T);//遞歸右半部分
            while (p < m || q < y)//合併兩部分至T輔助數組
            {
                if (q >= y || (p < m && A[p] <= A[q]))
                    T[i++] = A[p++];
                else T[i++] = A[q++];
            }
            for (int i = x; i < y; i++)//將輔助數組的修改複製到數據數組
                A[i] = T[i];
        }
    }

逆序對

給定一列數A[1,2,…..,n],求滿足i(小於)j但Ai>Aj的有序對(i,j)的個數。

可以嵌套兩個循環枚舉所有的(i,j);但是當A數組的元素個數很大的時候就需要利用更高效的算法,而歸併排序在第三步可以利用。只需要在T[i++] = A[q++];句中加一句至T[i++] = A[q++], cnt += m - p;就可以達到統計的目的;

具體原理可以當(q >= y || (p < m && A[p] <= A[q]))該條件爲false的時候A[p] > A[q]或後半部分已經沒了,而前半部分和後半部分已經局部有序,所以如果A[p] > A[q]的時候,A[p+1]>A[q]也成立;所以可以直接利用cnt+=m-p統計j = q時i的個數。

示例代碼

/*
    problem:逆序對nlogn算法建立在歸併排序的基礎上,所以先介紹一下歸併排序,當歸並排序弄明白後再看逆序對的nlogn實現
    author:zxz
    time:
    memory:
*/

#include <iostream>
#include <stdlib.h>
#include <stdio.h>
#include <algorithm>
#include <map>
#include <set>
#include <stack>
#include <math.h>
#include <queue>
#include <string>
#include <sstream>
#include <vector>
#include <string.h>
#include <time.h>
using namespace std;

const int maxn = 111;
const int INF = 111;
int cnt = 0;
void init()
{
    cnt = 0;
}

/*
A 是待排序數組; x,y代表待排序的區間; T是輔助數組;區間表示:[x,y);
*/
void merge_sort(int * A, int x, int y, int *T)
{
    if (y - x > 1)
    {
        int m = x + ((y - x) >> 1);
        int p = x, q = m, i = x;
        merge_sort(A, x, m, T);
        merge_sort(A, m, y, T);
        while (p < m || q < y)
        {
            if (q >= y || (p < m && A[p] <= A[q]))
                T[i++] = A[p++];
            else T[i++] = A[q++], cnt += m - p;
        }
        for (int i = x; i < y; i++)
            A[i] = T[i];
    }
}

void solve()
{
    int A[maxn], b[maxn];
    int n;
    while (scanf("%d", &n) != EOF)
    {
        init();//初始化;
        for (int  i = 0; i < n; i++)
        {
            scanf("%d", &A[i]);
        }
        merge_sort(A, 0, n, b);
        for (int i = 0; i < n; i++)
        {
            printf("%d ", A[i]);
        }
        printf("%d", cnt);
    }
}

int main()
{
#ifndef ONLINE_JUDGE
    freopen("cin.txt", "r", stdin);
    //freopen("cout.txt", "w", stdout);
    int mao = clock();
#endif
    solve();
#ifndef ONLINE_JUDGE
    cerr << "Time:" << clock() - mao << "ms" << endl;
#endif
    return 0;
}

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章