1. 程式人生 > >分治法 求 逆序對數 的個數 時間複雜度為O(n*logn)

分治法 求 逆序對數 的個數 時間複雜度為O(n*logn)

思路:

分治法 歸併排序的過程中,有一步是從左右兩個陣列中,每次都取出小的那個元素放到tmp[]陣列中

右邊的陣列其實就是原陣列中位於右側的元素。當不取左側的元素而取右側的元素時,說明左側剩下的元素均比右側的第一個元素大,即均能構成一個逆序對。假設現在左側剩餘n個元素,則逆序對數+n。

另外,如果當所有右側的元素都取完,但是左側仍然有元素剩餘時,左側剩餘的元素已經在之前的運算中加到了逆序對中,不需要再新增一次

下面給出 歸併排序 和 求逆序對數 兩份程式碼:

code1:

歸併排序

#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;

int n;
int a[20];


void query(int a[], int first, int mid, int last, int tmp[]){
    int i = first, j = mid+1;
    int k = 0;
    while(i <= mid && j <= last){
        if(a[i] < a[j]) tmp[k++] = a[i++];
        else tmp[k++] = a[j++];
    }
    while(i <= mid){
        tmp[k++] = a[i++];
    }
    while(j <= last){
        tmp[k++] = a[j++];
    }
    for(int id = 0; id < k; id++){
        a[first + id] = tmp[id];
    }
}

void merge_sort(int* a, int L, int R, int* tmp){
    if(L < R){
        int M = L + (R-L)/2;
        merge_sort(a,L,M,tmp);
        merge_sort(a,M+1,R,tmp);
        query(a,L,M,R,tmp);
    }
}
int main(){
    scanf("%d",&n);
    for(int i = 0; i < n; i++){
        scanf("%d",&a[i]);
    }
    int tmp[20];
    merge_sort(a,0,n-1,tmp);
    for(int i = 0; i < n; i++){
        printf("%d ",a[i]);
    }
    printf("\n");
    return 0;
}

code2:

求逆序對數:

cnt 表示逆序對數的個數

#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;

int n;
int a[20];
int cnt;

void query(int a[], int first, int mid, int last, int tmp[]){
    int i = first, j = mid+1;
    int k = 0;
    while(i <= mid && j <= last){
        if(a[i] <= a[j]) tmp[k++] = a[i++];
        else{
            tmp[k++] = a[j++];
            cnt += mid-i+1;
        }
    }
    while(i <= mid){
        tmp[k++] = a[i++];
    }
    while(j <= last){
        tmp[k++] = a[j++];
    }
    for(int id = 0; id < k; id++){
        a[first + id] = tmp[id];
    }
}

void merge_sort(int* a, int L, int R, int* tmp){
    if(L < R){
        int M = L + (R-L)/2;
        merge_sort(a,L,M,tmp);
        merge_sort(a,M+1,R,tmp);
        query(a,L,M,R,tmp);
    }
}
int main(){
    scanf("%d",&n);
    for(int i = 0; i < n; i++){
        scanf("%d",&a[i]);
    }
    int tmp[20];
    cnt = 0;
    merge_sort(a,0,n-1,tmp);
    for(int i = 0; i < n; i++){
        printf("%d ",a[i]);
    }
    printf("cnt = %d\n",cnt);
    printf("\n");
    return 0;
}

LRJ給的程式碼不好理解....