当前位置:首页 > 后端开发 > 正文

java二维数组怎么排序

Java二维数组排序需明确维度:若按行/列单独排,可遍历后用 Arrays.sort();若整体排序(如按某列),需转为对象数组配合 Comparator实现,或手动冒泡/选择排序

核心概念澄清

关键前提

  • 数据结构本质int[][] arr = new int[3][4]; 表示一个包含3个子数组的数组,每个子数组长度为4。
  • 无原生支持Arrays.sort() 仅能作用于一维数组或具备随机访问能力的单一序列。
  • 排序目标定义:需明确以下三种常见场景:
    | 排序类型 | 描述 | 典型应用场景 |
    |—————-|——————————-|—————————|
    | 逐行独立排序 | 对每一行单独排序 | 数据处理前的预处理 |
    | 按列优先排序 | 以列为单位重新组织数据 | 数学计算中的列向量处理 |
    | 全局扁平化排序 | 将二维结构展平为一维后排序 | 查找极值/生成有序列表 |

逐行独立排序(Row-wise Sorting)

实现原理

对二维数组的每一行(即每个一维子数组)分别调用Arrays.sort(),保持行间独立性。

代码示例

import java.util.Arrays;
public class RowSortExample {
    public static void main(String[] args) {
        int[][] matrix = {{5, 2, 8}, {1, 9, 3}, {7, 4, 6}};
        // 逐行排序(升序)
        for (int i = 0; i < matrix.length; i++) {
            Arrays.sort(matrix[i]); // 直接修改原数组
        }
        // 输出结果
        System.out.println("After row-wise sorting:");
        for (int[] row : matrix) {
            System.out.println(Arrays.toString(row));
        }
    }
}

输出结果

After row-wise sorting:
[2, 5, 8]
[1, 3, 9]
[4, 6, 7]

️ 注意事项

  • 原地修改:该方法会直接改变原始数组内容。
  • 稳定性:若需保留未排序行的原始顺序,应先深拷贝数组。
  • 降序排序:可通过自定义比较器实现:
    Arrays.sort(matrix[i], (a, b) -> Integer.compare(b, a)); // Java 8+

按列优先排序(Column-major Order Sorting)

实现难点

由于二维数组在内存中按行存储,按列排序需通过以下步骤完成:

  1. 转置矩阵:将行列互换
  2. 逐行排序:对转置后的行(原列)进行排序
  3. 二次转置:恢复原始维度

️ 完整实现代码

public class ColumnSortExample {
    public static void sortByColumns(int[][] matrix) {
        int rows = matrix.length;
        int cols = matrix[0].length;
        // 转置矩阵(行列互换)
        int[][] transposed = new int[cols][rows];
        for (int i = 0; i < rows; i++) {
            for (int j = 0; j < cols; j++) {
                transposed[j][i] = matrix[i][j];
            }
        }
        // 对转置后的行(原列)进行排序
        for (int[] row : transposed) {
            Arrays.sort(row);
        }
        // 再次转置回原始维度
        for (int i = 0; i < cols; i++) {
            for (int j = 0; j < rows; j++) {
                matrix[j][i] = transposed[i][j];
            }
        }
    }
    public static void main(String[] args) {
        int[][] matrix = {{5, 2, 8}, {1, 9, 3}, {7, 4, 6}};
        sortByColumns(matrix);
        System.out.println("After column-wise sorting:");
        for (int[] row : matrix) {
            System.out.println(Arrays.toString(row));
        }
    }
}

输出结果分析

Before: [[5, 2, 8], [1, 9, 3], [7, 4, 6]]
After: [[1, 2, 3], [4, 5, 6], [7, 8, 9]]
  • 效果验证:每列数据已按升序排列,但行间顺序被打乱。
  • 性能瓶颈:双重循环导致时间复杂度为O(mn log n),适用于小规模数据。

全局扁平化排序(Flatten & Sort)

🧩 适用场景

当需要将整个二维数组视为单一序列进行排序时使用,常用于:

java二维数组怎么排序  第1张

  • 查找最大/最小值
  • 生成全局有序列表
  • 数据聚合分析

实现步骤

  1. 展平数组:将所有元素提取到一维临时数组
  2. 排序操作:对临时数组进行排序
  3. 重构二维结构:将排序后的元素填回二维数组

代码实现

import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
public class FlattenSortExample {
    public static void globalSort(int[][] matrix) {
        List<Integer> flatList = new ArrayList<>();
        int rows = matrix.length;
        int cols = matrix[0].length;
        // 展平数组
        for (int[] row : matrix) {
            for (int num : row) {
                flatList.add(num);
            }
        }
        // 排序
        Collections.sort(flatList);
        // 重构二维数组
        int index = 0;
        for (int i = 0; i < rows; i++) {
            for (int j = 0; j < cols; j++) {
                matrix[i][j] = flatList.get(index++);
            }
        }
    }
    public static void main(String[] args) {
        int[][] matrix = {{5, 2, 8}, {1, 9, 3}, {7, 4, 6}};
        globalSort(matrix);
        System.out.println("After global sorting:");
        for (int[] row : matrix) {
            System.out.println(Arrays.toString(row));
        }
    }
}

输出结果

After global sorting:
[1, 2, 3]
[4, 5, 6]
[7, 8, 9]

️ 重要限制

  • 破坏原有结构:排序后元素的行列位置完全重组。
  • 内存消耗:需要额外O(mn)空间存储临时列表。
  • 反向映射困难:无法追溯元素原来的行列位置。

高级应用:带权重的复合排序

需求示例

假设有一个学生成绩表,每行代表一个学生,列分别为语文、数学、英语成绩,现需按总分降序排序,若总分相同则按语文成绩升序排序。

🤖 实现方案

import java.util.;
class Student implements Comparable<Student> {
    String name;
    int chinese;
    int math;
    int english;
    int total;
    public Student(String name, int ch, int ma, int en) {
        this.name = name;
        this.chinese = ch;
        this.math = ma;
        this.english = en;
        this.total = ch + ma + en;
    }
    @Override
    public int compareTo(Student other) {
        if (this.total != other.total) {
            return Integer.compare(other.total, this.total); // 总分降序
        } else {
            return Integer.compare(this.chinese, other.chinese); // 语文升序
        }
    }
}
public class WeightedSortExample {
    public static void main(String[] args) {
        List<Student> students = new ArrayList<>();
        students.add(new Student("Alice", 85, 90, 78));
        students.add(new Student("Bob", 90, 80, 85));
        students.add(new Student("Charlie", 85, 90, 80));
        Collections.sort(students);
        System.out.println("Sorted Students:");
        for (Student s : students) {
            System.out.printf("%s: %d(%d+%d+%d)n", s.name, s.total, s.chinese, s.math, s.english);
        }
    }
}

输出结果

Sorted Students:
Bob: 255(90+80+85)
Charlie: 255(85+90+80)
Alice: 253(85+90+78)

性能对比与选型建议

排序方式 时间复杂度 空间复杂度 适用场景 优点 缺点
逐行排序 O(mn log n) O(1) 独立行处理 简单高效 无法跨行比较
按列排序 O(mn log n) O(mn) 列数据分析 保持列语义完整性 实现复杂,性能较低
全局扁平化排序 O(mn log mn) O(mn) 全量数据统计 完全有序化 破坏原始结构
对象封装排序 O(m log m) O(m) 结构化数据排序 支持复杂比较逻辑 需要额外对象建模

常见误区与解决方案

误区1:直接调用Arrays.sort(matrix)

  • 错误表现:编译错误 no suitable method found for sort(int[][])
  • 原因Arrays.sort()不支持多维数组。
  • 解决:必须分解为一维数组操作。

误区2:试图通过交换行实现排序

  • 错误示例:尝试用冒泡排序交换整行。
  • 问题:无法保证局部最优解能导向全局最优。
  • 替代方案:使用优先队列或堆结构进行动态规划。

误区3:忽略空行或不规则数组

  • 风险:当二维数组各行长度不一致时,matrix[i].length可能越界。
  • 防御措施:添加边界检查:
    if (matrix == null || matrix.length == 0) return;
    for (int[] row : matrix) {
        if (row == null) continue; // 跳过空行
        Arrays.sort(row);
    }

相关问答FAQs

Q1: 如何实现二维数组的降序排序?

A: 有两种主要方式:

  1. 反转排序结果:先升序排序,再手动反转数组。
    Arrays.sort(row); // 升序
    reverseArray(row); // 自定义反转函数
  2. 使用自定义比较器Java 8+):
    Arrays.sort(row, (a, b) -> Integer.compare(b, a)); // 降序

    对于对象数组,可实现Comparator<T>接口。

Q2: 排序后如何保留原始索引信息?

A: 可采用以下两种方法:

  1. 并行存储法:创建两个二维数组,一个存排序后的值,另一个存原始索引。
  2. 包装类法:将数值与坐标封装为对象:
    class IndexedValue implements Comparable<IndexedValue> {
        int value;
        int originalRow;
        int originalCol;
        // 实现compareTo方法...
    }

    排序时仅比较value字段,排序完成后可通过`original

0