import org.slf4j.Logger;
import org.slf4j.LoggerFactory;import java.util.*;public class Ebbinghaus {private static final Logger log = LoggerFactory.getLogger(Ebbinghaus.class);private List<LearnRow> schemeTable = new ArrayList<>();//生成的计划表private HashMap<Integer, LearnRow> DayToTabMap = new HashMap<>();//映射计划表中行元素信息 <天数,映射对应的计划表Row>private LinkedHashMap<Integer, Integer> learnStateMap = new LinkedHashMap<>();//学习情况表 <当日计划表中是第几天,当日学习单词量>private int sumWordSize;//总单词量private int needLearnDay;//还需要学习的天数private int learnedWordCount = 0;//学习过的单词数private int nowDay = 1;//当前天数class LearnRow {private int toLearnIndex;//需要学习哪天的单词列表的索引private List<Integer> toReviewList;public LearnRow() {}public LearnRow(int toLearnIndex, List<Integer> toReviewList) {this.toLearnIndex = toLearnIndex;this.toReviewList = toReviewList;}@Overridepublic String toString() {return "LearnRow{" +"toLearnIndex=" + toLearnIndex +", toReviewList=" + toReviewList +'}';}public int getToLearnIndex() {return toLearnIndex;}public void setToLearnIndex(int toLearnIndex) {this.toLearnIndex = toLearnIndex;}public List<Integer> getToReviewList() {return toReviewList;}public void setToReviewList(List<Integer> toReviewList) {this.toReviewList = toReviewList;}}public Ebbinghaus(int sumWordSize) {this.sumWordSize = sumWordSize;}public List<LearnRow> getSchemeTable() {return schemeTable;}public HashMap<Integer, LearnRow> getDayToTabMap() {return DayToTabMap;}public LinkedHashMap<Integer, Integer> getLearnStateMap() {return learnStateMap;}/*** 添加一条学习记录信息,会导致更新*/public void pushLearnRecord(int dayToLearnWordSize) {learnStateMap.put(new Integer(nowDay++), new Integer(dayToLearnWordSize));this.learnedWordCount += dayToLearnWordSize;if (dayToLearnWordSize != 0) {this.needLearnDay = (this.sumWordSize - this.learnedWordCount) / dayToLearnWordSize;}//更新计划表此天后的计划if (learnStateMap.size() == 1) {//说明刚插入的是第一条记录,初始化计划表log.debug("初始化计划表");if (dayToLearnWordSize == 0) {//如果第一天计划0个单词,则返回错误throw new RuntimeException("第一天计划单词数不能为0");}//循环处理生成每一天的计划 每天学习当天的list 同时还要复习 1 天前的,2天前的 4天前的 7 天前的 15 天前的单词(如果存在的话)for (int i = 1; i <= this.needLearnDay + 1 + 15; i++) {if (i == 1) {//如果为第一天,生成RowArrayList<Integer> learnIndexList = new ArrayList<Integer>();LearnRow learnRow = new LearnRow(i, learnIndexList);schemeTable.add(learnRow);DayToTabMap.put(new Integer(i), learnRow);} else {//非第一天,生成RowArrayList<Integer> learnIndexList = new ArrayList<Integer>();//遍历前面每一个计划表Row,如果存在toLearnIndex不为0 的 1 天前的,2天前的 4天前的 7 天前的 15 天前的index 则加入learnIndexListfor (int j = 1; j < i; j++) {if (DayToTabMap.get(new Integer(j)).toLearnIndex != 0 && ((i - j) == 1 || (i - j) == 2 || (i - j) == 4 || (i - j) == 7 || (i - j) == 15)) {learnIndexList.add(new Integer(j));}}LearnRow learnRow = new LearnRow(i > (this.needLearnDay + 1) ? 0 : i % (this.needLearnDay + 2), learnIndexList);schemeTable.add(learnRow);DayToTabMap.put(new Integer(i), learnRow);}}log.debug(schemeTable.toString());} else {//新增的记录,判断学习单词数是否与前面一个的相同(前一天为nowDay - 2),如果不同则修改插入的该天后面的计划表 否则不变if (dayToLearnWordSize != learnStateMap.get(new Integer(nowDay - 2)).intValue()) {log.debug("需要重构表");//移除后面的表Row,重新插入新的重建Rowint size = schemeTable.size();for (int i = (this.nowDay - 1); i <= size; i++) {schemeTable.remove(this.nowDay - 2);}for (int i = (this.nowDay - 1); i <= size; i++) {DayToTabMap.remove(new Integer(i));}//重建删除项if (dayToLearnWordSize == 0) {//当插入一条学习计划为0的时候,重建删除项//需要先添加一条空的,再重建后续for (int i = this.nowDay - 1; i < this.needLearnDay + this.nowDay + 15; i++) {//处理重建数据的第一条数据,也就是当天的if (i == (this.nowDay - 1)) {ArrayList<Integer> learnIndexList = new ArrayList<Integer>();LearnRow learnRow = new LearnRow(0, learnIndexList);schemeTable.add(learnRow);DayToTabMap.put(new Integer(i), learnRow);} else {//生成RowArrayList<Integer> learnIndexList = new ArrayList<Integer>();//遍历前面每一个计划表Row,如果存在toLearnIndex不为0 的 1 天前的,2天前的 4天前的 7 天前的 15 天前的index 则加入learnIndexListfor (int j = 1; j < i; j++) {if (DayToTabMap.get(new Integer(j)).toLearnIndex != 0 && ((i - j) == 1 || (i - j) == 2 || (i - j) == 4 || (i - j) == 7 || (i - j) == 15)) {learnIndexList.add(new Integer(j));}}LearnRow learnRow = new LearnRow(i > (this.needLearnDay + this.nowDay - 1) ? 0 : i % (this.needLearnDay + this.nowDay), learnIndexList);schemeTable.add(learnRow);DayToTabMap.put(new Integer(i), learnRow);}}} else {for (int i = this.nowDay - 1; i < this.needLearnDay + this.nowDay + 15; i++) {//生成RowArrayList<Integer> learnIndexList = new ArrayList<Integer>();//遍历前面每一个计划表Row,如果存在toLearnIndex不为0 的 1 天前的,2天前的 4天前的 7 天前的 15 天前的index 则加入learnIndexListfor (int j = 1; j < i; j++) {if (DayToTabMap.get(new Integer(j)).toLearnIndex != 0 && ((i - j) == 1 || (i - j) == 2 || (i - j) == 4 || (i - j) == 7 || (i - j) == 15)) {learnIndexList.add(new Integer(j));}}LearnRow learnRow = new LearnRow(i > (this.needLearnDay + this.nowDay - 1) ? 0 : i % (this.needLearnDay + this.nowDay), learnIndexList);schemeTable.add(learnRow);DayToTabMap.put(new Integer(i), learnRow);}}} else {log.debug("不需要重构表");}log.debug(schemeTable.toString());}}public static void main(String[] args) {Ebbinghaus ebbinghaus = new Ebbinghaus(5612);ebbinghaus.pushLearnRecord(200);ebbinghaus.pushLearnRecord(200);//验证新增学习计划单词数改变ebbinghaus.pushLearnRecord(300);ebbinghaus.pushLearnRecord(300);//验证新增学习计划单词数改变 当天没进行学习,验证动态生成计划表ebbinghaus.pushLearnRecord(0);ebbinghaus.pushLearnRecord(300);ebbinghaus.pushLearnRecord(100);}
}
最近自己鼓捣的小玩意,模仿墨墨背单词APP中的的艾宾浩斯算法动态生成复习策略类似网上这种样式的计划表(不过我实现的没有打印出来只是基于内存中的)
不确定有什么Bug没,自己测试的比较简单