(高效率排序算法一)并归排序

归并排序

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

归 并过程为:比较a[i]和a[j]的大小,若a[i]≤a[j],则将第一个有序表中的元素a[i]复制到r[k]中,并令i和k分别加上1;否则将第二 个有序表中的元素a[j]复制到r[k]中,并令j和k分别加上1,如此循环下去,直到其中一个有序表取完,然后再将另一个有序表中剩余的元素复制到r中 从下标k到下标t的单元。归并排序的算法我们通常用递归实现,先把待排序区间[s,t]以中点二分,接着把左边子区间排序,再把右边子区间排序,最后把左
区间和右区间用一次归并操作合并成有序的区间[s,t]。

中文名:归并排序

外文名:Merge sort

稳定性:稳定

时间复杂度:O(n log n)

空间复杂度:O(n)

发明者:约翰·冯·诺伊曼

(速度仅次于快速排序,为稳定排序算法,一般用于对总体无序,但是各子项相对有序的数列,应用见2011年普及复赛第3题“瑞士轮”的标程)

快速排序流程效果如下,下次再写它

归并操作

归并操作(merge),也叫归并算法,指的是将两个顺序序列合并成一个顺序序列的方法。

如 设有数列{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;

下面是我网上找的图

当然我下面写的程序,数组还是同个数组,分解的时候是直接按最小分解开始,就是直接按最细粒度分解

package data;

import java.util.Arrays;
import java.util.Random;
/**
 * 并归排序
 * @author JYC506
 *
 */
public class MergeSort {
    /**
     * 对部分排好序的数组进行归并
     * @param arr 要操作的数组
     * @param start1 排好序的数组部分1起点
     * @param end1   排好序的数组部分1终点
     * @param start2 排好序的数组部分2起点
     * @param end2   排好序的数组部分2终点
     * @return
     */
	private static int[] merger(int[] arr, int start1, int end1, int start2, int end2) {
		int[] newArr = new int[(end1 - start1) + (end2 - start2) + 2];
		int index1 = start1;
		int index2 = start2;
		int index = 0;
		/*比较两个数组排好序的部分,从这两部分开始起点做比较,比较小的插入新数组
		例如比较a[i]和a[j]的大小,若a[i]≤a[j],则将第一个有序表中的元素a[i]复制到r[k]中,并令i和k分别加上1;否则将第二 个有序表中的元素a[j]复制到r[k]中,并令j和k分别加上1,如此循环下去,直到其中一个有序表取完*/
		while (index1 <= end1 && index2 <= end2) {
			if (arr[index1] < arr[index2]) {
				newArr[index] = arr[index1];
				index++;
				index1++;
			} else {
				newArr[index] = arr[index2];
				index++;
				index2++;
			}
		}
		/*然后再将另一个有序表中剩余的元素复制到r中从下标k到下标t的单元*/
		while (index1 <= end1) {
			newArr[index] = arr[index1];
			index++;
			index1++;
		}
		while (index2 <= end2) {
			newArr[index] = arr[index2];
			index++;
			index2++;
		}
		return newArr;
	}
    /**
     * 对部分且相邻了排好序的数组进行归并
     * @param arr 要操作的数组
     * @param start1 排好序的数组部分1起点
     * @param start2 排好序的数组部分2起点
     * @param end2 排好序的数组部分2终点
     */
	private static void merger(int[] arr, int start1, int start2, int end2) {
		int end1 = start2 - 1;
		int[] newArr = merger(arr, start1, end1, start2, end2);
		System.arraycopy(newArr, 0, arr, start1, newArr.length);
	}
    /**
     * 并归排序
     * @param arr 要操作的数组
     * @param start 起始坐标
     * @param size 分组后每一组的元素数
     */
	private static void mergerSort(int[] arr, int start, int size) {
		/*因为是成对比较,所以要乘以2*/
		int length=arr.length;
		int dSize=size*2;
		int num=length/dSize;
		int residue=length%dSize;
		// 归并到只剩一个有序集合的时候结束算法,也是就是余数为0的时候
		if(num==0){
			return;
		}
		// 进行一趟归并(注意,第一次并归只有一个元素,就是两两比较时已经算排序了)
		for(int i=0;i<num;i++){
            int sta=start+(size*2)*i;
			merger(arr,sta,sta+size,sta+size*2-1);
		}
		//将剩下的数和最后一个有序集合归并(这个要注意理解)
		if(residue!=0){
			merger(arr,length-residue-size*2,length-residue,length-1);
		}
		// 递归执行下一趟归并排序,并归元素师成倍增加
		mergerSort(arr, 0, 2 * size);

	}
	/**
	 *
	 * @param arr 要操作的数组
	 */
	public static void mergerSort(int[] arr){
		/*默认 起始坐标为0,并且分组元素为一个开始,因为一个是不用排序的*/
		mergerSort(arr, 0,1);
	}

	public static void main(String[] args) {
		/*测试并归排序*/
		int[] ar1=new int[]{10,4,6,3,8,2,5};
		MergeSort.mergerSort(ar1);
		System.out.println(Arrays.toString(ar1));
		/*测试100万随机数并归排序和java自带快速排序*/
		int size=1000000;
		int[] arr1=new int[size];
		int[] arr2=new int[size];
		Random ran=new Random();
		for(int i=0;i<size;i++){
			int data=ran.nextInt(size);
			arr1[i]=data;
			arr2[i]=data;
		}
		long start=System.currentTimeMillis();
		MergeSort.mergerSort(arr1);
		long end1=System.currentTimeMillis();
		Arrays.sort(arr2);
		long end2=System.currentTimeMillis();
		System.out.println((end1-start));
		System.out.println((end2-end1));
	}
}

运行结果如下

快速排序算法的确比并归算法速度快点

时间: 2024-10-24 02:26:52

(高效率排序算法一)并归排序的相关文章

排序算法(4)-线性时间排序

在前面三节排序算法中,我们分别分析了不同策略,思想用于排序,而这些算法都是基于数据间的比较来确定顺序的.假设我不用比较,换一种思路,那么就可以达到时间复杂度为O(n)的排序算法,当然是以付出额外的空间为代价的. 一.基本思想 线性时间排序的算法思想: (1):在计数排序中,利用比x小或等的元素个数和的来确定x位置.比如2 5 4 9 1 6.9比其余5个数都大,那就说明9 在排序后的第6个位置,这样我们只要得到比某个数大的元素个数就能得到元素在排序后数组中的位置了. (2):在桶排序中,是通过映

排序算法总结之希尔排序

一,希尔排序算法介绍 ①希尔排序又称缩小增量排序 ,它本质上是一个插入排序算法.为什么呢? 因为,对于插入排序而言,插入排序是将当前待排序的元素与前面所有的元素比较,而希尔排序是将当前元素与前面增量位置上的元素进行比较,然后,再将该元素插入到合适位置.当一趟希尔排序完成后,处于增量位置上的元素是有序的. ②希尔排序算法的效率依赖于增量的选取 假设增量序列为 h(1),h(2).....h(k),其中h(1)必须为1,且h(1)<h(2)<...h(k) . 第一趟排序时在增量为h(k)的各个元

非基于比较的排序算法之一:计数排序

计数排序(Counting sort)是一种稳定的排序算法.计数排序使用一个额外的数组C,其中第i个元素是待排序数组A中值小于等于i的元素的个数.然后根据数组C来将A中的元素排到正确的位置. 限制:所有值得取值范围不能太大,并且需要知道确切的取值范围.本算法需要的辅助空间要求较高. 当输入的元素是 n 个 0 到 k 之间的整数时,它的运行时间是 Θ(n + k).计数排序不是比较排序,排序的速度快于任何比较排序算法. 现在给出C#实现的计数排序(counting sort) public vo

详谈排序算法之选择类排序(两种方法实现堆排序)

   今天我们再来讨论一下选择类排序,选择类排序分为:简单排序,树形选择排序和堆排序.但我们主要说的是简单和堆排序两个,因为树形选择排序使用了较多的辅助空间,以及和∞进行多余比较,为弥补树型选择排序的这些缺点, J.W.J.Williams 在 1964 年提出了进一步的改进方法,即堆排序.对于我个人而言..一开始并不是很理解它的算法思想,纠结了许久.在网上查找资料的时候发现这位大神的文章思路十分清晰,而且把创建堆以及堆化数组的算法讲解的十分详细.如果有不明白堆排序思路的,可以先看看这篇文章~堆

排序算法总结----比较类排序

概述:排序算法可分为比较性的排序,以及运算性的排序:这里详细介绍这些排序的原理,性能,实现,以及应用场合. 前面是维基百科的介绍,这里介绍几个比较典型的算法. 理论 计算复杂性理论 大O符号 全序关系 列表 稳定性 比较排序 自适应排序 排序网络 整数排序 交换排序 冒泡排序 鸡尾酒排序 奇偶排序 梳排序 侏儒排序 快速排序 臭皮匠排序 Bogo排序 选择排序 选择排序 堆排序 Smooth排序 笛卡尔树排序 锦标赛排序 循环排序 插入排序 插入排序 希尔排序 二叉查找树排序 图书馆排序 Pat

排序算法总结----运算类排序

运算排序 第一:计数排序 1:原理 对于每个输入数,确定小于该数的个数.这样可以直接把数放在输出数组的位置. 2:性能 最差时间复杂度 最优时间复杂度 平均时间复杂度 最差空间复杂度 注:稳定算法 3:应用 适合0~100的范围的数,当然可以和基排序结合而扩展数的范围. 4:实现 void CountingSort(int *A, int *B, int array_size, int k) { int i, value, pos; int * C=new int[k+1]; for(i=0;

排序算法之直接选择排序

直接选择排序是最简单直观的排序算法,属于选择排序. 直接算法的排序思路: 第一趟,程序将记录定位在第一个数据上,拿第一个数据依次和后面的数据进行比较,如果第一个数据大,交换,依次类推.经过第一趟比较,这组数据中最小的数据被选出来,排在第一位. 第二趟,程序将记录定位在第二个数据上,拿第二个数据依次和后面的数据比较,同样地,第二个数据大就交换.经过第二次比较,这轮最小的书被选出来,放在了第二位. 这样经过n-1次比较,这组数据就会变得有序.下面是直接选择的排序算法实现. /** * Created

排序算法七:选择排序之堆排序

排序算法七:选择排序之堆排序 声明:引用请注明出处http://blog.csdn.net/lg1259156776/ 引言 在我的博文<"主宰世界"的10种算法短评>中给出的首个算法就是高效的排序算法.本文将对排序算法做一个全面的梳理,从最简单的"冒泡"到高效的堆排序等. 上博文讲述了选择排序中的简单排序算法,本文介绍的堆排序是树性选择排序,采用堆这个数据结构来辅助排序. 排序相关的的基本概念 排序:将一组杂乱无章的数据按一定的规律顺次排列起来. 数据

【数据结构】非比较排序算法(实现计数排序和基数排序)

● 计数排序 1.算法思想: 计数排序是直接定址法的变形.通过开辟一定大小的空间,统计相同数据出现的次数,然后回写到原序列中. 2.步骤: 1)找到序列中的最大和最小数据,确定开辟的空间大小. 2)开辟空间,利用开辟的空间存放各数据的个数. 3)将排好序的序列回写到原序列中. 具体实现如下: void CountSort(int *arr, int size) {  assert(arr);  int min = arr[0];  int max = arr[0];  int num = 0;

C语言中的排序算法--冒泡排序,选择排序,希尔排序

冒泡排序(Bubble Sort,台湾译为:泡沫排序或气泡排序)是一种简单的排序算法.它重复地走访过要排序的数列,一次比较两个元素,如果他们的顺序错误就把他们交换过来.走访数列的工作是重复地进行直到没有再需要交换,也就是说该数列已经排序完成.这个算法的名字由来是因为越小的元素会经由交换慢慢“浮”到数列的顶端 维基百科:点击打开链接 [cpp] view plain copy /* 用选择法对10个数进行排序 */ #include<stdio.h> void main() { int i,j,