引入:
偶尔看到有道算法题是要输入任意2个一元多项式(所谓一元多项式就是只有一个自变量,比如X),要求计算其和。
分析:
(1)考虑到多项式的加法就是合并同类项的过程,刚开始考虑到时候可能用顺序表来实现,但是考虑到给定的多项式输入可能指数差别很大,比如某个项最高指数为1000,最低指数为-1000,我们没必要给出一个长度为2000的顺序表,这样太浪费内存了,所以我们考虑到用单向链表来实现,其中每个项作为单向链表的某个节点,然后多项式就是一个单向链表。
(2)这里还必须考虑到用户的输入,比如可以输入正指数,可能输出负指数,而且给的项的幂可能是乱的,我们必须按照通常的降幂排列这个多项式,然后才可以计算。
(3)最后,在输出多项式时候还必须要注意特殊的幂,比如一般的项的输出形式可能是X^2这种形式,但是1阶则不用输出^, 0阶则既不用输出X,也不用输出0,还有就是如果阶为负数,则应该用括号括出来。
实践:
掌握了上述的方法后,这个很显而易见就能实现出来了。
首先定义一个多项式的项Item类,它是一个单向链表:
package com.charles.algo.ploy;
/**
* @author charles.wang
* 这是一个多项式的项
*/
public class Item {
//项的系数
private int xishu;
//项的指数
private int pos;
//下一个项
private Item next;
public Item(int xishu,int pos,Item next){
this.xishu=xishu;
this.pos = pos;
this.next= next;
}
public int getXishu() {
return xishu;
}
public void setXishu(int xishu) {
this.xishu = xishu;
}
public int getPos() {
return pos;
}
public void setPos(int pos) {
this.pos = pos;
}
public Item getNext() {
return next;
}
public void setNext(Item next) {
this.next = next;
}
}
然后我们就来定义多项式了,它应该包括许多基本操作,比如如果构造一个多项式,就是添加一个新项,如果找到和参数的项匹配的位于该多项式的项,如果把该多项式和一个单项做加法,如果按照降幂顺序打印出当前多项式。我的代码有了非常详尽的注释,所以这不再罗嗦了。
package com.charles.algo.ploy;
/**
* 这里用一个单向链表来表示一个多项式, 因为多项式的指数的跨度可能很多,所以不适合用顺序表来表示
*
* @author charles.wang
*
*/
public class Poly {
// 最高项
private Item highestItem;
/**
* 构造器
*/
public Poly() {
highestItem = new Item(0, 0, null);
}
/**
* 插入一个新项到已有的多项式,这个项必须和已知多项式的任何一个项都不相同
*
* @return
*/
public Poly insertItemToPoly(int xishu, int pos) {
// 如果当前的Poly什么都没有,那么直接构造一个项并且赋值给highestItem
if (highestItem.getXishu() == 0) {
Item newItem = new Item(xishu, pos, null);
highestItem = newItem;
return this;
}
// 如果当前的pos(幂)和当前Poly的某一个相同了,那么则无法插入这个Item
if (searchSamePosItem(pos) != null) {
return this;
}
// 如果当前指数高于最高项,那么新创建这个项,并且设为最高项
if (highestItem.getPos() < pos) {
Item newItem = new Item(xishu, pos, null);
// 吧新创建的项设为最高项
newItem.setNext(highestItem);
// 更新当前最高项
highestItem = newItem;
return this;
}
// 如果当前指数低于最高项,那么新创建这个项,并且按照降序排列找到合适的位置插入
Item newItem = new Item(xishu, pos, null);
Item currentItem = highestItem;
Item currentItemNextItem = null;
// 跳出循环条件是遍历到了多项式的最低项
while (currentItem != null) {
// 获取当前项的下一个项
currentItemNextItem = currentItem.getNext();
// 如果当前项的下一个项为null,则说明已经到了尾部,则直接插入,并且跳出循环
if (currentItemNextItem == null) {
currentItem.setNext(newItem);
break;
}
// 如果当前项的下一个项不为null,则比较当前的指数是否在2个项的指数之间,如果是,则插入,并且跳出循环,否则遍历下一个
else if (pos < currentItem.getPos()
&& pos > currentItemNextItem.getPos()) {
newItem.setNext(currentItemNextItem);
currentItem.setNext(newItem);
break;
}
// 否则,更新currentItem为currentItemNextItem,并且进行下一次循环
currentItem = currentItemNextItem;
}
return this;
}
/**
* 为当前多项式做加法运算,则会找到指数相同的项,然后合并同类项
*/
public Poly addOperatorWithSingleItem(int xishu, int pos) {
// 如果当前的Poly什么都没有,那么直接构造一个项并且赋值给highestItem
if (highestItem.getXishu() == 0) {
Item newItem = new Item(xishu, pos, null);
highestItem = newItem;
return this;
}
// 如果当前的pos(幂)和当前Poly的某一个项的指数相同,则合并同类项
Item matchingItem = searchSamePosItem(pos);
if (matchingItem != null) {
// 吧系数相加获得新的系数
int newXishu = matchingItem.getXishu() + xishu;
// 遍历多项式来找到匹配的,更新前后引用对象
Item currentItem = highestItem;
Item currentItemNextItem;
while (currentItem != null) {
// 如果是最高项,并且匹配指数
if (currentItem == highestItem && currentItem.getPos() == pos) {
// 创建新的项,并且让其成为最高项
Item newItem = new Item(newXishu, pos, null);
newItem.setNext(highestItem.getNext());
highestItem = newItem;
return this;
}
// 如果最高项的下一个项为null,这不可能,
// 因为我们已经search到matchingItems了,所以这里蕴含着最高项的下一个项一定不为null,因此不用判断
currentItemNextItem = currentItem.getNext();
// 找到匹配的了,执行替换
if (currentItemNextItem.getPos() == pos) {
Item newItem = new Item(newXishu, pos, null);
newItem.setNext(currentItemNextItem.getNext());
currentItem.setNext(newItem);
return this;
}
// 找不到匹配的了,则继续往更低的项上找
currentItem = currentItemNextItem;
}
return this;
}
// 如果当前的pos(幂)和当前Poly的任意一个项的指数都不同,那么做insertItemToPloy操作
else
return insertItemToPoly(xishu, pos);
}
/**
* 在当前多项式中搜索与给定的指数相同的项
*/
private Item searchSamePosItem(int pos) {
// 如果当前的Poly什么都没有,当然也就没有匹配指数的项了
if (highestItem.getXishu() == 0) {
return null;
}
// 如果给定的指数高于最高指数,那么肯定没有匹配
if (highestItem.getPos() < pos) {
return null;
}
// 否则,从最高项开始遍历,一直遍历到最低项,找到满足条件的项
Item searchingItem = highestItem;
while (searchingItem != null) {
// 获取当前的查阅的项的指数
int posOfSearchingItem = searchingItem.getPos();
if (posOfSearchingItem == pos)
return searchingItem;
// 否则,将当前搜索的Item移到下一个低于当前Item指数的项
searchingItem = searchingItem.getNext();
}
// 如果一直搜到searchingItem为null了(也就是一直搜索到多项式的最后一个项了依然找不到),那么返回null表明找不到匹配指数的项
return null;
}
/**
* 按照降幂顺序打印出当前的多项式
*/
public void printPoly() {
Item currentItem = highestItem;
Item currentItemNextItem;
int xishu;
int pos;
// 从最高项开始遍历
while (currentItem != null) {
// 获取当前的要打印项的系数和指数,以及下一个项目
xishu = currentItem.getXishu();
pos = currentItem.getPos();
currentItemNextItem = currentItem.getNext();
// 打印系数
System.out.print(xishu);
// 如果当前指数为0阶,则不用打印X
// 如果当前指数是1阶,那么只打印X,不打印^
if (pos == 1)
System.out.print("X");
// 如果当前指数既不是0阶又不是1阶,则打印出 X^ ,后面跟上指数
else if (pos != 0 && pos != 1) {
// 如果指数小于0,则用()括号括出来
if (pos < 0)
System.out.print("X^" + "(" + pos + ")");
else
System.out.print("X^" + pos);
}
// 如果下个项存在并且下个项系数大于0,则打印加号,否则就不打印符号。
// 因为 (1)如果项已经达到项尾则不用带符号
// (2)如果系数小于0自带减号,
if (currentItemNextItem != null
&& currentItemNextItem.getXishu() > 0)
System.out.print("+");
currentItem = currentItemNextItem;
}
}
/**
* 返回多项式的最高项Item
*
*/
public Item getHighestItem() {
return highestItem;
}
public static void main(String[] args) {
Poly poly1 = new Poly();
// 构造多项式 5X+3X^4-7X^2+6+12X^(-2) ,它应该被正确输入
poly1.insertItemToPoly(5, 1).insertItemToPoly(3, 4)
.insertItemToPoly(-7, 2).insertItemToPoly(6, 0)
.insertItemToPoly(12, -2);
System.out.print("原始多项式为:");
poly1.printPoly();
System.out.println();
// 执行多项式与某个项的相加
// 第一个被加的项6X^3和其中任何一个项的指数都不同
poly1.addOperatorWithSingleItem(6, 3);
System.out.print("加上6X^3后,新多项式为:");
poly1.printPoly();
System.out.println();
// 执行多项式与某个项的相加
// 第二个被加的项7X^4和其中最高项指数相同
poly1.addOperatorWithSingleItem(7, 4);
System.out.print("加上7X^4后,新多项式为:");
poly1.printPoly();
System.out.println();
// 执行多项式与某个项相加
// 第三个被加的项9X^2和其中非最高项-7X^2指数相同
poly1.addOperatorWithSingleItem(9, 2);
System.out.print("加上9X^2后,新多项式为:");
poly1.printPoly();
System.out.println();
}
}
我们来测试这个多项式的有效性,为此我们先构造多项式 5X+3X^4-7X^2+6+12X^(-2),然后依次与3个项分别相加,这3个项分别都很典型,一个是不和多项式任意项指数匹配的项,一个是与最高项指数匹配的项,一个是不和最高项指数匹配的项。我们运行上面的main方法,运行结果果然与我们所料。
因为我们最终的目的是执行多项式的加法,所以我们写了一个工具类,2个多项式的加法可以看成是吧多项式A和多项式B中的所有项依次相加,这也就是我们的方法实现了:
package com.charles.algo.ploy;
/**
* @author charles.wang
* 工具类,执行多项式相加
*/
public class PolyUtil {
private PolyUtil(){}
/**
* 执行2个多项式相加
* @param poly1
* @param poly2
* @return
*/
public static Poly polyAdd (Poly poly1,Poly poly2){
Poly newPoly1 = poly1;
//很简单,就是把poly2从最高多项式进行遍历,然后把每个项依次和poly1相加
Item currentItemInPoly2=poly2.getHighestItem();
while(currentItemInPoly2!=null){
//获取poly2中当前的项,将其加到poly1多项式中
newPoly1.addOperatorWithSingleItem(currentItemInPoly2.getXishu(), currentItemInPoly2.getPos());
currentItemInPoly2=currentItemInPoly2.getNext();
}
return newPoly1;
}
public static void main(String [] args){
//构造多项式1 7X^4+5X^2-6X^(-4)+13X+5
Poly poly1 = new Poly();
poly1.insertItemToPoly(7, 4).insertItemToPoly(5, 2).insertItemToPoly(-6, -4)
.insertItemToPoly(13, 1).insertItemToPoly(5, 0);
System.out.println("多项式1为:");
poly1.printPoly();
//构造多项式2 5X^5-3X^8+3X^2+7X+9X^(-3)+4X^(-4)
Poly poly2= new Poly();
poly2.insertItemToPoly(5, 5).insertItemToPoly(-3,8).insertItemToPoly(3,2)
.insertItemToPoly(7, 1).insertItemToPoly(9, -3).insertItemToPoly(4,-4);
System.out.println("多项式2为:");
poly2.printPoly();
//执行多项式加法
Poly newPloy = polyAdd(poly1,poly2);
System.out.println("执行多项式加法后,结果为:");
newPloy.printPoly();
}
}
我们执行上面的main()方法进行测试,果然2个多项式相加的结果是正确的。
总结:
其实很多算法题目,如果能找到合适的数据结构作为切入点之后,就不难了,当然这个需要经验的积累,还有需要多编程,像我现在经常写应用代码,算法这块疏忽了,所以写起来还是有点吃力的。
转载于:https://blog.51cto.com/supercharles888/1349036