第三次总结
一、前言:
到目前为止,我们共进行了pta八次大作业和一次期中考试,其中前三次大作业在第一次的blog中已经做了分析,四、五次大作业在第二次的blog中做出了分析,那么这次blog就对后三次大作业进行分析,后三次大作业难度适中,是循序渐进的,其中我将会对第六、七、八三次大作业中电信计费系列进行分析,这三道题目难度适中,但不是难在语法上,而是难在算法,需要有扎实的数学和好的逻辑思维能力才能对其有好的处理,也需要对正则表达式有良好的掌握。
二、设计与分析:
①题目集6(6-1) 电信计费系列1-座机计费
这道题目比较复杂,有以下功能需求:
实现一个简单的电信计费程序:
假设南昌市电信分公司针对市内座机用户采用的计费方式:
月租20元,接电话免费,市内拨打电话0.1元/分钟,省内长途0.3元/分钟,国内长途拨打0.6元/分钟。不足一分钟按一分钟计。
南昌市的区号:0791,江西省内各地市区号包括:0790~0799以及0701。
源码如下:
import java.text.ParseException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Scanner;
import java.util.Comparator;
import java.text.SimpleDateFormat;
import java.util.Date;
abstract class CallChargeRule extends ChargeRule{
public double calCost(ArrayList<CallRecord> callRecords) {
return 0;
}
}
class CallRecord extends CommunicationRecord{
Date startTime;
Date endTime;
String callingAddressAreaCode;
String answerAddressAreaCode;
SimpleDateFormat a = new SimpleDateFormat ("yyyy.MM.dd HH:mm:ss");
public CallRecord() {
super();
// TODO 自动生成的构造函数存根
}
public Date getStartTime() {
return startTime;
}
public void setStartTime(String startTime) {
try {
this.startTime = a.parse(startTime);
} catch (ParseException e) {
// TODO 自动生成的 catch 块
e.printStackTrace();
}
}
public Date getEndTime() {
return endTime;
}
public void setEndTime(String endTime) {
try {
this.endTime = a.parse(endTime);
} catch (ParseException e) {
// TODO 自动生成的 catch 块
e.printStackTrace();
}
}
public String getCallingAddressAreaCode() {
return callingAddressAreaCode;
}
public void setCallingAddressAreaCode(String callingAddressAreaCode) {
if(callingAddressAreaCode.matches("0791"))
this.callingAddressAreaCode = "NC";
else if(callingAddressAreaCode.matches("(079[0-9]|0701)")){
this.callingAddressAreaCode = "JX";
}else {
this.callingAddressAreaCode = "ZG";
}
}
public String getAnswerAddressAreaCode() {
return answerAddressAreaCode;
}
public void setAnswerAddressAreaCode(String answerAddressAreaCode) {
if(answerAddressAreaCode.matches("0791"))
this.answerAddressAreaCode = "NC";
else if(answerAddressAreaCode.matches("(079[0-9]|0701)")){
this.answerAddressAreaCode = "JX";
}else {
this.answerAddressAreaCode = "ZG";
}
}
}
abstract class ChargeMode {
ArrayList<ChargeRule> chargeRules = new ArrayList<ChargeRule>();
public ArrayList<ChargeRule> getChargeRules() {
return chargeRules;
}
public void setChargeRules(ArrayList<ChargeRule> chargeRules) {
this.chargeRules = chargeRules;
}
public double calCost(UserRecords userRecords) {
return 0;
}
public double getMonthlyRent() {
return 0;
}
}
abstract class ChargeRule {
}
abstract class CommunicationRecord {
String callingNumber;
String answerNumber;
public String getCallingNumber() {
return callingNumber;
}
public void setCallingNumber(String callingNumber) {
this.callingNumber = callingNumber;
}
public String getAnswerNumber() {
return answerNumber;
}
public void setAnswerNumber(String answerNumber) {
this.answerNumber = answerNumber;
}
}
class LandlinePhoneCharging extends ChargeMode{
double monthlyRent = 20;
public LandlinePhoneCharging() {
super();
}
@Override
public double calCost(UserRecords userRecords) {
LandPhoneInCityRule a = new LandPhoneInCityRule();
LandPhoneInlandRule b = new LandPhoneInlandRule();
LandPhoneInProvinceRule c = new LandPhoneInProvinceRule();
return a.calCost(userRecords.getCallingInCityRecords())+b.calCost(userRecords.getCallingInLandRecords())+c.calCost(userRecords.getCallingInProvinceRecords())+20;
}
@Override
public double getMonthlyRent() {
return monthlyRent;
}
}
class LandPhoneInCityRule extends CallChargeRule{
@Override
public double calCost(ArrayList<CallRecord> callRecords) {
double cost=0;
if(callRecords.size()==0) {
return 0;
}
for(int i=0;i<callRecords.size();i++) {
long a = (callRecords.get(i).endTime.getTime()-callRecords.get(i).startTime.getTime())/1000;
long b = a%60;
if(b==0&&
(callRecords.get(i).endTime.getTime()-callRecords.get(i).startTime.getTime())>0) {
cost = cost + (a/60)*0.1;
}else {
cost = cost + ((a-b)/60+1)*0.1;
}
}
return cost;
}
}
class LandPhoneInlandRule extends CallChargeRule{
@Override
public double calCost(ArrayList<CallRecord> callRecords) {
double cost=0;
if(callRecords.size()==0) {
return 0;
}
for(int i=0;i<callRecords.size();i++) {
long a = (callRecords.get(i).endTime.getTime()-callRecords.get(i).startTime.getTime())/1000;
long b = a%60;
if(b==0&&
(callRecords.get(i).endTime.getTime()-callRecords.get(i).startTime.getTime())>0) {
cost = cost + (a/60)*0.6;
}else {
cost = cost + ((a-b)/60+1)*0.6;
}
}
return cost;
}
}
class LandPhoneInProvinceRule extends CallChargeRule{
@Override
public double calCost(ArrayList<CallRecord> callRecords) {
double cost=0;
if(callRecords.size()==0) {
return 0;
}
for(int i=0;i<callRecords.size();i++) {
long a = (callRecords.get(i).endTime.getTime()-callRecords.get(i).startTime.getTime())/1000;
long b = a%60;
if(b==0&&
(callRecords.get(i).endTime.getTime()-callRecords.get(i).startTime.getTime())>0) {
cost = cost + (a/60)*0.3;
}else {
cost = cost + ((a-b)/60+1)*0.3;
}
}
return cost;
}
}
public class Main {
public static void main(String[] args) {
// TODO 自动生成的方法存根
Scanner in = new Scanner(System.in);
ArrayList<User> x = new ArrayList<User>();
ArrayList<CallRecord> z = new ArrayList<CallRecord>();
LandlinePhoneCharging cost = new LandlinePhoneCharging();
while(true) {
String a = in.nextLine();
if(a.equals("end")) {
break;
}
if(a.length()==0) {
continue;
}
if(jug(a)==2){
if(z.size()==0){
User b = new User();
String[] strarray=a.split(" ",2);
b.setNumber(strarray[0].substring(2));
x.add(b);
for (int i = 0; i < x.size(); i++) {
for (int j = 0; j < x.size(); j++) {
if (i != j && x.get(i).number.equals(x.get(j).number)) {
x.remove(x.get(j));
}
}
}
}
}
else if(jug(a)==1) {
CallRecord b = new CallRecord();
String[] strarray=a.split(" ",6);
b.setCallingAddressAreaCode(strarray[0].substring(2,6));
b.setAnswerAddressAreaCode(strarray[1].substring(0, 4));
b.setCallingNumber(strarray[0].substring(2));
b.setAnswerNumber(strarray[1]);
b.setStartTime(strarray[2].concat(" ").concat(strarray[3]));
b.setEndTime(strarray[4].concat(" ").concat(strarray[5]));
z.add(b);
}
else{
continue;
}
}
for(int i=0;i<x.size();i++) {
for(int j =0;j<z.size();j++) {
if(z.get(j).answerAddressAreaCode.equals("NC")) {
if(x.get(i).number.equals(z.get(j).callingNumber))
x.get(i).userRecords.addCallingInCityRecords(z.get(j));
}else if(z.get(j).answerAddressAreaCode.equals("JX")) {
if(x.get(i).number.equals(z.get(j).callingNumber))
x.get(i).userRecords.addCallingInProvinceRecords(z.get(j));
}else if(z.get(j).answerAddressAreaCode.equals("ZG")){
if(x.get(i).number.equals(z.get(j).callingNumber))
x.get(i).userRecords.addCallingInLandRecords(z.get(j));
}
}
}
Collections.sort(x, new MyComparatorNumber());
for(int i =0;i<x.size();i++) {
x.get(i).balance = 100- cost.calCost(x.get(i).userRecords);
double q = 80-x.get(i).balance;
if(i==x.size()-1) {
System.out.print(x.get(i).number+" "+String.format("%.1f", q)+" "+String.format("%.1f", x.get(i).balance));
}
else {
System.out.println(x.get(i).number+" "+String.format("%.1f", q)+" "+String.format("%.1f", x.get(i).balance));
}
}
}
static class MyComparatorNumber implements Comparator<User>{
@Override
public int compare(User u1, User u2) {
double p = Double.parseDouble(u1.number);
double q = Double.parseDouble(u2.number);
return (int)(p-q);
}
}
public static int jug(String a) {
String parrten1 = "t-0791[0-9]{7,8} [0-9]{3,4}[0-9]{7,8} [1-9]\\d{3}.([1-9]|1[0-2]).([1-9]|[1-2][0-9]|3[0-1])\\s(20|21|22|23|[0-1]\\d):[0-5]\\d:[0-5]\\d [1-9]\\d{3}.([1-9]|1[0-2]).([1-9]|[1-2][0-9]|3[0-1])\\s(20|21|22|23|[0-1]\\d):[0-5]\\d:[0-5]\\d";
String parrten2 = "u-0791[0-9]{7,8}[ ]0";
if(a.matches(parrten1)) {
return 1;
}
if(a.matches(parrten2)) {
return 2;
}
return 0;
}
}
class MessageRecord {
String message;
public String getMessage() {
return message;
}
public void setMessage(String message) {
this.message = message;
}
}
class User {
UserRecords userRecords = new UserRecords();
double balance = 100;
ChargeMode ChargeMode;
String number;
public User() {
}
public double calBalance() {
return 100-calCost();
}
public double calCost() {
return 0;
}
public UserRecords getUserRecords() {
return userRecords;
}
public void setUserRecords(UserRecords userRecords) {
this.userRecords = userRecords;
}
public double getBalance() {
return balance;
}
public ChargeMode getChargeMode() {
return ChargeMode;
}
public void setChargeMode(ChargeMode chargeMode) {
ChargeMode = chargeMode;
}
public String getNumber() {
return number;
}
public void setNumber(String number) {
this.number = number;
}
}
class UserRecords {
ArrayList<CallRecord> callingInCityRecords = new ArrayList<CallRecord>();
ArrayList<CallRecord> callingInProvinceRecords = new ArrayList<CallRecord>();
ArrayList<CallRecord> callingInLandRecords = new ArrayList<CallRecord>();
ArrayList<CallRecord> answerInCityRecords = new ArrayList<CallRecord>();
ArrayList<CallRecord> answerInProvinceRecords = new ArrayList<CallRecord>();
ArrayList<CallRecord> answerInLandRecords = new ArrayList<CallRecord>();
ArrayList<MessageRecord> sendMessageRecords = new ArrayList<MessageRecord>();
ArrayList<MessageRecord> reciveMessageRecords = new ArrayList<MessageRecord>();
public void addCallingInCityRecords(CallRecord callRecord) {
callingInCityRecords.add(callRecord);
}
public void addCallingInProvinceRecords(CallRecord callRecord) {
callingInProvinceRecords.add(callRecord);
}
public void addCallingInLandRecords(CallRecord callRecord) {
callingInLandRecords.add(callRecord);
}
public void addAnswerInInCityRecords(CallRecord answerRecord) {
answerInCityRecords.add(answerRecord);
}
public void addAnswerInInProvinceRecords(CallRecord answerRecord) {
answerInProvinceRecords.add(answerRecord);
}
public void addAnswerInInLandRecords(CallRecord answerRecord) {
answerInLandRecords.add(answerRecord);
}
public void addSendMessageRecords(MessageRecord sendMessageRecord) {
sendMessageRecords.add(sendMessageRecord);
}
public void addReciveMessageRecords(MessageRecord reciveMessageRecord) {
reciveMessageRecords.add(reciveMessageRecord);
}
public ArrayList<CallRecord> getCallingInCityRecords() {
return callingInCityRecords;
}
public ArrayList<CallRecord> getCallingInProvinceRecords() {
return callingInProvinceRecords;
}
public ArrayList<CallRecord> getCallingInLandRecords() {
return callingInLandRecords;
}
public ArrayList<CallRecord> getAnswerInCityRecords() {
return answerInCityRecords;
}
public ArrayList<CallRecord> getAnswerInProvinceRecords() {
return answerInProvinceRecords;
}
public ArrayList<CallRecord> getAnswerInLandRecords() {
return answerInLandRecords;
}
public ArrayList<MessageRecord> getSendMessageRecords() {
return sendMessageRecords;
}
public ArrayList<MessageRecord> getReciveMessageRecords() {
return reciveMessageRecords;
}
}
SourceMonitor的生成报表如下:



总的来说,题目功能的实现需要各个类巧妙的配合,以及运用好父类子类之间的关系,减少类的数量。由于前几次大作业的分数惨状,为了降低我们的学习压力,老师贴心地为我们设计好了类图,里面有很好的方法,大大降低了我们做题目的难度。这道题功能简单来说就是写一个程序,计算各个开户的座机用户的话费情况,座机号码除区号外由是7-8位数字组成。座机市内拨打电话0.1元/分钟,省内长途0.3元/分钟,国内长途拨打0.6元/分钟。不足一分钟按一分钟计。且座机接听电话不计费。用用户记录类中的各种容器来存放各个用户的通话记录,例如座机在市内打座机就放到对应的容器内,再在计算话费的类中遍历容器来计算各部分话费,最后进行相加即得总话费。最后需要对用户容器进行排序(座机号码从小到大排序),我用了一个比较接口来实现排序。
②题目集7:(7-1) 电信计费系列2-手机+座机计费
这道题目难度较第一次明显升级,共有功能需求:
实现南昌市电信分公司的计费程序,假设该公司针对手机和座机用户分别采取了两种计费方案,分别如下:
1、针对市内座机用户采用的计费方式(与电信计费系列1内容相同):
月租20元,接电话免费,市内拨打电话0.1元/分钟,省内长途0.3元/分钟,国内长途拨打0.6元/分钟。不足一分钟按一分钟计。
假设本市的区号:0791,江西省内各地市区号包括:0790~0799以及0701。
2、针对手机用户采用实时计费方式:
月租15元,市内省内接电话均免费,市内拨打市内电话0.1元/分钟,市内拨打省内电话0.2元/分钟,市内拨打省外电话0.3元/分钟,省内漫游打电话0.3元/分钟,省外漫游接听0.3元/分钟,省外漫游拨打0.6元/分钟;
源码因为太长就不放了。
SourceMonitor的生成报表如下:


这道题目是第一道题目的进阶版,在电信计费系列中新增了一个新的用户类型——手机。手机使得题目难度有较大增加,需要考虑的情况变多。座机用户接听电话是不收费的,而手机用户在江西省外接听电话是需要收费的。因此,对于每一条通讯信息的处理需要更加的谨慎,不只是要考虑拨打电话,还要考虑手机在省外接听电话的情况。为了实现这些功能,我新增了处理手机拨打和接听电话的类。如下:

有了这些类,我能较为清晰的处理好每一种情况。这道题还需要额外的写出多个正则表达式来应对多种通话记录的情况。
③题目集8:(8-1) 电信计费系列3-手机短信计费
实现一个简单的电信计费程序,针对手机的短信采用如下计费方式:
1、接收短信免费,发送短信0.1元/条,超过3条0.2元/条,超过5条0.3元/条。
2、如果一次发送短信的字符数量超过10个,按每10个字符一条短信进行计算。
源码如下:
import java.util.ArrayList;
import java.util.Collections;
import java.util.Scanner;
import java.util.Comparator;
abstract class ChargeMode {
ArrayList<ChargeRule> chargeRules = new ArrayList<ChargeRule>();
public ArrayList<ChargeRule> getChargeRules() {
return chargeRules;
}
public void setChargeRules(ArrayList<ChargeRule> chargeRules) {
this.chargeRules = chargeRules;
}
public double calCost(UserRecords userRecords) {
return 0;
}
public double getMonthlyRent() {
return 0;
}
}
abstract class ChargeRule {
}
abstract class CommunicationRecord {
String callingNumber;
String answerNumber;
public String getCallingNumber() {
return callingNumber;
}
public void setCallingNumber(String callingNumber) {
this.callingNumber = callingNumber;
}
public String getAnswerNumber() {
return answerNumber;
}
public void setAnswerNumber(String answerNumber) {
this.answerNumber = answerNumber;
}
}
public class Main {
public static void main(String[] args) {
// TODO 自动生成的方法存根
Scanner in = new Scanner(System.in);
ArrayList<User> x = new ArrayList<User>();
ArrayList<MessageRecord> z = new ArrayList<MessageRecord>();
MessageCharging cost = new MessageCharging();
while(true) {
String a = in.nextLine();
if(a.equals("end")) {
break;
}
if(jug(a)==1){
User b = new User();
String[] strarray=a.split(" ",2);
b.setNumber(strarray[0].substring(2));
b.setChargeMode(strarray[1]);
x.add(b);
for (int i = 0; i < x.size(); i++) {
for (int j = 0; j < x.size(); j++) {
if (i != j && x.get(i).number.equals(x.get(j).number)) {
x.remove(x.get(j));
}
}
}
}
else if(jug(a)==2) {
MessageRecord b = new MessageRecord();
String c = a.substring(2);
b.setCallingNumber(c.substring(0, 11));
b.setAnswerNumber(c.substring(12, 23));
b.setMessage(c.substring(24));
z.add(b);
for (int i = 0; i < x.size(); i++) {
for (int j = 0; j < x.size(); j++) {
if (i != j && x.get(i).number.equals(x.get(j).number)) {
x.remove(x.get(j));
}
}
}
}
}
for(int i=0;i<x.size();i++) {
for(int j=0;j<z.size();j++) {
if(x.get(i).number.equals(z.get(j).callingNumber)) {
if(x.get(i).number.equals(z.get(j).callingNumber)&&x.get(i).number.equals(z.get(j).answerNumber)) {
continue;
}
x.get(i).userRecords.addSendMessageRecords(z.get(j));
}
}
}
Collections.sort(x, new MyComparatorToUser());
for(int i =0;i<x.size();i++) {
x.get(i).balance = 100- cost.calCost(x.get(i).userRecords);
double q = 100-x.get(i).balance;
if(i==x.size()-1) {
System.out.print(x.get(i).number+" "+String.format("%.1f", q)+" "+String.format("%.1f", x.get(i).balance));
}
else {
System.out.println(x.get(i).number+" "+String.format("%.1f", q)+" "+String.format("%.1f", x.get(i).balance));
}
}
in.close();
}
static class MyComparatorToUser implements Comparator<User>{
@Override
public int compare(User u1, User u2) {
double p = Double.parseDouble(u1.number);
double q = Double.parseDouble(u2.number);
if(u1.number.charAt(0)=='0'&&u2.number.charAt(0)=='0') {
return (int)(p-q);
}
if(u1.number.charAt(0)=='0') {
p=0;
}
if(u2.number.charAt(0)=='0') {
q=0;
}
return (int)(p-q);
}
}
public static int jug(String a) {
String parrten1 = "u-(13[0-9]|14[01456879]|15[0-35-9]|16[2567]|17[0-8]|18[0-9]|19[0-35-9])\\d{8} 3";//开户
String parrten2 = "t-[0-9]{3,4}[0-9]{7,8} (13[0-9]|14[01456879]|15[0-35-9]|16[2567]|17[0-8]|18[0-9]|19[0-35-9])\\d{8} [0-9]{3,4} [1-9]\\d{3}.([1-9]|1[0-2]).([1-9]|[1-2][0-9]|3[0-1])\\s(20|21|22|23|[0-1]\\d):[0-5]\\d:[0-5]\\d [1-9]\\d{3}.([1-9]|1[0-2]).([1-9]|[1-2][0-9]|3[0-1])\\s(20|21|22|23|[0-1]\\d):[0-5]\\d:[0-5]\\d";
if(a.matches(parrten1)) {
return 1;
}else if (a.matches("m-1[0-9]{10}[ ]1[0-9]{10}[ ](([0-9]+|[a-z]+|[A-Z]+)|(,|[.])|[ ])+")) {
return 2;
}
return 0;
}
}
class MessageCharging extends ChargeMode{
public MessageCharging() {
super();
}
@Override
public double calCost(UserRecords userRecords) {
double cost=0;
int MessageNumbers=0;
for(int i=0;i<userRecords.sendMessageRecords.size();i++) {
int length = userRecords.sendMessageRecords.get(i).message.length();
if(length<=10||length%10==0) {
if(length<=10)
MessageNumbers=MessageNumbers+1;
else
MessageNumbers=MessageNumbers+length/10;
}else{
MessageNumbers = MessageNumbers+length/10+1;
}
}
if(MessageNumbers<=3) {
cost = MessageNumbers*0.1;
}else if(MessageNumbers<=5) {
cost = 0.3+(MessageNumbers-3)*0.2;
}else {
cost = 0.7+(MessageNumbers-5)*0.3;
}
return cost;
}
}
class MessageRecord extends CommunicationRecord{
String message;
public String getMessage() {
return message;
}
public void setMessage(String message) {
this.message = message;
}
}
class User {
UserRecords userRecords = new UserRecords();
double balance = 100;
String ChargeMode;
String number;
public User() {
}
public double calBalance() {
return 100-calCost();
}
public double calCost() {
return 0;
}
public UserRecords getUserRecords() {
return userRecords;
}
public void setUserRecords(UserRecords userRecords) {
this.userRecords = userRecords;
}
public double getBalance() {
return balance;
}
public void setChargeMode(String chargeMode) {
ChargeMode = chargeMode;
}
public String getNumber() {
return number;
}
public void setNumber(String number) {
this.number = number;
}
}
class UserRecords {
ArrayList<MessageRecord> sendMessageRecords = new ArrayList<MessageRecord>();
ArrayList<MessageRecord> reciveMessageRecords = new ArrayList<MessageRecord>();
public void addSendMessageRecords(MessageRecord sendMessageRecord) {
sendMessageRecords.add(sendMessageRecord);
}
public void addReciveMessageRecords(MessageRecord reciveMessageRecord) {
reciveMessageRecords.add(reciveMessageRecord);
}
public ArrayList<MessageRecord> getSendMessageRecords() {
return sendMessageRecords;
}
public ArrayList<MessageRecord> getReciveMessageRecords() {
return reciveMessageRecords;
}
}
SourceMonitor的生成报表如下:


电信计费第三次作业短信计费算是较为容易的一次,算是与前两次作业没有啥联系的一次,完全可以删除前两次作业的大部分代码来做本次作业。本次大作业的难点在于对短信信息内容的处理,需要限制其的格式,所以需要一个较为严谨的正则表达式。然后就是处理短信信息来计费,每十个字符算作一条短信,所以一个用户的每条记录不能单独来计费,需要算出短信条数的总和来计费。
三、踩坑心得
①计算短信费用时,刚开始是逐条计算,导致计算错误,后来把每条记录的短信条数综合,再进行计算,就解决问题了。
②使用容器时,删除其中一个元素时不会改变容器大小,如果需要用到容器的长度来作为判断依据,不要使用原容器来判断。
③容器中对象的排序,刚开始采用循环排序,发现太麻烦了,于是使用了comparable接口来帮助排序,使得排序简单了很多。
④字符串相等不要用==,而是要用equals。
四、改进建议
①算法不够简洁,需要更加简洁明了。
②逻辑不够清晰,无法很精准正确的抓住题意,需要加强。
③尽量减少对变量的重复计算
④if-else嵌套较多,需要减少
五、总结
①这几次作业相较于上次有明显的提高,类与类之间的关系更加清晰,逻辑更加完整。。
②学会了如何使用容器。
③在确定数组大小时尽量使用array,无法确定数组大小时才使用ArrayList。
④学会了抽象类的用法
⑤更加深入地懂得了类之间的分工合作


浙公网安备 33010602011771号