0

0

Java对象数组归并排序逻辑错误解析与修正

碧海醫心

碧海醫心

发布时间:2025-09-13 12:40:15

|

465人浏览过

|

来源于php中文网

原创

Java对象数组归并排序逻辑错误解析与修正

本文旨在深入分析Java中对对象数组执行归并排序时常见的逻辑错误,特别是子数组创建时的System.arraycopy误用以及merge方法中循环结构的不当,导致排序结果异常。通过详细的错误剖析,提供了一套修正后的归并排序实现方案,包括辅助数组复制方法和优化的合并逻辑,确保对象数组能够正确、高效地进行排序。

1. 归并排序核心原理回顾

归并排序(merge sort)是一种基于分治思想的高效排序算法。其基本步骤如下:

  1. 分解(Divide):将待排序的数组递归地分解为两个子数组,直到每个子数组只包含一个元素(单个元素被认为是自然有序的)。
  2. 解决(Conquer):递归地对每个子数组进行排序。
  3. 合并(Combine):将两个已排序的子数组合并成一个更大的有序数组。这个合并过程是归并排序的核心,它通过比较两个子数组的元素,逐个将较小的(或较大的,取决于排序方向)元素放入结果数组中。

2. Box类及其比较逻辑

在处理对象数组的排序时,我们通常需要定义对象之间的比较规则。在本例中,我们有一个Box类,它包含宽度、高度和长度属性,并通过计算体积来定义其比较逻辑。

public class Box {
  private double width, height, length;

  Box(double w, double h, double l){
    width=w;
    height=h;
    length=l;
  }

  private double getVolume(){
    return width*height*length;
  }

  // 按照体积进行比较,用于升序排序
  public int compareTo(Box o){
    double myVol = this.getVolume();
    double thatVol = o.getVolume();
    if (myVol > thatVol)
      return 1;      // 当前对象体积更大
    else if (myVol < thatVol)
      return -1;     // 当前对象体积更小
    else
      return 0;      // 体积相等
  }

  public String toString(){
    return "Width: "+width+
           "\theight: "+height+
            "\tlength: "+length+
            "\tVolume: "+getVolume();
  }
}

compareTo方法是Java中Comparable接口的一部分,它定义了对象之间自然排序的规则。在本例中,compareTo方法根据Box对象的体积进行比较,返回正数、负数或零,分别表示当前对象大于、小于或等于另一个对象。

3. 原始实现中的关键逻辑错误分析

原始的归并排序实现存在两个主要的逻辑错误,导致排序结果不正确,甚至出现所有元素都被同一个对象覆盖的情况。

3.1 子数组创建错误:System.arraycopy的误用

在mergeSort方法中,将原始数组theBoxes分解为firstHalf和secondHalf时,secondHalf的创建方式存在问题:

立即学习Java免费学习笔记(深入)”;

// 原始错误代码片段
static void mergeSort(Box[] theBoxes) {
    if(theBoxes.length > 1 ){
        Box [] firstHalf = new Box[theBoxes.length/2];
        System.arraycopy(theBoxes, 0 , firstHalf, 0 ,theBoxes.length /2); 
        mergeSort(firstHalf);

        int secondHalfLength = theBoxes.length - theBoxes.length / 2 ; 
        Box [] secondHalf = new Box [secondHalfLength];
        // 错误点:secondHalf也从theBoxes的索引0开始复制
        System.arraycopy(theBoxes, 0 , secondHalf, 0 ,secondHalfLength); 
        mergeSort(secondHalf);

        merge(firstHalf, secondHalf , theBoxes); 
    }
}

问题在于secondHalf的创建。System.arraycopy(theBoxes, 0, secondHalf, 0, secondHalfLength); 这行代码将theBoxes数组从索引0开始复制secondHalfLength个元素到secondHalf。这意味着,如果theBoxes是[A, B, C, D],firstHalf会正确地得到[A, B],但secondHalf也会得到[A, B](如果secondHalfLength是2),而不是期望的[C, D]。

这样会导致merge方法在合并时,实际上是在合并两个部分或完全重叠的子数组,而不是两个独立的、已排序的子数组,从而使最终的排序结果错误,甚至可能出现所有元素都变成同一个对象的情况(如果重复合并导致某个特定对象被反复选中)。

3.2 merge方法中的循环结构问题

原始的merge方法在处理合并逻辑时,其内部的循环结构也存在一个不易察觉的错误:

// 原始错误代码片段
static void merge(Box [] list1, Box [] list2 , Box [] temp ){
    int current1 = 0;
    int current2 = 0;
    int current3 = 0; 

    while (current1 < list1.length && current2 < list2.length){
        // 比较逻辑(此处假设为降序,与compareTo的升序定义不符,后面会修正)
        if(list1[current1].compareTo(list2[current2]) > 0){ 
            temp[current3++] = list1[current1++];
        }else{
            temp[current3++] = list2[current2++];
        }

        // 错误点:这两个while循环不应该嵌套在主while循环内部
        while(current1 < list1.length){
            temp[current3++] = list1[current1++];
        }
        while(current2 < list2.length){
            temp[current3++] = list2[current2++];
        }
    }
}

在merge方法中,用于复制剩余元素的两个while循环被错误地放置在了主while (current1 某一次迭代结束后,如果其中一个子列表恰好耗尽,这两个内部循环才会尝试执行。但在主循环的后续迭代中,它们会被跳过。

正确的做法是,主循环负责在两个子数组都有元素时进行比较和合并,而当其中一个子数组耗尽后,将另一个子数组中剩余的所有元素直接复制到目标数组中。因此,这两个处理剩余元素的while循环应该放在主while循环的外部

MedPeer科研绘图
MedPeer科研绘图

生物医学领域的专业绘图解决方案,告别复杂绘图,专注科研创新

下载

3.3 排序方向与compareTo的匹配

原始merge方法中的比较条件if(list1[current1].compareTo(list2[current2]) > 0)。如果compareTo返回1表示list1的元素更大,那么这个条件成立时,会将list1[current1]放入temp数组。这意味着它在选择更大的元素,从而实现的是降序排序。然而,Box类的compareTo方法通常按照标准约定用于实现升序排序(即this小于o时返回负数)。为了保持一致性并实现升序排序,merge方法中的比较逻辑也需要调整。

4. 修正后的归并排序实现

为了解决上述问题,我们需要对mergeSort和merge方法进行修正。

4.1 arrayCopy辅助方法

为了避免System.arraycopy的误用,我们可以编写一个简单的辅助方法来从源数组的指定范围复制元素到新数组。

static Box[] arrayCopy(Box[] sourceArray, int startIndex, int endIndex) {
    Box[] tempArray = new Box[endIndex - startIndex];
    for (int i = startIndex, m = 0; i < endIndex; i++, m++) {
        tempArray[m] = sourceArray[i];
    }
    return tempArray;
}

这个arrayCopy方法接收源数组、起始索引和结束索引(不包含),然后创建一个新数组,并将指定范围内的元素复制过去。

4.2 修正后的mergeSort方法

使用arrayCopy辅助方法来正确地创建firstHalf和secondHalf子数组。

static void mergeSort(Box[] theBoxes) {
    if (theBoxes.length > 1) {
        int mid = theBoxes.length / 2;

        // 正确创建firstHalf,从theBoxes的0到mid-1
        Box[] firstHalf = arrayCopy(theBoxes, 0, mid);
        mergeSort(firstHalf);

        // 正确创建secondHalf,从theBoxes的mid到theBoxes.length-1
        Box[] secondHalf = arrayCopy(theBoxes, mid, theBoxes.length);
        mergeSort(secondHalf);

        merge(firstHalf, secondHalf, theBoxes);
    }
}

通过arrayCopy(theBoxes, mid, theBoxes.length),secondHalf现在将正确地包含原始数组的后半部分元素,解决了子数组内容重叠的问题。

4.3 修正后的merge方法

修正merge方法中的循环结构,并将比较逻辑调整为实现升序排序。

static void merge(Box[] list1, Box[] list2, Box[] temp) {
    int current1 = 0; // 指向list1的当前元素
    int current2 = 0; // 指向list2的当前元素
    int current3 = 0; // 指向temp数组的当前位置

    // 当两个子数组都有元素时,进行比较并合并
    while (current1 < list1.length && current2 < list2.length) {
        // 对于升序排序,选择较小的元素放入temp数组
        if (list1[current1].compareTo(list2[current2]) <= 0) { // 如果list1的元素更小或相等
            temp[current3++] = list1[current1++];
        } else { // 如果list2的元素更小
            temp[current3++] = list2[current2++];
        }
    }

    // 将list1中剩余的元素复制到temp数组(如果list2先耗尽)
    while (current1 < list1.length) {
        temp[current3++] = list1[current1++];
    }

    // 将list2中剩余的元素复制到temp数组(如果list1先耗尽)
    while (current2 < list2.length) {
        temp[current3++] = list2[current2++];
    }
}

修正后的merge方法将处理剩余元素的while循环移到了主循环之外,确保了所有元素都能被正确复制。同时,if (list1[current1].compareTo(list2[current2])

5. 完整示例代码

结合Box类、修正后的arrayCopy、mergeSort和merge方法,以下是一个完整的Java归并排序示例:

import java.util.Arrays;

public class MergeSortObjects {

    // Box类(保持不变)
    public static class Box {
        private double width, height, length;

        Box(double w, double h, double l) {
            width = w;
            height = h;
            length = l;
        }

        private double getVolume() {
            return width * height * length;
        }

        // 按照体积进行升序比较
        public int compareTo(Box o) {
            double myVol = this.getVolume();
            double thatVol = o.getVolume();
            if (myVol > thatVol)
                return 1;
            else if (myVol < thatVol)
                return -1;
            else
                return 0;
        }

        @Override
        public String toString() {
            return "Width: " + String.format("%.1f", width) +
                   "\theight: " + String.format("%.1f", height

相关专题

更多
java
java

Java是一个通用术语,用于表示Java软件及其组件,包括“Java运行时环境 (JRE)”、“Java虚拟机 (JVM)”以及“插件”。php中文网还为大家带了Java相关下载资源、相关课程以及相关文章等内容,供大家免费下载使用。

841

2023.06.15

java正则表达式语法
java正则表达式语法

java正则表达式语法是一种模式匹配工具,它非常有用,可以在处理文本和字符串时快速地查找、替换、验证和提取特定的模式和数据。本专题提供java正则表达式语法的相关文章、下载和专题,供大家免费下载体验。

742

2023.07.05

java自学难吗
java自学难吗

Java自学并不难。Java语言相对于其他一些编程语言而言,有着较为简洁和易读的语法,本专题为大家提供java自学难吗相关的文章,大家可以免费体验。

738

2023.07.31

java配置jdk环境变量
java配置jdk环境变量

Java是一种广泛使用的高级编程语言,用于开发各种类型的应用程序。为了能够在计算机上正确运行和编译Java代码,需要正确配置Java Development Kit(JDK)环境变量。php中文网给大家带来了相关的教程以及文章,欢迎大家前来阅读学习。

397

2023.08.01

java保留两位小数
java保留两位小数

Java是一种广泛应用于编程领域的高级编程语言。在Java中,保留两位小数是指在进行数值计算或输出时,限制小数部分只有两位有效数字,并将多余的位数进行四舍五入或截取。php中文网给大家带来了相关的教程以及文章,欢迎大家前来阅读学习。

399

2023.08.02

java基本数据类型
java基本数据类型

java基本数据类型有:1、byte;2、short;3、int;4、long;5、float;6、double;7、char;8、boolean。本专题为大家提供java基本数据类型的相关的文章、下载、课程内容,供大家免费下载体验。

446

2023.08.02

java有什么用
java有什么用

java可以开发应用程序、移动应用、Web应用、企业级应用、嵌入式系统等方面。本专题为大家提供java有什么用的相关的文章、下载、课程内容,供大家免费下载体验。

430

2023.08.02

java在线网站
java在线网站

Java在线网站是指提供Java编程学习、实践和交流平台的网络服务。近年来,随着Java语言在软件开发领域的广泛应用,越来越多的人对Java编程感兴趣,并希望能够通过在线网站来学习和提高自己的Java编程技能。php中文网给大家带来了相关的视频、教程以及文章,欢迎大家前来学习阅读和下载。

16926

2023.08.03

Java JVM 原理与性能调优实战
Java JVM 原理与性能调优实战

本专题系统讲解 Java 虚拟机(JVM)的核心工作原理与性能调优方法,包括 JVM 内存结构、对象创建与回收流程、垃圾回收器(Serial、CMS、G1、ZGC)对比分析、常见内存泄漏与性能瓶颈排查,以及 JVM 参数调优与监控工具(jstat、jmap、jvisualvm)的实战使用。通过真实案例,帮助学习者掌握 Java 应用在生产环境中的性能分析与优化能力。

19

2026.01.20

热门下载

更多
网站特效
/
网站源码
/
网站素材
/
前端模板

精品课程

更多
相关推荐
/
热门推荐
/
最新课程
Kotlin 教程
Kotlin 教程

共23课时 | 2.7万人学习

C# 教程
C# 教程

共94课时 | 7.1万人学习

Java 教程
Java 教程

共578课时 | 48.2万人学习

关于我们 免责申明 举报中心 意见反馈 讲师合作 广告合作 最新更新
php中文网:公益在线php培训,帮助PHP学习者快速成长!
关注服务号 技术交流群
PHP中文网订阅号
每天精选资源文章推送

Copyright 2014-2026 https://www.php.cn/ All Rights Reserved | php.cn | 湘ICP备2023035733号