算法 -- 计算逆序数 , significant逆序数 归并排序

求解逆序数是归并排序的副产品。

这学期见过很多版本的逆序数,大多数的版本都曲解了“significant逆序数”(后面称为显著逆序数),也就是说:

if i  <   j ,  A[i]  >  k*A[j], (1  <  k)这就是“显著逆序数” ,只要数值的顺序不同于index的顺序,那么再看其数值大的程度,就可以决定是否是“显著逆序数”。

我实现了下面的版本,注释中讲解的是我在编写程序时遇到的问题:

//此处使用的归并排序是采用的不使用哨兵元素的形式。
//如果i < j and A[i] > 3*A[j]时才算做是逆序数。
#include<iostream>
#include<cstdlib>
#include<ctime>
#include<cassert>
using namespace std;

int merge(int A[], int left, int mid, int right)
{
	int RC = 0; 
	int *L = new int[mid-left+1];
	int *R = new int[right-mid];
	int lLen = mid - left + 1;
	int rLen = right - mid;
	for(int i = 0; i < lLen; ++i)
		L[i] = A[left+i];
	for(int i = 0; i < rLen; ++i)
		R[i] = A[mid+1+i];
	int i(0),j(0),k(left);

	while(( i < lLen) && (j < rLen))
	{

		if (L[i] <= R[j])
		{
			A[k] = L[i];
			i++;
			k++;
		}
		else
		{
			A[k] = R[j];
			j++;
			k++;
        }
    }
	assert(i <= lLen && j <= rLen);
	while(i < lLen)
	{
		A[k] = L[i];
		i++;
		k++;
	}
	while(j < rLen)
	{
		A[k] = R[j];
		k++;
		j++;
	}

    i = j = 0;
	while(( i < lLen) && (j < rLen))
    {
        if (L[i] > (3*R[j]))
        {
            RC += ((right-left)/2-i+1);
            ++j;
        }
        else ++i;
    }

	delete [] L;
	delete [] R;
	return RC;
}



int mergeSort(int A[], int left, int right)
{
	int mid;
	int RCL = 0, RCR = 0 , RC = 0 ;
	if(left < right)
	{
		mid = left + (right-left)/2;
		RCL = mergeSort(A,left,mid);
		RCR = mergeSort(A,mid+1,right);
		RC = merge(A,left,mid,right);
	}
	return (RCL + RCR + RC);
}



int main()
{
    int len;
    int A[100];
    while(cin >> len) {
        for(int i = 0; i < len; ++i) {
            cin >> A[i];
        }
        cout <<	 mergeSort(A,0,len-1) << endl;
    }

	return 0;
}


关于上述程序的问题,已经在注释中说明。



你可能感兴趣的:(算法,归并排序,merge,逆序数,逆序数,significant)