归并排序算法

归并排序(Merge Sort)算法实现


java实现归并排序算法,非常基础的一个算法,先明白分治法的主要思想,分而治之,然后再统一起来完成剩下的操作,最后完成排序,内部需要用到额外的存储空间,时间复杂度是O(nlg(n));
归并排序分为两种,一种是自顶向下的,另一种是自底向上的;两种排序方法虽然都是归并排序,但是实现方式却大不一样;

1. 自顶而下的归并排序

###代码实现

private static void sort(int[] copy, int l, int r) {
	if (l >= r) return;
	int mid = (l + r) / 2;
	sort(copy, l, mid);
	sort(copy, mid+1, r);
	merge(copy, l, mid, r);
}

private static void merge(int[] copy, int l, int mid, int r) {
	int[] t = new int[r-l+1];
	int j=l, k=mid+1;
	for (int i=0; i<t.length; i++) {
		if (j <= mid && k <= r) {
			if (copy[j] < copy[k])
				t[i] = copy[j ++];
			else
				t[i] = copy[k ++];
		} else if (j <= mid){
			t[i] = copy[j ++];
		} else
			t[i] = copy[k ++];
	}
	
	for (int i=l; i<=r; i++) {
		copy[i] = t[i-l];
	}
}

2. 自底而上的归并排序

代码实现

	int[] c = {9, 0, 2, 4, 5, 6, 1, 1};
	int n = c.length;
	for (int k=1; k<n; k*=2) {
		for (int l=0; l<n-k; l+=k*2) {
			merge(c, l, l+k-1, l+k*2-1);
		}
	}
  • 两种方法都使用了归并排序的核心程序merge函数,但是一个是采用递归实现,架构上是自顶而下,另一个是非递归自底而上的程序,两种算法区别可通过下面图解方式一目了然;
  • 自顶而下的归并排序

这里写图片描述

  • 自底而上的归并排序
    这里写图片描述

3. 从两路归并到多路归并

代码实现

import java.util.*;

public class Main {

    private static class Pair<T extends Comparable> implements Comparable<Pair<T>>{
        int idx;
        List<T> A;
        Pair(int idx, List<T> a) {
            this.idx = idx;
            A = a;
        }

        @Override
        public int compareTo(Pair<T> o) {
            return A.get(idx).compareTo(o.A.get(o.idx));
        }
    }


    public static void main(String[] args) {

        List<Integer>[] arr = new ArrayList[5];
        arr[0] = new ArrayList<>(Arrays.asList(1, 4, 9, 15));
        arr[1] = new ArrayList<>(Arrays.asList());
        arr[2] = new ArrayList<>(Arrays.asList(2, 5, 8));
        arr[3] = new ArrayList<>(Arrays.asList(1, 9));
        arr[4] = new ArrayList<>(Arrays.asList(3));
        ArrayList<Integer> B = new ArrayList<>();
        merge(arr, B);
        System.out.println(B);
    }


    private static void merge(List<Integer>[] arr, ArrayList<Integer> B) {
        PriorityQueue<Pair<Integer>> pq = new PriorityQueue<>();
        for (int i=0; i<arr.length; i++) {
            if (arr[i].size() > 0)
                pq.offer(new Pair<Integer>(0, arr[i]));
        }
        while (!pq.isEmpty()) {
            Pair<Integer> pair = pq.poll();
            B.add(pair.A.get(pair.idx));
            pair.idx ++;
            if (pair.idx != pair.A.size())
                pq.offer(pair);
        }
    }

}
  • 使用了优先队列来进行取最小值的处理,这里如果使用c++的话即用pair实现,但java的话,自定义了一个pair类同样可以最终达到多路归并的效果;
  • 总共元素个数是n,共有k路的话,其复杂度为O(n*lg(k));

思考和修改:

  • 上面的List[]数组毕竟不常用,还是化为我们最常见的二维数组吧,再用泛型包装下,用以进行拓展使用;
import java.util.*;

public class Main<M extends Comparable> {

    private class Pair<T extends Comparable> implements Comparable<Pair<T>>{
        int idx;
        T[] A;
        Pair(int idx, T[] a) {
            this.idx = idx;
            this.A = a;
        }

        @Override
        public int compareTo(Pair<T> o) {
            return A[idx].compareTo(o.A[o.idx]);
        }
    }


    public static void main(String[] args) {
        Integer[][] arr = {{1, 2}, {}, {3, 5, 7}, {3, 5, 9, 10}};
        List<Integer> B = new ArrayList<>();
        Main<Integer> m = new Main<>();
        m.merge(arr, B);
        System.out.println(B);


        String[][] arr2 = {{"sad", "as"}, {}, {"qw", "xaz", "ior"}, {"asjk", "tri", "dsk", "skdj"}};
        List<String> C = new ArrayList<>();
        Main<String> m2 = new Main<>();
        m2.merge(arr2, C);
        System.out.println(C);

    }


    private void merge(M[][] arr, List<M> B) {
        PriorityQueue<Pair<M>> pq = new PriorityQueue<>();
        for (int i=0; i<arr.length; i++) {
            if (arr[i].length > 0)
                pq.offer(new Pair<M>(0, arr[i]));
        }
        while (!pq.isEmpty()) {
            Pair<M> pair = pq.poll();
            B.add(pair.A[pair.idx]);
            pair.idx ++;
            if (pair.idx != pair.A.length)
                pq.offer(pair);
        }
    }

}

结果查看:

在这里插入图片描述


4. 拓展-Shell排序

看到归并排序,突然想到这和希尔排序很像,于是在此将shell排序算法记录一下,作一比较:

for (int gap = n/2; gap>0; gap/=2) {
	for (int i=gap; i<n; i++) {
		for (int j=i-gap; j>=0 && a[j]>a[j+gap]; j-=gap) {
			int temp = a[j];
			a[j] = a[j+gap];
			a[j+gap] = temp;
		}
	}
}
  • 当gap为1时,shell排序即为插入排序;

与之对比的是自下而上的归并排序,Merge sort,可以参考以下核心代码实现;

int n = 10;
int[] a = new int[n+1]; //第0个位置不放置元素,从1开始;
int k=1;
boolean flag=true;
while (k<n) {
	k *= 2;
	for (int i=0; i<n/k; i++) {
		Arrays.sort(a, 1+i*k, 1+(i+1)*k);
	}
	Arrays.sort(a, 1+n/k*k, n+1);
}

关于自底向上的归并排序,想要了解的多,可以参考这道PAT试题,能让你了解的更透彻;
并附上我的AC代码:

public static void main(String[] args) throws IOException {
	Read.init(System.in);
    int n = Read.nextInt();
    int[] a = new int[n+1], b = new int[n+1];
    for (int i=1; i<=n; i++) {
        a[i] = Read.nextInt();
    }
    for (int i=1; i<=n; i++) {
        b[i] = Read.nextInt();
    }
    int p = 2, q;
    while (p <= n && b[p-1] <= b[p]) p++;
    q = p;
    while (p <= n && b[p] == a[p]) p++;
    if (p == n+1) {
        System.out.println("Insertion Sort");
        Arrays.sort(b, 0, q+1);
        System.out.print(b[1]);
        for (int i=2; i<=n; i++)
            System.out.print(" " + b[i]);
    } else {
        System.out.println("Merge Sort");
        int k=1;
        boolean flag=true;
        while (flag) {
        	flag = false;
        	for (int i=1; i<=n; i++) {
        		if (a[i] != b[i]) {
        			flag = true;
        			break;
        		}
        	}
        	k *= 2;
        	for (int i=0; i<n/k; i++) {
        		Arrays.sort(a, 1+i*k, 1+(i+1)*k);
        	}
        	Arrays.sort(a, 1+n/k*k, n+1);
        }
        System.out.print(a[1]);
        for (int i=2; i<=n; i++)
            System.out.print(" " + a[i]);
        
    }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值