简体   繁体   English

计算插入排序中的掉期数

[英]counting number of swaps in insertion sort

In the problem given here , i have to count total no. 这里给出的问题中,我必须计算总数。 of swaps required while sorting an array using insertion sort. 使用插入排序对数组进行排序时所需的交换数。
here is my approach 这是我的方法

#include <stdio.h>
int main()
{
    int t, N, swaps, temp, i, j;
    scanf("%d", &t);

    while(t--){
        scanf("%d", &N);

        int arr[N];
        swaps = 0;

        for(i=0; i<N; ++i){

            scanf("%d", &temp);

            j=i;
            while(j>0 && arr[j-1] > temp){
                arr[j] = arr[j-1];
                ++swaps;
                --j;
            }

            arr[j] = temp;
        }
        printf("%d\n", swaps);
    }

    return 0;
}

but, this soln is giving time limit exceeded. 但是,这种解决方案给了时间限制。

How can i make it more fast? 我怎样才能使其更快?
and, what are the other better solutions of this problem? 并且,该问题还有哪些其他更好的解决方案?

this is a standard problem named inversion count 这是一个名为倒数的标准问题

This can be solved using mergesort in O(n*lg(n)). 这可以使用O(n * lg(n))中的mergesort解决。 Here is my code for counting the inversions 这是我计算反转的代码

int a[200001];
long long int count;
void Merge(int p,int q,int r)
{
    int n1,n2,i,j,k,li,ri;
    n1=q-p+1;
    n2=r-q;
    int l[n1+1],rt[n2+1];
    for(i=0;i<n1;i++)
        l[i]=a[p+i];
    for(i=0;i<n2;i++)
        rt[i]=a[q+1+i];
    l[n1]=LONG_MAX;
    rt[n2]=LONG_MAX;
    li=0;ri=0;
    for(i=p;i<=r;i++)
    {
        if(l[li]<=rt[ri])
            a[i]=l[li++];
        else
        {
            a[i]=rt[ri++];
            count+=n1-li;
        }
    }
}
void mergesort(int p,int r)
{
    if(p<r)
    {
        int q=(p+r)/2;

        mergesort(p,q);
        mergesort(q+1,r);
        Merge(p,q,r);
    }
}    
int main()
{
    scanf("%d",&n);
    for(i=0;i<n;i++)
        scanf("%d",&a[i]);
    count=0;
    mergesort(0,n-1);
    printf("%lld\n",count);
}    

Basically the problem of inversion count is to find the no. 基本上,反转计数的问题是找到编号。 of pairs i and j where j>i such that a[i]>a[j] 对i和j,其中j> i使得a [i]> a [j]

To know the idea behind this you should know the basic merge sort algorithm 要了解其背后的想法,您应该了解基本的合并排序算法

http://en.wikipedia.org/wiki/Merge_sort http://en.wikipedia.org/wiki/Merge_sort

Idea: 理念:

Use divide and conquer 使用分而治之

divide: size of sequence n to two lists of size n/2 conquer: count recursively two lists combine: this is a trick part (to do it in linear time) 除法:将序列n的大小分为大小为n / 2的两个列表征服:递归计数两个列表的组合:这是一个技巧部分(在线性时间内完成)

combine use merge-and-count. 结合使用合并和计数。 Suppose the two lists are A, B. They are already sorted. 假设两个列表是A,B。它们已经被排序。 Produce an output list L from A, B while also counting the number of inversions, (a,b) where a is-in A, b is-in B and a>b. 从A,B生成输出列表L,同时还计算反转数(a,b),其中a在-A处,b在-B处,并且a> b。

The idea is similar to "merge" in merge-sort. 这个想法类似于合并排序中的“合并”。 Merge two sorted lists into one output list, but we also count the inversion. 将两个已排序的列表合并到一个输出列表中,但我们还要计算反转。

Everytime a_i is appended to the output, no new inversions are encountered, since a_i is smaller than everything left in list B. If b_j is appended to the output, then it is smaller than all the remaining items in A, we increase the number of count of inversions by the number of elements remaining in A. 每次将a_i附加到输出后,都不会遇到新的求逆,因为a_i小于列表B中剩余的所有内容。如果将b_j附加到输出中,则它小于A中所有其余项,则我们增加了通过A中剩余元素的数量计算的反转数。

This reminds me of a similar problem you may want to look at: http://www.spoj.pl/problems/YODANESS/ 这使我想起了您可能要查看的类似问题: http : //www.spoj.pl/problems/YODANESS/

In your problem, you can't afford the time to swap everything in case there are many swaps required. 在您的问题中,如果需要进行多次交换,您将没有时间交换所有内容。 (imagine if the input was in reverse order 9,8,7,6.. then you would have to swap everything with everything basically. (想象一下,如果输入的顺序是相反的9,8,7,6 ..那么您就必须基本上将所有内容交换为所有内容。

I think in your case, each number must be swapped with all the numbers to the left of it that are smaller than it. 我认为在您的情况下,每个数字都必须与它左边所有小于它的数字互换。

I suggest you use a range tree http://en.wikipedia.org/wiki/Range_tree 我建议您使用范围树http://en.wikipedia.org/wiki/Range_tree

The great thing about a range tree is each node can know how many nodes are to its left and to its right. 关于范围树的妙处在于,每个节点都可以知道左侧和右侧有多少个节点。 You could ask the tree "how many numbers are there greater than 10" very efficiently and that's how many swaps you would have for a 9 say. 您可以非常有效地问这棵树“有多少个数字大于10”,这就是您说9个字就需要进行多少次交换。

The trick is to build the range tree as you move from i=0 to i=N-1. 诀窍是在从i = 0到i = N-1的过程中构建范围树。 At each point you can query the tree against the ith number before inserting the ith number into the range tree. 在将第i个数字插入到范围树之前,您可以在每个点针对第i个数字查询树。

good luck! 祝好运!

I did the same code in c++, and it is getting accepted,it is taking time about 4.2 seconds on spoj( http://www.spoj.com/submit/CODESPTB/ ). 我在c ++中执行了相同的代码,并且该代码被接受了,它在spoj上花费了大约4.2秒的时间( http://www.spoj.com/submit/CODESPTB/ )。

here is the code snippet: 这是代码片段:

 //http://www.spoj.com/problems/CODESPTB/ //mandeep singh @msdeep14 #include<iostream> using namespace std; int insertionsort(int arr[], int s) { int current,i,j,count=0; for(i=1;i<s;i++) { current=arr[i]; for(j=i-1;j>=0;j--) { if(current<arr[j]) { arr[j+1]=arr[j]; count++; } else break; } arr[j+1]=current; } return count; } int main() { int t,n,i,res; int arr[100000]; cin>>t; while(t--) { cin>>n; for(i=0;i<n;i++) { cin>>arr[i]; } res=insertionsort(arr,n); cout<<res<<endl; } return 0; } 

#include < stdio.h >
int main() {
   int N, swaps, temp[100], i, j;
   scanf("%d", & N);
   int arr[N];
   swaps = 0;
   for (i = 0; i < N; i++) {
       scanf("%d", & temp[i]);
       j = i;
       while (j > 0 && arr[j - 1] > temp[i]) {
           arr[j] = arr[j - 1];
           ++swaps;
           --j;
       }
       arr[j] = temp[i];
   }
   printf("%d", swaps);
   return 0;
}

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

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