跳到主要内容
极客日志极客日志面向AI+效率的开发者社区
首页博客我的书AI学习GitHub 精选镜像AI工具UI配色美学关于
搜索内容 / 工具 / 仓库 / 镜像...⌘K搜索
注册
博客列表
Javajava算法

Java 实现线性方程组求解:LU 分解与部分主元法

Java 实现线性方程组求解:LU 分解结合部分主元法。核心在于将矩阵 A 分解为下三角矩阵 L 和上三角矩阵 U,并通过行交换保证数值稳定性。代码包含完整的分解、前代回代过程及结果输出,适合需要理解数值计算底层逻辑的开发者参考。

霸天发布于 2014/4/16更新于 2026/10/2591 浏览
Java 实现线性方程组求解:LU 分解与部分主元法

Java 实现线性方程组求解:LU 分解与部分主元法

在数值计算中,求解线性方程组 $Ax=b$ 是基础且高频的任务。虽然可以直接调用库函数,但理解底层的 LU 分解(LUP)有助于处理更复杂的数值问题。这里分享一个基于 Java 的完整实现,重点展示了如何通过部分主元法(Partial Pivoting)来避免除零错误并提高精度。

核心思路

我们将系数矩阵 $A$ 分解为一个下三角矩阵 $L$ 和一个上三角矩阵 $U$,同时引入置换向量 $p$ 记录行交换情况。这样原方程转化为 $PAx = Pb$,即 $LUx = Pb$。求解分为两步:先向前代入求中间变量 $Y$,再向后回代求最终解 $X$。

代码实现

package com.data.struct;

public class LinearEquation {
    // 系数矩阵 A
    private double[][] A = new double[][]{
        {1, 2, 0},
        {3, 4, 4},
        {5, 6, 3}
    };
    // 常数向量 B
    private double[] B = new double[]{3, 7, 8};
    
    // 存储分解后的 L 和 U 矩阵
    private double[][] L = new double[3][3];
    private double[][] U = new double[3][3];
    // 行交换记录
    private int[] p = new int[3];
    // 解向量 X
    private double[] X = new double[3];

    public void solve() throws Exception {
        lupDecomposition();
        
        // 1. 前代过程:求解 Ly = Pb
        double[] Y = new double[3];
        for (int i = 0; i < 3; i++) {
            Y[i] = B[p[i]];
            double sub = 0;
            for (int j = 0; j <= i - 1; j++) {
                sub += L[i][j] * Y[j];
            }
            Y[i] = Y[i] - sub;
        }

        // 2. 回代过程:求解 Ux = Y
        for (int i = 2; i >= 0; i--) {
            double sub = 0;
            for (int j = i + 1; j < 3; j++) {
                sub += U[i][j] * X[j];
            }
            X[i] = (Y[i] - sub) / U[i][i];
        }
    }

    // LUP 分解核心逻辑
    private void lupDecomposition() throws Exception {
        // 初始化置换向量
        for (int i = 0; i < 3; i++) {
            p[i] = i;
        }

        for (int k = 0; k < 3; k++) {
            // 选主元:寻找当前列绝对值最大的行
            double s = 0;
            int k2 = k;
            for (int i = k; i < 3; i++) {
                if (Math.abs(A[i][k]) > s) {
                    s = Math.abs(A[i][k]);
                    k2 = i;
                }
            }
            
            // 如果主元为 0,说明矩阵奇异
            if (s == 0) {
                throw new Exception("error");
            }

            // 交换行记录
            int tmp = p[k];
            p[k] = p[k2];
            p[k2] = tmp;

            // 交换实际矩阵行
            for (int i = 0; i < 3; i++) {
                double tmp2 = A[k][i];
                A[k][i] = A[k2][i];
                A[k2][i] = tmp2;
            }

            // 高斯消元更新 A 为 L 和 U 的混合形式
            for (int i = k + 1; i < 3; i++) {
                A[i][k] = A[i][k] / A[k][k];
                for (int j = k + 1; j < 3; j++) {
                    A[i][j] = A[i][j] - A[i][k] * A[k][j];
                }
            }
        }

        // 从修改后的 A 中提取 L 和 U
        for (int i = 0; i < 3; i++) {
            for (int j = 0; j <= i; j++) {
                if (i == j) {
                    L[i][j] = 1;
                } else {
                    L[i][j] = A[i][j];
                }
            }
            for (int j = i; j < 3; j++) {
                U[i][j] = A[i][j];
            }
        }
    }

    public void printL() {
        for (int i = 0; i < 3; i++) {
            for (int j = 0; j < 3; j++) {
                System.out.print(L[i][j] + " ");
            }
            System.out.println();
        }
    }

    public void printU() {
        for (int i = 0; i < 3; i++) {
            for (int j = 0; j < 3; j++) {
                System.out.print(U[i][j] + " ");
            }
            System.out.println();
        }
    }

    public void print() {
        System.out.println("Solution X:");
        for (int i = 0; i < 3; i++) {
            System.out.println("X[" + i + "] = " + X[i]);
        }
    }

    public static void main(String[] args) {
        try {
            LinearEquation solver = new LinearEquation();
            solver.solve();
            System.out.println("Matrix L:");
            solver.printL();
            System.out.println("Matrix U:");
            solver.printU();
            solver.print();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

关键点解析

  1. 部分主元法:在每一列消元前,都会查找该列下方绝对值最大的元素作为主元。这能有效防止除以极小值导致的数值溢出或精度丢失。
  2. 原地分解:为了节省空间,代码直接在原矩阵 A 上进行操作,利用下三角区域存 L(不含对角线),上三角区域存 U。
  3. 异常处理:当检测到主元为 0 时抛出异常,这意味着矩阵不可逆,无法求解唯一解。

总结

这个实现虽然针对的是 3x3 矩阵,但逻辑适用于任意阶数。在实际工程中,如果涉及大规模计算,建议直接使用 Apache Commons Math 等成熟库,但在面试或算法学习场景下,手写一遍能帮你彻底搞懂数值线性代数的门道。

目录

  1. Java 实现线性方程组求解:LU 分解与部分主元法
  2. 核心思路
  3. 代码实现
  4. 关键点解析
  5. 总结

更多推荐文章

查看全部
  • 链表实现解析:结构体与数组两种方式对比
  • LLM 大模型入门项目推荐:多模态与 RAG 实战指南
  • 智慧仓储机器人数据采集与物联网运维方案
  • C++ 图论实战:深入理解三种最短路径算法
  • AI 大模型时代产品经理核心能力与学习指南
  • DeepSeek-R1 大模型基于 MS-Swift 框架部署、推理与微调实战
  • Kafka 生产者 API 快速上手与 Scala 实现
  • VSCode 本地运行 DeepSeek 搭建私人 AI 助手
  • 38 岁俄罗斯程序员 20 年编码生涯的 16 条人生建议
  • 七款主流大模型英文降重能力横向测评
  • 2025 年 12 月 GESP CCF 编程能力等级认证 C++ 六级真题
  • 深入理解 Java 虚拟机内存模型
  • VSCode 本地运行 DeepSeek 模型教程
  • OpenClaw 开源 AI Agent 框架解析
  • 基于 Qt 与 C++ 的经典游戏小球打砖块完整项目实战
  • AI 大模型在金融、医疗、法律等垂直领域的创新应用与突破
  • LogicGame:清华智谱发布大模型规则推理新基准
  • 昇腾平台 DeepSeek-R1 与 Qwen2.5 强化学习训练优化实践
  • OpenClaw 跨平台 AI 助手完全使用指南:从入门到精通
  • Neo4j Desktop 2 安装与实战指南

相关免费在线工具

  • Keycode 信息

    查找任何按下的键的javascript键代码、代码、位置和修饰符。 在线工具,Keycode 信息在线工具,online

  • Escape 与 Native 编解码

    JavaScript 字符串转义/反转义;Java 风格 \uXXXX(Native2Ascii)编码与解码。 在线工具,Escape 与 Native 编解码在线工具,online

  • JavaScript / HTML 格式化

    使用 Prettier 在浏览器内格式化 JavaScript 或 HTML 片段。 在线工具,JavaScript / HTML 格式化在线工具,online

  • JavaScript 压缩与混淆

    Terser 压缩、变量名混淆,或 javascript-obfuscator 高强度混淆(体积会增大)。 在线工具,JavaScript 压缩与混淆在线工具,online

  • 加密/解密文本

    使用加密算法(如AES、TripleDES、Rabbit或RC4)加密和解密文本明文。 在线工具,加密/解密文本在线工具,online

  • Gemini 图片去水印

    基于开源反向 Alpha 混合算法去除 Gemini/Nano Banana 图片水印,支持批量处理与下载。 在线工具,Gemini 图片去水印在线工具,online