为什么使用归并排序?
java中的Arrays.sort(Object[] o)是对数组进行排序,它使用的是归并排序的方式,
快速排序要比归并排序更快一些,但为什么使用归并排序了?原因是归并排序是一种稳定的排序
方式,即归并排序不交换相同的元素,这就意味着,在按一种方式排序后同时可以按另外一种
方式进行排序。比如员工可以首先按工资排序,然后按名字排序,一种排序不会打乱另一种排序
的顺序。
下面分析下sort方法的简化版:
/**
* 归并排序 (递归实现)
* 前提: 每个元素要有可比性,这里元素必须实现Comparable接口。
* 基本原理为:1.拆分 假设有N个元素的列表,首先把它拆分成2个或2个
* 以上的元素组成的新的列表(这里我的新列表长度不超过3),分别对对它们进行排序。
* 2.归并。把所有的排好序的子类表两两归并,如此重复,直到归并成一个含N个
* 元素的有序列表为止
* 图解:(大于3就继续分解)
* 大于3 8 7 6 5 4 3 2 1
* 分|解
* |
* 大于3 8 7 6 5 4 3 2 1
* 分|解 分|解
* | |
* 小于 3 8 7 6 5 4 3 2 1
* 排序 7 8 5 6 3 4 1 2
* 归并 | |
* 7 8 5 6 3 4 1 2
* | |
* 顺序保存 5 6 7 8 1 2 3 4
* |
* 归并 5 6 7 8 1 2 3 4
* |
* 顺序保存 1 2 3 4 5 6 7 8
* @param src 临时中间数组,它是目标数组的拷贝
* @param target 目标排序数组
* @param low 需排序的起始索引
* @param high 需排序的结束索引
*
*/
public static void mergeSort(Object[] src,Object[] dest,int low,int high){
int length = high - low;
if(length < 3 ){ //对长度小于3的列表排序
//排序方法一:起泡排序(大数沉底)
// for(int i=low;i<high-1;i++){
// for(int j=low;j<high-1-i+low;j++){
// if(((Comparable) dest[j]).compareTo(dest[j+1]) > 0){
// swap(dest, j, j+1);
// }
// }
// }
//排序方法二:这是起泡排序的一种变体(小数上浮)
for (int i = low; i < high; i++){
for (int j = i; j > low ; j--){
if(((Comparable) dest[j - 1]).compareTo(dest[j]) > 0){
swap(dest, j-1, j);
}
}
}
return;
}
int mid = (high + low)/2; //拆分
mergeSort(dest, src, low, mid); //递归,可能会继续拆分(那么必然继续合并)
mergeSort(dest, src, mid, high);
//开始归并,方法一
// for(int i=low,p=low,q=mid;i<high;i++){
// //第一个条件时为了添加剩余的值
// if(q >= high || (p < mid &&((Comparable) src[p]).compareTo(src[q]) <= 0)){
// dest[i] = src[p++];
// }else{
// dest[i] = src[q++];
// }
// }
//开始归并,方法二
int i = low;
int p = low; //第一个列表指针
int q = mid; //第二个列表指针
while(p < mid && q <high){
if(((Comparable) src[p]).compareTo(src[q]) <= 0){
dest[i++] = src[p++];
}else{
dest[i++] = src[q++];
}
}
//添加剩余的值
while(p < mid && i<high){
dest[i++] = src[p++];
}
while(q < high && i<high){
dest[i++] = src[q++];
}
private static void swap(Object[] x, int a, int b) {
Object t = x[a];
x[a] = x[b];
x[b] = t;
}
}
递归形式的算法在形式上比较简洁,但实用性不够好。
下面讲讲归并排序的非递归实现
public class MergeDemo{
public static void main(String[] args) {
String[] a= {"9","8","7","6","5","4","3","2","1"};
Object[] aux = (Object[])a.clone();
mergeSort(aux, a);
for(int i=0;i<a.length;i++){
System.out.println(a[i]);
}
}
//每个拆分的列表元素个数<=3
private static final int INSERTIONSORT_THRESHOLD = 3;
/**
*
* 归并排序(非递归实现)
*/
public static void mergeSort(Object[] src,Object[] dest){
int spreCount = INSERTIONSORT_THRESHOLD;
int low,mid,high;
int len = src.length;
if(len <= INSERTIONSORT_THRESHOLD*2){ //如果只能划分为两组,直接排序
sort(dest,0,len);
return;
}
while(spreCount < len){
for(int i=0;i<len;i=high){ //依次排序归并相邻两个列表
low = i;
high = low + spreCount * 2 ;
mid = low + spreCount;
if(high >= len){
high = len;
}
int l = high - low;
if(l <= INSERTIONSORT_THRESHOLD){
sort(src,low,high);
break;
}
if(spreCount == 3){ //所有拆分的列表只进行一次排序
sort(dest,low,mid);
sort(dest,mid,high);
}
if(l == len) //最后一次归并把src有次序的赋给dest
Merge(src,dest,low,mid,high);
else
Merge(dest,src,low,mid,high);
}
spreCount *= 2;
}
}
//对拆分的每个列表进行排序
private static void sort(Object[] dest,int low,int high){
for (int i = low; i < high; i++){
for (int j = i; j > low ; j--){
if(((Comparable) dest[j - 1]).compareTo(dest[j]) > 0){
swap(dest, j-1, j);
}
}
}
}
//归并相邻两个列表并保存在dest中
private static void Merge(Object[] src, Object[] dest, int low, int mid,
int high) {
int i = low;
int p = low; //第一个列表指针
int q = mid; //第二个列表指针
while(p < mid && q <high){
if(((Comparable) src[p]).compareTo(src[q]) <= 0){
dest[i++] = src[p++];
}else{
dest[i++] = src[q++];
}
}
//添加剩余的值
while(p < mid && i<high){
dest[i++] = src[p++];
}
while(q < high && i<high){
dest[i++] = src[q++];
}
}
private static void swap(Object[] x, int a, int b) {
Object t = x[a];
x[a] = x[b];
x[b] = t;
}
}
分享到:
相关推荐
在上面的代码实现中,我们可以看到,归并排序的时间复杂度为 O(nlog2^n),这是因为我们需要将原始数组分割成小组,并对每个小组进行排序,然后将排序好的小组合并成一个有序数组。空间复杂度为 O(N),这是因为我们...
归并排序:如何使用Java实现归并排序算法,程序详细解读; 归并排序:如何使用Java实现归并排序算法,程序详细解读; 归并排序:如何使用Java实现归并排序算法,程序详细解读; 归并排序:如何使用Java实现归并排序...
Java 中归并排序算法详解 Java 中归并排序算法是一种时间复杂度为 O(N logN) 的排序算法,因而其在平常生活工作中应用非常广泛。下面是对 Java 中归并排序算法的详细解释: 算法思想 归并排序算法顾名思义,是一...
在Java中实现归并排序,我们可以创建一个名为`MergeSort`的类来封装整个过程。归并排序的基本思想是将待排序的序列分成两个或更多的子序列,对每个子序列分别进行排序,然后将排序后的子序列合并成一个有序序列。这...
在Java中实现归并排序,主要涉及到以下几个关键步骤: 1. **分割(Divide)**:将原始数组分为两个相等(或接近相等)的子数组。这通常通过取数组中间索引来完成。例如,如果数组长度为`n`,则可以将前`n/2`个元素...
这里有三个主要的排序算法:归并排序、消除递归的归并排序和快速排序,它们都是在Java编程语言中实现的。让我们深入探讨这些算法及其Java实现。 1. **归并排序(Merge Sort)** 归并排序是一种基于分治思想的排序...
在这个场景中,我们讨论的焦点是使用 Java Swing 来实现一个排序算法的动画展示,特别是归并排序。归并排序是一种高效的、稳定的排序算法,它的基本思想是将大问题分解为小问题来解决,通过递归地将两个或更多有序数...
本篇将重点讲解如何利用ArrayList实现快速排序(Quick Sort)、归并排序(Merge Sort)和堆排序(Heap Sort)这三种经典的排序算法,并探讨它们的原理、优缺点以及在实际应用中的选择。 **快速排序(Quick Sort)**...
该资源提供了一份全面的指南,介绍了如何在Java中实现归并排序。文档中涵盖了归并排序的基本概念,包括如何对数组进行排序以及如何在Java中实现归并排序。此外,文档还包括一个逐步指南,介绍如何在Java中实现归并...
在归并外排序中,每个块视为一个已排序的序列,而合并操作则是在多个块之间进行。 Java实现归并外排序时,通常会用到以下几个关键类和方法: - `FileReader` 和 `BufferedReader`:用于读取文件。 - `FileWriter` ...
在Java中实现归并排序,我们可以遵循以下步骤: **一、理解归并排序原理** 归并排序是将大问题分解成小问题来解决。它将待排序的序列分成两个子序列,分别对这两个子序列进行排序,然后将排好序的子序列合并成一个...
归并排序 在排序前,先建好一个长度等于原数组长度的临时数组
归并排序 java实现归并排序
4. **合并操作**:这是归并排序中的关键步骤。我们需要创建一个新的临时数组,比较两个子数组的元素,按顺序将它们添加到临时数组中。比较时,从两个子数组的起始位置开始,选择较小的元素放入新数组,直到其中一...
这里我们将深入探讨两种常见的排序算法:插入排序(Insertion Sort)和归并排序(Merge Sort),它们都是在Java环境下实现的。 **插入排序**是一种简单直观的排序算法,它的工作原理是通过构建有序序列,对于未排序...
在Java中实现归并排序,我们可以分别实现递归版和非递归版,这两种方法各有其特点和适用场景。 ### 1. 分治策略 归并排序的核心是分治法,它将一个大数组分为两个相等或接近相等的子数组,分别对这两个子数组进行...
### Java实现归并排序算法(源代码)知识点详解 #### 一、归并排序概述 归并排序是一种经典的排序算法,其核心思想是分而治之。它将一个大问题分解为若干个相同的小问题来解决,最终通过合并这些小问题的解来得到...
本文将深入探讨四种常见的排序算法:快速排序、归并排序、冒泡排序和选择排序。这些算法不仅在理论上有其重要性,而且在实际编程项目中也经常被用到。 ### 快速排序 快速排序是由英国计算机科学家C.A.R. Hoare提出...
利用分治法思想实现归并排序,Java语言描述。
它将数组分为两半,分别对左右两半进行归并排序,然后再合并这两个已排序的子数组。Java中,可以使用两个辅助数组来辅助排序和合并的过程。 6. **希尔排序(Shell Sort)**: 希尔排序是插入排序的一种优化版本,...