簡體   English   中英

C 中的反轉計數歸並排序

[英]inversion count mergesort in C

從 1 到 n 的整數排列是一個序列 a1, a2, ..., an,使得從 1 到 n 的每個 integer 在序列中恰好出現一次。

當較大的在較小的之前時,排列中的兩個整數形成反轉。

例如,在排列 4 2 7 1 5 6 3 中,總共有 10 次反轉。 它們是以下對:4-2、4-1、4-3、2-1、7-1、7-5、7-6、7-3、5-3、6-3。

輸入 n 和數組 [n] 2<=n<=100,000

首先我解決了冒泡排序的問題,但后來我遇到了時間復雜度問題。

其次我解決了它合並排序但我做得不好

這是我的繩子

#include <stdio.h>
#include <malloc.h>
int n;

void sizein(){
    scanf("%d",&n);
}

int count=0;
static void merge(int data[],int p,int q,int r){
    int i,j,l;
    int k=p;
    int sorted[n];
    for(i=p,j=q+1;i<=q&&j<=r;){
        sorted[k++]=(data[i]<=data[j]) ? data[i++]:data[j++];
        if(data[i>data[j]]){
            count+=q-i;
        }
    }
    if(i>q){
        for(l=j;l<=r;l++,k++){
            sorted[k]=data[l];
        }
    }
    else{
        for(l=i;l<=q;l++,k++){
            sorted[k]=data[l];
        }
    }
    for(l=p;l<=r;l++){
        data[l]=sorted[l];
    }
}

void merge_sort(int data[],int p,int r){
    if(p<r){
        int q=(p+r)/2;
        merge_sort(data,p,q);
        merge_sort(data,q+1,r);
        merge(data,p,q,r);
    }
}

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

我應該在哪里修

我在您的代碼中找不到一些實現位,它們根據索引將 arrays 划分為子數組(作為基於值的快速排序排序)請查看下面提供的代碼

int q = p + (r - l) / 2;//recommended to be used in the function mergesort
int q=(p+r)/2;//your implementation

為您的 function 部分嘗試此代碼,因為我的代碼在超過一百萬個值的情況下運行良好,我無法清楚地看到在您的 function merge的實現中將值復制到的任何子數組我添加了注釋以使您更容易理解,變量的術語略有不同。

有關此算法的生動解釋,請參閱“ANANY LEVETIN-算法設計與分析簡介”一書

看看並試試這個

void merge(int arr[], int l, int m, int r)
{
    int i, j, k;
    int n1 = m - l + 1;
    int n2 = r - m;
 
    /* create temp arrays */
    int L[n1], R[n2];
 
    /* Copy data to temp arrays L[] and R[] */
    for (i = 0; i < n1; i++)
        L[i] = arr[l + i];
    for (j = 0; j < n2; j++)
        R[j] = arr[m + 1 + j];
 
    /* Merge the temp arrays back into arr[l..r]*/
    i = 0; // Initial index of first subarray
    j = 0; // Initial index of second subarray
    k = l; // Initial index of merged subarray
    while (i < n1 && j < n2) {
        if (L[i] <= R[j]) {
            arr[k] = L[i];
            i++;
        }
        else {
            arr[k] = R[j];
            j++;
        }
        k++;
    }
 
    /* Copy the remaining elements of L[], if there
    are any */
    while (i < n1) {
        arr[k] = L[i];
        i++;
        k++;
    }
 
    /* Copy the remaining elements of R[], if there
    are any */
    while (j < n2) {
        arr[k] = R[j];
        j++;
        k++;
    }
}

/* l is for left index and r is right index of the
sub-array of arr to be sorted */
void mergeSort(int arr[], int l, int r)
{
    if (l < r) {
        // Same as (l+r)/2, but avoids overflow for
        // large l and h
        int m = l + (r - l) / 2;
 
        // Sort first and second halves
        mergeSort(arr, l, m);
        mergeSort(arr, m + 1, r);
 
        merge(arr, l, m, r);
    }
}
 

/* Driver code */
int main()
{
    int arr[] = { 12, 11, 13, 5, 6, 7 };
    int arr_size = sizeof(arr) / sizeof(arr[0]);
 
    printf("Given array is \n");
    //printArray(arr, arr_size);
 
    mergeSort(arr, 0, arr_size - 1);
 
    printf("\nSorted array is \n");
    //printArray(arr, arr_size);
    return 0;
}

在閱讀了一段時間的代碼后,我仍然不能說我理解了計算反轉的想法。 但是,我可以指出其中對我來說似乎不正確的三件事。

首先,我看不到你在哪里調用sizein() function 來初始化n變量。

第二個問題是這里的條件:

    if(data[i>data[j]]){
        count+=q-i;
    }

您將索引i與看起來很奇怪的數據項data[j]的值進行比較。 更糟糕的是,如果您要對一組幾何圖形或一組歌曲進行排序,由於要比較的數據類型不兼容,這可能是不可能的。 更糟糕的是,即使比較成功,例如int索引和data[]中的int值,如果比較滿足,則比較結果為int值 1,否則為 0。 因此,此條件將解析為

    if(data[0]){
        count+=q-i;
    }

或者

    if(data[1]){
        count+=q-i;
    }

這顯然是錯誤的。

正確的代碼如下所示:

    if (data[i] > data[j]) {
        count += q - i;
    }

如果在運算符和它們的操作數之間留出適當的間距,錯誤會更加明顯。

另一個錯誤潛伏在對merge_sort()的調用中。 首先,用這個循環填充data[]數組:

for (i = 0; i < n; i ++) {
    scanf("%d", &data[i]);
}

顯然,您使用索引從0n-1的數據填充n -items 數組。

然后調用合並排序例程:

merge_sort( data, 0, n);

這表明參數p是第一項或要排序的部分的索引,而q是最后一項。 但是,這與遞歸調用不同:

    merge_sort( data, p, q);
    merge_sort( data, q+1, r);

在第一次調用中設置q作為結束索引,在第二次調用中設置q+1作為開始索引表示結束索引是包含的,即它是要排序的段中最后一項的 position。 否則,這兩個調用將使項data[q]未排序。 這也來自內部循環,當i <= q或 whle l <= r等時繼續。

所以最初的電話不應該是

merge_sort( data, 0, n);

反而

merge_sort( data, 0, n-1);

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM