《Java数据结构与算法》第二篇:线性表(下)——Java实现一元多项式乘法运算:从原理到实战的完整指南

新星杯·14天创作挑战营·第17期 10w+人浏览 258人参与

目录

前言

代码分享:

一、项目架构深度解析

1.1 主程序类(Main.java) - 程序入口

二、多项式类的核心实现

2.1 链表节点设计:面向对象思维

2.1.1 哑节点设计模式

2.1.2 数据封装原则

三、多项式创建算法:有序插入的智慧

3.1 完整的CreatePolyn方法解析(如果这一块难理解可以先跳转五的insert讲解)

四、多项式乘法:算法核心实现

4.1 multiply方法:数学原理与代码实现

五、插入与合并优化:性能关键点

5.1 insertOrMergeTerm方法深度优化

六、完整测试用例与验证

总结:

致谢:


前言

干货预警!本期内容将深入探讨一元多项式乘法运算的Java实现,涉及链表操作、算法设计、边界处理等核心技术点。文章内容较为深入,建议大家慢慢观看、动手实践,确保完全掌握每个技术细节。

本期我们将完整实现:

一元多项式的链表表示方法

多项式相乘的核心算法

有序链表的插入与合并优化

完整的用户交互界面

相信通过本文的详细剖析,你将彻底掌握多项式运算的底层实现原理!

代码分享:

import java.util.*;

public class Main {
    public static void main(String[] args) {
        polynomial_of_one_variable A = new polynomial_of_one_variable();
        A.CreatePolyn();
//        A.print();
        polynomial_of_one_variable B = new polynomial_of_one_variable();
        B.CreatePolyn();
//        B.print();
        polynomial_of_one_variable C = A.multiply(B);
        System.out.print("A:");
        A.print();
        System.out.println();
        System.out.print("B:");
        B.print();
        System.out.println();
        System.out.print("C:");
        C.print();
    }
}

import java.util.Scanner;

public class polynomial_of_one_variable {
    float coefficient;
    int exponent;
    polynomial_of_one_variable next;
    polynomial_of_one_variable head;

    // 无参构造函数,用于创建哑节点
    polynomial_of_one_variable() {
        this.coefficient = 0;
        this.exponent = -1;  // 特殊标记,表示哑节点
        next = null;
        head = this;  // 哑节点自身就是头节点
    }

    polynomial_of_one_variable(float coefficient, int exponent) {
        this.coefficient = coefficient;
        this.exponent = exponent;
        next = null;
        head = null;
    }

    public void print() {
        polynomial_of_one_variable p;
        if (next == null) {//这里设计为哑节点
            return;
        }
        p = this.next;
        while (p != null) {
            System.out.print(p.coefficient + " ");
            if (p.exponent != 0) {
                System.out.print("*x^" + p.exponent);
            }
            if (p.next != null && p.next.coefficient > 0) {
                System.out.print("+");//负数自带负号
            }
            p = p.next;
        }
    }

    public void CreatePolyn() {
        polynomial_of_one_variable h = head, s, q, p;
        Scanner sc = new Scanner(System.in);
        while (true) {
            System.out.print("Enter coefficient(系数): (指数系数都为0时结束)");
            float coefficient2 = sc.nextFloat();
            System.out.println("Enter exponent(指数): (指数系数都为0时结束)");
            int exponent2 = sc.nextInt();
            if ((int) coefficient2 == 0 && exponent2 == 0) {
                break;
            }
            s = new polynomial_of_one_variable(coefficient2, exponent2);
            q = h.next;
            p = h;
            while (q != null && exponent2 < q.exponent) {
                p = q;
                q = q.next;
            }
            if (q == null || exponent2 > q.exponent) {
                p.next = s;
                s.next = q;
            } else {
                q.coefficient += coefficient2;
            }
        }
    }


    public polynomial_of_one_variable multiply(polynomial_of_one_variable other) {
        // 1. 创建结果多项式的哑节点
        polynomial_of_one_variable result = new polynomial_of_one_variable();

        // 2. 如果任意一个多项式为空,返回空结果
        if (this.next == null || other.next == null) {
            return result;
        }

        // 3. 遍历当前多项式的每一项
        polynomial_of_one_variable p1 = this.next; // 跳过当前多项式的哑节点
        while (p1 != null) {
            // 4. 遍历另一个多项式的每一项
            polynomial_of_one_variable p2 = other.next; // 跳过另一个多项式的哑节点
            while (p2 != null) {
                // 5. 计算两个项的乘积
                float newCoefficient = p1.coefficient * p2.coefficient;
                int newExponent = p1.exponent + p2.exponent;

                // 6. 将乘积项插入到结果多项式中
                insertOrMergeTerm(result, newCoefficient, newExponent);

                p2 = p2.next; // 移动到另一个多项式的下一项
            }
            p1 = p1.next; // 移动到当前多项式的下一项
        }

        return result;
    }


    private void insertOrMergeTerm(polynomial_of_one_variable result, float coefficient, int exponent) {
        // 1. 如果系数为0,不需要插入
        if (coefficient == 0) {
            return;
        }

        // 2. 查找插入位置,其实这部分开始就和上面creat很像了,其实是一模一样,但是为了方便看,改了变量名
        polynomial_of_one_variable current = result; // 从哑节点开始
        polynomial_of_one_variable nextNode = result.next;

        // 找到第一个指数小于或等于新项指数的位置
        while (nextNode != null && exponent < nextNode.exponent) {
            current = nextNode;
            nextNode = nextNode.next;
        }

        // 3. 处理三种情况
        if (nextNode != null && exponent == nextNode.exponent) {
            // 情况1:指数相同,合并系数
            nextNode.coefficient += coefficient;
            // 如果合并后系数为0,删除该节点
            if (nextNode.coefficient == 0) {
                current.next = nextNode.next;
            }
        } else {
            // 情况2:插入新节点
            polynomial_of_one_variable newNode = new polynomial_of_one_variable(coefficient, exponent);
            current.next = newNode;
            newNode.next = nextNode;
        }
        // 情况3:nextNode == null 已经在else中处理(插入到链表末尾)
    }
}

一、项目架构深度解析

1.1 主程序类(Main.java) - 程序入口

import java.util.*;

public class Main {
    public static void main(String[] args) {
        // 创建多项式A:使用哑节点技术初始化
        polynomial_of_one_variable A = new polynomial_of_one_variable();
        A.CreatePolyn(); // 交互式创建多项式,支持实时排序
        
        // 创建多项式B:同样的初始化流程
        polynomial_of_one_variable B = new polynomial_of_one_variable();
        B.CreatePolyn();
        
        // 核心计算:执行多项式乘法运算
        // 算法复杂度:O(m*n),其中m、n分别为两个多项式的项数
        polynomial_of_one_variable C = A.multiply(B);
        
        // 格式化输出结果
        System.out.print("A:");  A.print();  System.out.println();  // 打印多项式A
        System.out.print("B:");  B.print();  System.out.println();  // 打印多项式B  
        System.out.print("C:");  C.print();  // 打印结果多项式C
    }
}

深度解析:

设计模式:采用清晰的"输入-处理-输出"流水线模式

内存管理:每个多项式独立管理,避免内存泄漏

用户体验:分步输入,清晰的结果展示

二、多项式类的核心实现

2.1 链表节点设计:面向对象思维

import java.util.Scanner;

public class polynomial_of_one_variable {
    // 节点数据域:存储系数和指数
    float coefficient;    // 系数:支持浮点数,增强计算精度
    int exponent;        // 指数:必须为整数,表示x的幂次
    
    // 链表指针域
    polynomial_of_one_variable next;  // 后继指针:指向下一个多项式项
    polynomial_of_one_variable head;  // 头指针:始终指向哑节点,维护链表完整性

    // 无参构造函数:创建哑节点(Dummy Node)
    // 哑节点作用:简化边界条件处理,统一插入删除操作
    polynomial_of_one_variable() {
        this.coefficient = 0;      // 哑节点系数为0
        this.exponent = -1;        // 特殊标记(-1),与正常节点区分
        next = null;               // 初始后继为空
        head = this;               // 自引用:哑节点就是头节点
    }

    // 带参构造函数:创建数据节点
    polynomial_of_one_variable(float coefficient, int exponent) {
        this.coefficient = coefficient;  // 初始化系数
        this.exponent = exponent;        // 初始化指数
        next = null;                     // 新节点后继为空
        head = null;                     // 普通节点不维护头指针
    }

关键技术点详解:

2.1.1 哑节点设计模式

// 传统链表 vs 带哑节点链表
// 传统链表插入第一个节点需要特殊处理:
if (head == null) {
    head = newNode;
} else {
    // 正常插入...
}

// 带哑节点链表:所有插入操作统一处理
dummyNode.next = newNode;  // 无需特殊判断

2.1.2 数据封装原则

coefficient使用float类型:支持小数系数,如2.5x²

exponent使用int类型:确保幂次为整数,符合数学定义

指针分离:head指针仅哑节点维护,普通节点专注数据存储

三、多项式创建算法:有序插入的智慧

3.1 完整的CreatePolyn方法解析(如果这一块难理解可以先跳转五的insert讲解)

public void CreatePolyn() {
    // 初始化指针:h指向哑节点,p、q用于遍历查找插入位置
    polynomial_of_one_variable h = head, s, q, p;
    Scanner sc = new Scanner(System.in);
    
    while (true) {  // 持续输入直到用户主动终止
        // 用户交互:输入系数和指数
        System.out.print("Enter coefficient(系数): (指数系数都为0时结束)");
        float coefficient2 = sc.nextFloat();
        System.out.println("Enter exponent(指数): (指数系数都为0时结束)");
        int exponent2 = sc.nextInt();
        
        // 终止条件判断:系数和指数同时为0
        if ((int) coefficient2 == 0 && exponent2 == 0) {
            break;  // 退出输入循环
        }
        
        // 创建新节点:封装用户输入的数据
        s = new polynomial_of_one_variable(coefficient2, exponent2);
        q = h.next;  // q指向第一个数据节点(哑节点之后)
        p = h;       // p指向哑节点,用于记录插入位置的前驱
        
        // **核心算法**:查找有序插入位置
        // 目标:保持多项式按指数降序排列(从高次到低次)
        while (q != null && exponent2 < q.exponent) {
            p = q;          // p跟随q移动,始终指向q的前驱
            q = q.next;     // q向后遍历,直到找到合适位置
        }
        // 循环结束条件:
        // 1. q == null:已到达链表末尾,新项指数最小
        // 2. exponent2 >= q.exponent:找到插入位置
        
        // **三种情况处理策略**
        if (q == null || exponent2 > q.exponent) {
            // 情况1:新项指数唯一,直接插入
            p.next = s;    // 前驱节点指向新节点
            s.next = q;    // 新节点指向后继节点
            // 示例:链表 [x³, x¹] 插入 x² → [x³, x², x¹]
        } else {
            // 情况2:指数已存在,合并同类项
            q.coefficient += coefficient2;  // 系数相加
            
            // 合并后系数为0的特殊处理
            if (q.coefficient == 0) {
                p.next = q.next;  // 跳过当前节点,相当于删除
                // 注意:这里可以优化为实际删除节点释放内存
            }
        }
    }
}

算法流程图解:

输入新项(coefficient, exponent)
    ↓
从哑节点开始遍历
    ↓
while (当前节点存在 且 新指数 < 当前节点指数)
    ↓ 移动指针继续查找
找到插入位置:当前节点指数 ≤ 新指数
    ↓
if (指数相等) → 合并系数
else → 创建新节点插入

四、多项式乘法:算法核心实现

4.1 multiply方法:数学原理与代码实现

public polynomial_of_one_variable multiply(polynomial_of_one_variable other) {
    // 1. 结果多项式初始化:创建哑节点
    polynomial_of_one_variable result = new polynomial_of_one_variable();
    
    // 2. 边界条件检查:空多项式相乘结果为0
    if (this.next == null || other.next == null) {
        return result;  // 返回空多项式(只有哑节点)
    }
    
    // 3. 双重循环遍历:多项式A的每一项 × 多项式B的每一项
    polynomial_of_one_variable p1 = this.next;  // 跳过当前多项式的哑节点
    while (p1 != null) {
        polynomial_of_one_variable p2 = other.next;  // 跳过另一个多项式的哑节点
        
        while (p2 != null) {
            // 4. 数学运算规则:
            // (a*x^m) × (b*x^n) = (a*b)*x^(m+n)
            float newCoefficient = p1.coefficient * p2.coefficient;
            int newExponent = p1.exponent + p2.exponent;
            
            // 5. 将乘积项插入结果多项式(自动排序和合并)
            insertOrMergeTerm(result, newCoefficient, newExponent);
            
            p2 = p2.next;  // 移动B多项式指针
        }
        p1 = p1.next;  // 移动A多项式指针
    }
    
    return result;  // 返回最终结果
}

数学原理示例:

A = 3x² + 2x¹  
B = 4x³ + x¹

计算过程:
3x² × 4x³ = 12x⁵
3x² × x¹   = 3x³  
2x¹ × 4x³ = 8x⁴
2x¹ × x¹   = 2x²

结果:12x⁵ + 8x⁴ + 3x³ + 2x²

五、插入与合并优化:性能关键点

5.1 insertOrMergeTerm方法深度优化

private void insertOrMergeTerm(polynomial_of_one_variable result, float coefficient, int exponent) {
    // 优化1:零系数过滤 - 数学性质利用
    if (coefficient == 0) {
        return;  // 零项不参与运算,直接返回提升性能
    }
    
    // 初始化遍历指针
    polynomial_of_one_variable current = result;      // 当前指针,初始指向哑节点
    polynomial_of_one_variable nextNode = result.next; // 后继指针,指向第一个数据节点
    
    // 优化2:有序查找 - 利用多项式已排序的特性
    // 目标:找到第一个指数 ≤ 新项指数的位置
    while (nextNode != null && exponent < nextNode.exponent) {
        current = nextNode;      // 当前指针跟进
        nextNode = nextNode.next; // 后继指针前移
    }
    // 循环终止时:
    // - nextNode == null:新项应插入链表末尾
    // - exponent >= nextNode.exponent:找到插入位置
    
    // 情况分析处理
    if (nextNode != null && exponent == nextNode.exponent) {
        // 情况1:指数匹配,合并同类项
        nextNode.coefficient += coefficient;  // 系数相加
        
        // 优化3:零系数项清理 - 内存优化
        if (nextNode.coefficient == 0) {
            current.next = nextNode.next;  // 从链表中删除零系数项
            // 注意:实际项目中应该释放nextNode内存
        }
    } else {
        // 情况2:需要插入新节点
        polynomial_of_one_variable newNode = new polynomial_of_one_variable(coefficient, exponent);
        
        // 链表插入操作
        current.next = newNode;   // 前驱节点指向新节点
        newNode.next = nextNode;  // 新节点指向原后继节点
        
        // 示例:在 [x⁴, x²] 中插入 x³
        // 结果:x⁴ → x³ → x²
    }
}

六、完整测试用例与验证

总结:

通过本次一元多项式乘法运算的Java实现,我们成功将数学理论与数据结构完美结合,采用带哑节点的链表结构优雅地解决了多项式表示问题,利用有序插入和实时合并优化确保了运算效率,核心乘法算法通过双重循环遍历实现了完整的多项式相乘逻辑。虽然输出格式化功能尚有优化空间,但整体系统展现了扎实的编程功底和算法设计能力,为后续扩展更复杂的符号运算功能奠定了坚实基础,体现了技术深度与工程价值的完美统一。

致谢:

感谢各位技术爱好者的耐心阅读!由于多项式输出格式化涉及较多的边界情况处理,本文中的print方法确实存在改进空间,欢迎各位读者提出优化建议。

如果本文对你有帮助,请点赞收藏支持。对于多项式输出格式化的优化方案,欢迎在评论区分享你的见解,我们一起完善这个项目!

下期预告:我们将进入第三篇——栈与队列,敬请期待!

评论 5
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值