自顶向下归并排序和自底向上的归并排序

欢迎探讨,如有错误敬请指正

如需转载,请注明出处http://www.cnblogs.com/nullzx/


1. 归并排序算法的使用情景

归并排序算法和快速排序算法是java.util.Arrays中使用的排序算。对于一般的基本数据类型,Arrays.sort函数使用双轴快速排序算法,而对于对象类型使用归并排序(准确的说使用的是TimSort排序算法,它是归并排序的优化版本)。这样做的原因有两点,第一个原因,归并排序是稳定的,而快速排序不是稳定的。第二个原因,对于基本数据类型,排序的稳定性意义不大,但对于复合数据类型(比如对象)排序的稳定性就能帮助我们保持排序结果的某些性质。

2. 自顶向下的归并排序

自顶向下的排序算法就是把数组元素不断的二分,直到子数组的元素个数为一个,因为这个时候子数组必定是已有序的,然后将两个有序的序列合并成一个新的有序的序列,两个新的有序序列又可以合并成另一个新的有序序列,以此类推,直到合并成一个有序的数组。

为了体现归并的排序的稳定性,我们的代码使用java的泛型来实现对任意对象的排序。

	public static <T extends Comparable<? super T>>
	void MergeSortUpToDown(T[] A){
		@SuppressWarnings("unchecked")
		//创建合并两个有序序列的辅助数组
		T[] aux = (T[])Array.newInstance(A.getClass().getComponentType(), A.length);
		mergeSortUpToDown0(A, aux, 0, A.length-1);
	}

	public static <T extends Comparable<? super T>>
	void mergeSortUpToDown0(T[] A, T[] aux, int start, int end){
		if(start == end)
			return;
		int mid = (start+end)/2;
		mergeSortUpToDown0(A, aux, start, mid);
		mergeSortUpToDown0(A, aux, mid+1, end);
		//复制到辅助数组中,此时[start,mid] [mid+1, end]两个子数组已经有序
		System.arraycopy(A, start, aux, start, end - start + 1);
		//然后归并回来
		int i = start, j = mid+1, k;
		for(k = start; k <= end; k++){
			if(i > mid){
				A[k] = aux[j++];
			}else
			if(j > end){
				A[k] = aux[i++];
			}else
			if(aux[i].compareTo(aux[j]) <= 0){
				A[k] = aux[i++];
			}else{
				A[k] = aux[j++];
			}
		}
	}

3. 自底向上的归并排序

自底向上的归并排序算法的思想就是数组中先一个一个归并成两两有序的序列,两两有序的序列归并成四个四个有序的序列,然后四个四个有序的序列归并八个八个有序的序列,以此类推,直到,归并的长度大于整个数组的长度,此时整个数组有序。需要注意的是数组按照归并长度划分,最后一个子数组可能不满足长度要求,这个情况需要特殊处理。自顶下下的归并排序算法一般用递归来实现,而自底向上可以用循环来实现。

	//自底向上归并排序
	public static <T extends Comparable<? super T>> void MergeSortDownToUp(T[] A){
		@SuppressWarnings("unchecked")
		T[] aux = (T[])Array.newInstance(A.getClass().getComponentType(), A.length);
		int len,i,j,k,start,mid,end;
		//len表示归并子数组的长度,1表示,一个一个的归并,归并后的长度为2,2表示两个两个的归并,归并后的长度为4,以此类推
		for(len = 1; len < A.length; len = 2*len){
			//复制到辅助数组中
			System.arraycopy(A, 0, aux, 0, A.length);
			//按照len的长度归并回A数组,归并后长度翻倍
			for(start = 0; start < A.length; start = start+2*len){
				mid = start + len - 1;
				//对于数组长度不满足2的x次幂的数组,mid可能会大于end
				end = Math.min(start + 2*len - 1, A.length-1);
				i = start;
				//mid大于end时,j必然大于end,所以不会引起越界访问
				j = mid+1;
				//[start,mid] [mid+1, end]
				for(k = start; k <= end; k++){
					if(i > mid){
						A[k] = aux[j++];
					}else
					if(j > end){
						A[k] = aux[i++];
					}else
					if(aux[i].compareTo(aux[j]) < 0){
						A[k] = aux[i++];
					}else{
						A[k] = aux[j++];
					}
				}
			}
		}
	}

4.参考文章

[1] 算法(第四版)RobertSedgewick

时间: 2024-12-21 12:46:58

自顶向下归并排序和自底向上的归并排序的相关文章

自底向上的归并排序算法

1.什么是自底向上的归并排序? 说到底,不管是前面说的自顶向下的归并排序还是现在讲的自底向上的归并排序,其实质都是归并. 来看看一个演示过程:          这个就是待排序的数组序列          先将数组序列以2个元素为一组分成4组,每个组内部分成2个子序列进行向上合并           这是合并之后的效果           然后以4个元素为一组分成2组,每个组内部分成2个子序列进行向上合并           这是合并之后的效果           然后以8个元素为一组分成1个组

【Algorithm】自底向上的归并排序

一. 算法描述 自底向上的归并排序:归并排序主要是完成将若干个有序子序列合并成一个完整的有序子序列:自底向上的排序是归并排序的一种实现方式,将一个无序的N长数组切个成N个有序子序列,然后再两两合并,然后再将合并后的N/2(或者N/2 + 1)个子序列继续进行两两合并,以此类推得到一个完整的有序数组.下图详细的分解了自底向上的合并算法的实现过程: 二. 算法实现 /*==================================================================

ACM:归并排序,以及利用归并排序思想求解逆序对数!

(一)归并排序 分析: (1)划分问题:把序列分成元素个数尽量相等的两半. (2)递归求解:把两半元素分别排序. (3)合并问题:把两个有序表合并成一个.(每次只需要把两个序列的最小元素加以比较,删除其中的较小元素并加入合并后的新表) #include <iostream> using namespace std; const int MAXN = 1000; int A[MAXN], T[MAXN]; void merge_sort(int *A, int x, int y, int *T)

归并和归并排序

归并操作:是将两个有序独立的文件合并成为一个有序文件的过程. 归并排序:和快速排序的过程相反,它是两个递归调用(排序子文件)后是一个归并的过程. 快速排序时,先分解成两个子问题后是两个递归调用(排序子文件)的过程. 归并操作 1 基本的两路归并 2 抽象原位归并 归并排序 1 自顶向下的归并排序 2 自底向上的归并排序 3 归并排序的性能特征 归并排序的链表实现 归并排序与快速排序对比 1. 归并操作 1.1 基本的两路归并 将两个已经有序的数组 a 和 b 合并成一个有序的数组 c . 归并操

【Algorithm】自顶向下的归并排序

一. 算法描述 自顶向下的归并排序:采用分治法进行自顶向下的程序设计方式,分治法的核心思想就是分解.求解.合并. 先将长度为N的无序序列分割平均分割为两段 然后分别对前半段进行归并排序.后半段进行归并排序 最后再将排序好的前半段和后半段归并 过程(2)中进行递归求解,最终下图详细的分解了自顶向下的合并算法的实现过程: 二. 算法实现 /*============================================================================= #

算法-归并排序

归并排序是建立在归并操作上的一种有效的排序算法,算法主要采用分治法(Divide and Conquer)的一个非常典型的应用.归并排序的算法复杂度为O(N*logN),需要的额外的空间跟数组的长度N有关系,实现归并排序最简单的方法是将两个数组重新整合到第三个数组中.通常对于一个数组我们对前半部分进行排序,然后惊醒后半部分进行排序,实现原地归并操作,不过需要额外的空间存储数组.假设数据中有8个元素,先分为四组进行比较,之后分为两组进行比较,最后分为一组进行比较,这样就衍生出来两种方法,一种是自顶

算法(第四版)学习笔记(三)——归并排序

归并排序  MERGE-SORT 时间复杂度: 空间复杂度: 一.原地归并排序 步骤:将两个已有序数组组合到一个数组中并排好序. 1 #include<stdio.h> 2 #include<malloc.h> 3 int *c; 4 void merge(int *a, int *b,int m,int n); 5 int main() 6 { 7 int n,m,sum,i; 8 scanf("%d",&n); 9 int *a=(int *)mal

算法_归并排序

归并排序的基本思想是:将两个已经有序的数组,归并成为更大的有序数组.这种操作称为归并排序.要让一个数组排序,可以先递归的把它分成两半分别排序,然后将结果归并起来.归并排序能够保证对一个任意长度为N的数组排序所需时间和NlogN成正比. 基本的归并方法代码如下:该方法先将所有的元素复制到aux[]中,然后再归并到a[]中.方法在归并的时候,进行了四次条件判断:左半边用尽(取右半边的元素),右半边用尽(取左半边的元素),右半边的当前元素小于左半边的当前元素(取右半边的元素)以及右半边的元素大于等于左

算法(第4版)-2.2 归并排序

归并:将两个有序的数组归并成一个更大的有序数组. 归并算法:先(递归地)将它分为两半分别排序,然后将结果归并起来. · 优点:保证将任意长度为N的数组排序所需时间和NlogN成正比: · 缺点:所需的额外空间和N成正比. 2.2.1 原地归并的抽象方法 public static void merge(Comparable[] a, int lo, int mid, int hi) { // 将a[lo..mid]和a[mid+1..hi]归并 int i = lo, j = mid + 1;