简体   繁体   中英

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)). 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]

To know the idea behind this you should know the basic merge sort algorithm

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)

combine use merge-and-count. Suppose the two lists are A, B. They are already sorted. 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.

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.

This reminds me of a similar problem you may want to look at: 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.

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

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.

The trick is to build the range tree as you move from i=0 to i=N-1. At each point you can query the tree against the ith number before inserting the ith number into the range tree.

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/ ).

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

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

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