Merge Sort and count inversion

这个博客介绍了如何使用Merge Sort算法进行排序,并在排序过程中统计逆序对的数量。文章通过Java代码展示了Merge Sort的实现,分析了其时间复杂度为O(nlogn),并提供了测试用例来验证算法的正确性和效率。此外,还提到了逆序对统计的概念,链接了一个外部资源以获取更多详细解释。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

package com;


public class MergeSort {
    public static int inversionCounts = 0;
    
    private static Integer[] unsortedArray;
    
    
    public static Integer[] getUnsortedArray() {
        return unsortedArray;
    }


    public static void setUnsortedArray(Integer[] unsortedArray) {
        MergeSort.unsortedArray = unsortedArray;
    }


    public static Integer[] mergeSort(int from, int end)
    {
        // zero case
        if (unsortedArray.length == 0)
            return null;
        // Base case
        if (end == from)
            return new Integer[] { unsortedArray[end] };

        //split array into half and half
        int middle = (from + end) / 2;
        Integer[] halfArray = mergeSort(from, middle);
        Integer[] anotherHalfArray = mergeSort(middle + 1, end);
       //After this step, we assume that we got 2 sorted arrays already

        //New temp array
        int size = halfArray.length + anotherHalfArray.length;
        Integer[] newArray = new Integer[size];

        //Compare those two array and do the manual merge
        int i = 0, j = 0, k = 0;
        int leftOverInLeftHalfArray = halfArray.length;
        while (i != size && j != halfArray.length && k != anotherHalfArray.length)
        {
            if (halfArray[j] > anotherHalfArray[k])
            {
                newArray[i] = halfArray[j];
                j++;
                leftOverInLeftHalfArray --;
            }
            else
            {
                newArray[i] = anotherHalfArray[k];
                k++;
                inversionCounts += leftOverInLeftHalfArray;
            }
            i++;
        }

        //Clean up
        while (j != halfArray.length)
        {
            newArray[i++] = halfArray[j++];
        }
        while (k != anotherHalfArray.length)
        {
            newArray[i++] = anotherHalfArray[k++];
        }

        return newArray;

    }
}

big o分析:
设数组长度为n,我们每次进行split(<span style="font-family: Arial, Helvetica, sans-serif;">mergeSort(from, middle);</span>)都会进行2次递归调用,所以在第n层,我们的递归调用规模为2^n
但是同样的,每个递归调用中的问题规模(即Compare,merge,and cleanup所操作的对象的长度)也相应变小了,为n/2^n,因此,在每一层,递归的时间消耗为n/2^n * 2^n = n
递归树高度为log2 n,所以递归调用总共时间消耗为n*log2n, big o: O(nlogn)


Test case:
package test;


import static org.junit.Assert.*;


import java.util.Random;


import org.junit.Before;
import org.junit.Test;


import com.MergeSort;


public class TestMergeSort {


    private static Integer[] numbers;
    private final static int SIZE = 20;
    private final static int MAX = 20;


    static
    {
        numbers = new Integer[SIZE];
        Random generator = new Random();
        for (int i = 0; i < SIZE; i++)
        {
            numbers[i] = generator.nextInt(MAX);
        }
    }
    public static void printArray(Integer[] array)
    {
        for (int i = 0; i < array.length; i++)
            System.out.print(array[i] + " ");
        System.out.println();
    }


    public static void main(String[] args) {
        printArray(numbers);
        long startTime = System.currentTimeMillis();
        MergeSort.setUnsortedArray(numbers);
        numbers = MergeSort.mergeSort(0, SIZE - 1);
        long stopTime = System.currentTimeMillis();
        long time = stopTime - startTime;
        printArray(numbers);
        System.out.print("Elapsed time:" + time);
        assert (true);
        System.out.println("Inversion Counts:" + MergeSort.inversionCounts);
    }


}

这里同时做的还有整个数组中Inversion的统计,用到了LeftSideInversion,RightSideInversion和SplitInversion的概念,具体的解释看这里
https://cgi.csc.liv.ac.uk/~martin/teaching/comp202/Java/Inversions-code.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值