归并排序&&归并排序求逆序对

眉间皱痕 提交于 2020-03-08 08:22:00

归并排序

归并排序(MERGE-SORT)是建立在归并操作上的一种有效的排序算法,该算法是采用分治法(Divide and Conquer)的一个非常典型的应用。将已有序的子序列合并,得到完全有序的序列;即先使每个子序列有序,再使子序列段间有序。若将两个有序表合并成一个有序表,称为二路归并。

算法:

第一步:申请空间,使其大小为两个已经排序序列之和,该空间用来存放合并后的序列
第二步:设定两个指针,最初位置分别为两个已经排序序列的起始位置
第三步:比较两个指针所指向的元素,选择相对小的元素放入到合并空间,并移动指针到下一位置
重复步骤3直到某一指针超出序列尾
将另一序列剩下的所有元素直接复制到合并序列尾
 

import java.util.*;

public class Main1 {
    static int a[] = new int[10010];
    static int b[] = new int[10010];
     

    public static void sort(int a[], int l, int r) {
        if (r - l > 0) {
            int mid = (r + l) / 2;
            int i = l;
            int p = l;
            int q = mid + 1;
            sort(a, l, mid);
            sort(a, mid + 1, r);
            while (p <= mid || q <= r) {                  
                if (q > r || (p <= mid && a[p] <= a[q]))      //这一点是简化代码,包含了当后边数组没有比前一半大的时候
                    b[i++] = a[p++];
                else {
                    b[i++] = a[q++];
                     
                }
            }
            for (i = l; i <= r; i++)
                a[i] = b[i];
        }
    }

    public static void main(String[] args) {
        Scanner sc = new Scanner(System.in);
        int n = sc.nextInt();
        for (int i = 1; i <= n; i++) {
            a[i] = sc.nextInt();
        }
        sort(a, 1, n);
        for (int i = 1; i <= n; i++)
            System.out.printf("%d ", a[i]);
        System.out.println(ans);
    }
}

归并排序求逆序对

求序列的逆序对,先看下面的例子:

设有数列{6,202,100,301,38,8,1}

初始状态:6,202,100,301,38,8,1

第一次归并后:{6,202},{100,301},{8,38},{1},比较次数:3;

第二次归并后:{6,100,202,301},{1,8,38},比较次数:4;

第三次归并后:{1,6,8,38,100,202,301},比较次数:4;

总的比较次数为:3+4+4=11;

逆序数为14;
 

根据归并排序的特性(左右两部分的有序序列合并时,假设i在左边,j在右边,对于右边的j,统计左边比它大的元素个数s(j),则s(j) = mid-i+1 ,合并万所有的序列时即可得出答案,即f(j)之和便是答案),只需将上面的代码修改一处:把“else  b[i++] = a[q++];”改成“ else {b[i++] = a[q++];  ans += mid-p+1;}" ,注意在调用之前将ans清零。
 

package demo2;

import java.util.*;

public class Main1 {
    static int a[] = new int[10010];
    static int b[] = new int[10010];
    static int ans = 0;

    public static void sort(int a[], int l, int r) {
        if (r - l > 0) {
            int mid = (r + l) / 2;
            int i = l;
            int p = l;
            int q = mid + 1;
            sort(a, l, mid);
            sort(a, mid + 1, r);
            while (p <= mid || q <= r) {
                if (q > r || (p <= mid && a[p] <= a[q]))
                    b[i++] = a[p++];
                else {
                    b[i++] = a[q++];
                    ans += mid - p + 1;
                }
            }
            for (i = l; i <= r; i++)
                a[i] = b[i];
        }
    }

    public static void main(String[] args) {
        Scanner sc = new Scanner(System.in);
        int n = sc.nextInt();
        for (int i = 1; i <= n; i++) {
            a[i] = sc.nextInt();
        }
        sort(a, 1, n);
        for (int i = 1; i <= n; i++)
            System.out.printf("%d ", a[i]);
        System.out.println(ans);
    }
}

 

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!