简体   繁体   English

C 中的反转计数归并排序

[英]inversion count mergesort in C

A permutation of integers from 1 to n is a sequence a1, a2, ..., an, such that each integer from 1 to n is appeared in the sequence exactly once.从 1 到 n 的整数排列是一个序列 a1, a2, ..., an,使得从 1 到 n 的每个 integer 在序列中恰好出现一次。

Two integers in а permutation form an inversion, when the bigger one is before the smaller one.当较大的在较小的之前时,排列中的两个整数形成反转。

As an example, in the permutation 4 2 7 1 5 6 3, there are 10 inversions in total.例如,在排列 4 2 7 1 5 6 3 中,总共有 10 次反转。 They are the following pairs: 4–2, 4–1, 4–3, 2–1, 7–1, 7–5, 7–6, 7–3, 5–3, 6–3.它们是以下对:4-2、4-1、4-3、2-1、7-1、7-5、7-6、7-3、5-3、6-3。

Input n and array[n] 2<=n<=100,000输入 n 和数组 [n] 2<=n<=100,000

First I solved problem with bubble sorting but then i met time complexity problem.首先我解决了冒泡排序的问题,但后来我遇到了时间复杂度问题。

Second I solved it mergesort but I didn't do well其次我解决了它合并排序但我做得不好

Here is my cord这是我的绳子

#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;
}

Where should i fix it我应该在哪里修

I cannot find some implementation bits in your code that divides the arrays into sub-arrays based on the index(as quick sort sorts based on value) kindly have a look at the code provided below我在您的代码中找不到一些实现位,它们根据索引将 arrays 划分为子数组(作为基于值的快速排序排序)请查看下面提供的代码

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

try this code for your function part as my code runs well with over half a million values, I cannot clearly see any subarray to which values are copied in your implementation of the function merge I have added comments to make it easier for you to understand, the terminology of the variables are slightly different.为您的 function 部分尝试此代码,因为我的代码在超过一百万个值的情况下运行良好,我无法清楚地看到在您的 function merge的实现中将值复制到的任何子数组我添加了注释以使您更容易理解,变量的术语略有不同。

refer "ANANY LEVETIN-INTRODUCTION TO THE DESIGN AND ANALYSIS OF ALGORITHS" book for a vivid explanation on this algorithm有关此算法的生动解释,请参阅“ANANY LEVETIN-算法设计与分析简介”一书

Have a look and try this看看并试试这个

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;
}

After reading the code for some time I still can not say I understand the idea of counting the inversions.在阅读了一段时间的代码后,我仍然不能说我理解了计算反转的想法。 However, I can point out three things in it which seem incorrect to me.但是,我可以指出其中对我来说似乎不正确的三件事。

First, I can't see where you call the sizein() function to initialize the n variable.首先,我看不到你在哪里调用sizein() function 来初始化n变量。

The second problem is the condition here:第二个问题是这里的条件:

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

You compare the index i to the value of a data item data[j] which looks strange.您将索引i与看起来很奇怪的数据项data[j]的值进行比较。 Even worse, if you were to sort an array of geometric figures or an array of songs it could be just impossible due to incompatibility of the types of data to be compared.更糟糕的是,如果您要对一组几何图形或一组歌曲进行排序,由于要比较的数据类型不兼容,这可能是不可能的。 What's even worse, even if comparison succeedes, as in the case of an int index and an int value in data[] ,the result of comparison is an int value 1 if comparison is satisfied or 0 otherwise.更糟糕的是,即使比较成功,例如int索引和data[]中的int值,如果比较满足,则比较结果为int值 1,否则为 0。 As a result this condition will resolve to因此,此条件将解析为

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

or to或者

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

which is obviously wrong.这显然是错误的。

The correct code looks like this:正确的代码如下所示:

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

The error would be more apparent if you left appropriate spacing between operators and their operands.如果在运算符和它们的操作数之间留出适当的间距,错误会更加明显。

Yet another error lurks in the call to merge_sort() .另一个错误潜伏在对merge_sort()的调用中。 First, you fill the data[] array with this loop:首先,用这个循环填充data[]数组:

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

Obviously, you fill an n -items array with data at indices from 0 through n-1 .显然,您使用索引从0n-1的数据填充n -items 数组。

Then you call the merge-sorting routine:然后调用合并排序例程:

merge_sort( data, 0, n);

which suggests the parameter p is the index of the first item or the part to be sorted and q is one-past-the last item.这表明参数p是第一项或要排序的部分的索引,而q是最后一项。 However, this disagrees with recursive calls:但是,这与递归调用不同:

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

Setting q as the ending index in the first call and q+1 as the starting index in the second suggests the ending index is inclusive , that is, it is the position of the last item in the segment to be sorted.在第一次调用中设置q作为结束索引,在第二次调用中设置q+1作为开始索引表示结束索引是包含的,即它是要排序的段中最后一项的 position。 Otherwise the two calls would leave the item data[q] unsorted.否则,这两个调用将使项data[q]未排序。 This also follows from internal loops, which continue while i <= q or whle l <= r etc.这也来自内部循环,当i <= q或 whle l <= r等时继续。

So the initial call shouldn't be所以最初的电话不应该是

merge_sort( data, 0, n);

but rather反而

merge_sort( data, 0, n-1);

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM