问题描述
给两个多项式
例如
p1: 3x^3+2x^2+x+1
p2: x^2+x+1
给出p1和p2的加减乘除四则运算的结果
前要知识
List类、Set类、Map和HashMap
算法描述
对于多项式来说,一个多项式可以分成多个单元相加(减),(3x^3)+(2x^2)+(x)+(1)
对于每个单元(3x^3),(2x^2),(x)和(1)
我们可以用List结构来存储,而对于符号位+,+,+
同样可以用List结构存储。而对于整个多项式,可以用一个类进行表达。
当然,对于整体性来说,我们希望看到的是每一个自变量的指数和系数存储在一个数据结构中,因此引入含有Key主键的HashMap存储指数和系数。key值为指数,value值为系数。
//类Polynomial 的基本信息
public static class Polynomial {
List<Character> symbolList = new LinkedList<>(); //用于记录 + - 符号
List<String> specPolynomial = new LinkedList<>(); //用于记录分割多项式后的部分
Map<Integer, Integer> powerAndCoefficient = new HashMap<>(); //power幂 coefficient系数 hashmap存储
}
具体描述
1.构造函数
因为我们输入的是String字符串,为了方便起见,需要将String字符串构造为Polynomial类型,代码如下:
Polynomial(String string) { //多项式的构造函数
int left = 0, right = 0;
while (left < string.length() - 1 && right < string.length()) { //当左边到达最后一位 或 右边超出string位数时结束循环
if (string.charAt(right) == '+' || string.charAt(right) == '-') { //如果是加号或减号 前面left到right就是分割后的部分 right位置就是符号位
specPolynomial.add(string.substring(left, right)); //将分割后的部分加入到specPolynomial 列表中
left = right + 1;
symbolList.add(string.charAt(right)); //将符号加入symbol 列表中
}
right++; //继续循环
}
specPolynomial.add(string.substring(left)); //将最后一段加入specPolynomial 列表中
for (int j = 0; j < specPolynomial.size(); j++) { //遍历specPolynomial 取出每一个元素
String temp = specPolynomial.get(j);
char symbol = '+'; //定义一个symbol
if (j > 0)
symbol = symbolList.get(j - 1); //symbol的值为symbolList列表中的前一位
int mul = 1;
if (symbol == '+') //如果symbol为正号 则mul为1 即为原值
mul = 1;
else //如果symbol为负号 则mul为-1 即为相反值
mul = -1;
boolean notHasX = true; //判定有无x
for (int i = 0; i < temp.length(); i++) {
if (temp.charAt(i) == 'x') { //如果查询到x notHasX置为否
notHasX = false;
break;
}
}
if (notHasX) { //当没有x时,即常系数
powerAndCoefficient.put(0, Integer.valueOf(temp) * mul);
} else {
int powerLocation = 0;//定义power符号的位置
boolean flag = false; //找到^字符
while (powerLocation < temp.length()) { //遍历temp字符串
if (temp.charAt(powerLocation) == '^') { //如果找到^符号 flag置为true 并跳出循环
flag = true;
break;
} else {
powerLocation++; //如果还没找到 则向下移一位
}
}
if (flag) {//有^符号
if (temp.charAt(0) != 'x') //如果temp 的第一个字母不是x 即有不为1的系数
powerAndCoefficient.put(Integer.valueOf(temp.substring(powerLocation + 1)), Integer.valueOf(temp.substring(0, powerLocation - 1)) * mul);
else //如果temp的第一个字母是x 即系数为1
powerAndCoefficient.put(Integer.valueOf(temp.substring(powerLocation + 1)), mul);
} else {//没有^符号 x的一次项
if (temp.substring(0, powerLocation - 1).equals(""))
//没有系数 即为系数为1
powerAndCoefficient.put(1, mul);
else
//系数不为1
powerAndCoefficient.put(1, Integer.valueOf(temp.substring(0, powerLocation - 1)) * mul);
}
}
}
}
2.加法与减法
第一种情况:有相同的幂(map中存储的key值相同),将他们对应的value值相加,存入新的HashMap中。
第二种情况:该幂是两者中唯一的,将其key值和value值存入HashMap中。
代码如下:
public static String add(Polynomial p1, Polynomial p2) {
StringBuilder res = new StringBuilder(); //构建StringBuilding 函数 构造res变量
boolean flag = false;
Map<Integer, Integer> map = new HashMap<>();
for (int i = 0; i <= 10; i++) { //假设最高幂为10
if (p1.powerAndCoefficient.get(i) == null && p2.powerAndCoefficient.get(i) != null) { //如果p1没有找到幂值而在p2中找到幂值
map.put(i, p2.powerAndCoefficient.get(i)); //在hashmap中加入key 和 value
} else if (p1.powerAndCoefficient.get(i) != null && p2.powerAndCoefficient.get(i) == null) {//如果p1找到幂值而在p2中没有找到幂值
map.put(i, p1.powerAndCoefficient.get(i));
} else if (p1.powerAndCoefficient.get(i) == null && p2.powerAndCoefficient.get(i) == null) //如果都没有 直接跳过
continue;
else { //如果都有 两个值相加
map.put(i, p1.powerAndCoefficient.get(i) + p2.powerAndCoefficient.get(i));
}
}
Set<Integer> set = map.keySet(); //设置Set集合 把map中的key值放到set集合中
Object[] array; //将set放到object类数组中
array = set.toArray();
res = resCalculate(map, set, array, flag, res);//计算res值
if (res.length() == 0) //如果res的长度为0 说明值就是0
res.append("0");
return res.toString();
}
减法算法与加法算法相同,代码如下:
public static String sub(Polynomial p1, Polynomial p2) {
StringBuilder res = new StringBuilder();
boolean flag = false;
Map<Integer, Integer> map = new HashMap<>();
for (int i = 0; i <= 10; i++) {
if (p1.powerAndCoefficient.get(i) == null && p2.powerAndCoefficient.get(i) != null) {
map.put(i, p2.powerAndCoefficient.get(i));
} else if (p1.powerAndCoefficient.get(i) != null && p2.powerAndCoefficient.get(i) == null) {
map.put(i, p1.powerAndCoefficient.get(i));
} else if (p1.powerAndCoefficient.get(i) == null && p2.powerAndCoefficient.get(i) == null)
continue;
else {
map.put(i, p1.powerAndCoefficient.get(i) - p2.powerAndCoefficient.get(i));
}
}
Set<Integer> set = map.keySet();
Object[] array;
array = set.toArray();
res = resCalculate(map, set, array, flag, res);
if (res.length() == 0)
res.append("0");
return res.toString();
}
3.乘法
多项式的乘法法则是多项式1中的每一项与多项式2中的每一项相乘,结果再相加。因此通过两个循环得出新的key值和value值。但是如果对于已存在的键值,每一次加入一个相同的键值,会造成键值重复,使结果为最新输入的键值和数值。因此每一次 put 时,要加上上一次的value值。
代码如下:
public static Map<Integer, Integer> multiplyTwoPowerAndCoefficient(Map<Integer, Integer> pac1, Map<Integer, Integer> pac2) {
Map<Integer, Integer> map = new HashMap<>();
Set<Integer> set1 = pac1.keySet(); Set<Integer> set2 = pac2.keySet();
Object object1[] = set1.toArray(); Object object2[] = set2.toArray();
for (int i = 0; i < object1.length; i++) {
for (int j = 0; j < object2.length; j++) { //依次遍历两个object集合
if (map.get((int) object1[i] + (int) object2[j]) == null) //如果没有指数相加结果的值存在
map.put((int) object1[i] + (int) object2[j], pac1.get(object1[i]) * pac2.get(object2[j])); //创建一个新的key
else { //如果存在指数相加结果 更新该key值的value value等于循环该次结果的值加上以前存储的该key对应value值
map.put((int) object1[i] + (int) object2[j], map.get((int) object1[i] + (int) object2[j]) + ((int) pac1.get(object1[i]) * pac2.get(object2[j])));
}
}
}
return map;
}
public static String multiply(Polynomial p1, Polynomial p2) {
Map<Integer, Integer> map = new HashMap<>();
map = multiplyTwoPowerAndCoefficient(p1.powerAndCoefficient, p2.powerAndCoefficient); //输入map的值
Set<Integer> set = map.keySet();
Object array[] = set.toArray();
boolean flag = false;
StringBuilder res = new StringBuilder();
res = resCalculate(map, set, array, flag, res);
if (res.length() == 0) res.append("0");
return res.toString();
}
4.除法
除法应该是最难的一步,在我们人类的思维中,小学就学过,除法的分母分子可以因式分解,再通过约分得到最简式,可是在我的计算机能力范围内,这时不允许的。因此我想了一个投机取巧的办法,直接打“/”号,但是又写了一种情况来解决能够整除的多项式,代码如下:
public static boolean judgeComplitedDivide(Map<Integer, Integer> p1, Map<Integer, Integer> p2) {
//判断可不可以被整除
if (p1.size() != p2.size()) //如果p1和p2的长度不一样 直接返回false
return false;
else {
Set<Integer> set1 = p1.keySet();
Set<Integer> set2 = p2.keySet();
Object object1[]=set1.toArray();
Object object2[]=set2.toArray();
float temp[]=new float[object1.length];
for(int i=0;i<object1.length;i++){ //由于set集合里的数是顺序递增排列 所以只考虑对应位置的值是否相同即可得出结果
if(object1[i]!=object2[i]){ //对应的key值不同
return false;
}else{ //对应的key值相同 存入数组中
temp[i]=p1.get(object1[i])/p2.get(object2[i]);
}
}
for(int i=1;i<temp.length;i++){ //遍历这个数组 如果有不同的元素 直接返回false
if(temp[i]!=temp[i-1])
return false;
}
divideCoedfficient=temp[0]; //将全局变量divideCoedfficient设为temp[0] 随后返回true
return true;
}
}
public static String divide(Polynomial p1, Polynomial p2,String s1,String s2) {
boolean isComplitedlyDivided = false;
isComplitedlyDivided=judgeComplitedDivide(p1.powerAndCoefficient, p2.powerAndCoefficient);
StringBuilder res = new StringBuilder();
if (!isComplitedlyDivided) { //如果不能整除 直接输出
res.append("(").append(s1).append(")/(").append(s2).append(")");
} else { //如果可以整除 直接输出divideCoedfficient
res.append(divideCoedfficient);
}
return res.toString();
}
5.输出map中的结果
遍历每一个key值,得到相对应的value值,按照格式进行输出即可
代码如下:
public static StringBuilder resCalculate(Map<Integer, Integer> map, Set<Integer> set, Object[] array, boolean flag, StringBuilder res) {
for (Integer i = 0; i < set.size(); i++) { //array[i]是指数
if (map.get(array[i]) == 0) //如果key值对应的value值为0 直接跳过
;
else if ((Integer) array[i]== 0) { //如果指数为0 常数项
if (!flag) { //第一项
flag = true;
res.append(map.get((Integer) array[i]));
} else { //非第一项
if (map.get((Integer) array[i]) > 0) //如果这个数大于0
res.append("+").append(map.get((Integer) array[i]));
else //这个数小于0
res.append(map.get((Integer) array[i]));
}
} else if ((Integer) array[i] == 1) { //如果指数为1
if (!flag) {
flag = true;
res.append(map.get((Integer) array[i])).append("x");
} else {
if (map.get((Integer) array[i]) == 1) //系数为1
res.append("+x");
else if (map.get(i) > 0) //系数不为1
res.append("+").append(map.get((Integer) array[i])).append("x");
else //系数小于0
res.append(map.get((Integer) array[i])).append("x");
}
} else { //如果指数不为0或1
if (!flag) {
flag = true;
res.append(map.get((Integer) array[i])).append("x^").append((Integer) array[i]);
} else {
if (map.get((Integer) array[i]) == 1)
res.append("+x^").append((Integer) array[i]);
else if (map.get((Integer) array[i]) > 0) //如果系数大于0
res.append("+").append(map.get((Integer) array[i])).append("x^").append((Integer) array[i]);
else
res.append(map.get((Integer) array[i])).append("x^").append((Integer) array[i]);
}
}
}
return res;
}
输出结果
已知问题
1.除法问题
2.部分情况会出现崩溃
3.输出结果的时候会从幂低级到幂高级输出 其实我会改,但是我懒
4.······
本人不才,如有错误,烦请各路大佬斧正!!!