├── .gitignore ├── README.md ├── dispatching_algorithm.iml ├── img ├── FCFS.png ├── SCAN.png └── SSTF.png └── src └── wang └── relish └── dispatching ├── Main.java ├── algorithm ├── Executor.java ├── FCFS.java ├── SCAN.java └── SSTF.java ├── bean └── Task.java ├── common ├── Direct.java └── Type.java └── comparator └── ScanComparator.java /.gitignore: -------------------------------------------------------------------------------- 1 | out/ 2 | .idea/ 3 | src/wang/relish/dispatching/other/ -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ## 精读《电梯调度算法》 2 | 3 | 文章地址:https://mp.weixin.qq.com/s/h_jlf9EAbE9dg7WJdiHKbg 4 | 5 | ## 引言 6 | 7 | 大家一定经历过等电梯的烦恼,尤其是在赶时间的时候,则更为头疼。如果你是一名程序员的话, 你一定有在等电梯时盘算过如何对电梯调度进行优化。 8 | 9 | ## 常见调度算法简介 10 | 文章对各种算法的介绍还算细致, 具体介绍了如何针对不同的情况对电梯的调度算法进行优化,使其能更高效地运作,但并未给出相应的代码。笔者不才,愿对其介绍的几种较易理解的非实时调度算法进行Java代码实现,权当抛砖引玉之效。献丑献丑。 11 | 12 | ### 1.1 先来先服务算法(FCFS,FCFS-First Come First Serve) 13 | 14 | 根据乘客请求乘坐电梯的先后次序进行调度。 15 | 16 | **优点**: 17 | 18 | > 公平、简单,且每个乘客的请求都能依次地得到处理,不会出现某一乘客的请求长期得不到满足的情况。 19 | 20 | **缺点**: 21 | 22 | > 在载荷较大的情况下,这种算法的性能就会严重下降,甚至恶化。 23 | 24 | *(缺点)举个例子*: 电梯处于1楼, A乘客请求从10楼到1楼,B乘客请求从1楼到10楼, C乘客请求从9楼到1楼。根据FCFS算法,电梯会先满足A乘客的请求,再满足B乘客的请求,最后满足C乘客的请求。 25 | 26 | **代码**: 27 | 28 | ```Java 29 | /** 30 | * 一次任务请求 31 | * 32 | * @author relish 33 | * @since 2018/08/21 34 | */ 35 | public class Task { 36 | 37 | public String name; 38 | /** 39 | * 请求所在楼层 40 | */ 41 | public int from; 42 | /** 43 | * 请求去往楼层 44 | */ 45 | public int to; 46 | 47 | public Task(String name, int from, int to) { 48 | this.name = name; 49 | this.from = from; 50 | this.to = to; 51 | } 52 | 53 | public Direct getDirect() { 54 | return from - to > 0 ? Direct.DOWN : Direct.UP; 55 | } 56 | 57 | 58 | @Override 59 | public String toString() { 60 | return String.format("%s %d->%d", name, from, to); 61 | } 62 | } 63 | ``` 64 | 65 | ```Java 66 | /** 67 | * 运动方向 68 | */ 69 | public enum Direct { 70 | UP, 71 | DOWN 72 | } 73 | ``` 74 | 75 | ```Java 76 | public class FCFS { 77 | public static void exec(List taskList, int initPos) { 78 | System.out.println("1)先来先服务算法(FCFS):"); 79 | System.out.format("电梯当前位于第%s层, 对如下乘客进行服务:\n", initPos); 80 | for (Task task : taskList) { 81 | System.out.format("%d->%d ", task.from, task.to); 82 | } 83 | System.out.println("\n请求次序 服务乘客 电梯移动楼层数"); 84 | 85 | int totalTime = 0; 86 | int prev = initPos; 87 | for (int i = 0; i < taskList.size(); i++) { 88 | Task task = taskList.get(i); 89 | int abs = Math.abs(task.from - prev); 90 | totalTime += abs; 91 | int d = Math.abs(task.from - task.to); 92 | totalTime += d; 93 | prev = task.to; 94 | System.out.format(" %d %s:%2d->%2d %2d\n", i, task.name, task.from, task.to, abs + d); 95 | } 96 | System.out.println("总移动距离: " + totalTime); 97 | double ave = totalTime / 1.0 / taskList.size(); 98 | System.out.format("平均每次服务的距离: %.1f\n", ave); 99 | } 100 | } 101 | ``` 102 | 103 | **点评**:代码简单。任务执行只需按请求队列的顺序执行即可。 104 | 105 | ![FCFS](./img/FCFS.png) 106 | 107 | ### 1.2 最短寻找楼层时间优先算法(SSTF,Shortest Seek Time First) 108 | 109 | 此算法选择下一个服务对象的原则是最短寻找楼层的时间。 110 | **优点**: 111 | 112 | > 注重电梯寻找楼层的优化。请求队列中距当前能够最先到达的楼层的请求信号就是下一个服务对象。 113 | 114 | **缺点**: 115 | 116 | > 队列中的某些请求可能长时间得不到响应,出现所谓的“饿死”现象。 117 | 118 | *(缺点)补充说明*: 处于中间楼层的请求会被快速响应,但处于底层和上层的请求,会被长时间搁置。 119 | 120 | **代码**: 121 | 122 | ```Java 123 | public class SSTF { 124 | public static void exec(List taskList, int initPos) { 125 | System.out.println("1)先来先服务算法(FCFS):"); 126 | System.out.format("电梯当前位于第%s层, 对如下乘客进行服务:\n", initPos); 127 | for (Task task : taskList) { 128 | System.out.format("%d->%d ", task.from, task.to); 129 | } 130 | System.out.println("\n请求次序 服务乘客 电梯移动楼层数"); 131 | 132 | //---------------------调度开始----------------------- 133 | int prev = initPos; 134 | List visit = new ArrayList<>(); 135 | for (int i = 0; i < taskList.size(); i++) { 136 | int min = Integer.MAX_VALUE; 137 | int shortIndex = 0; 138 | for (int j = 0; j < taskList.size(); j++) { 139 | Task task = taskList.get(j); 140 | if (task == null) continue; 141 | int curr = Math.abs(task.from - prev); 142 | if (min > curr) { 143 | min = curr; 144 | shortIndex = j; 145 | } 146 | } 147 | Task e = taskList.get(shortIndex); 148 | visit.add(e); 149 | taskList.set(shortIndex, null); 150 | prev = e.to; 151 | } 152 | taskList.clear(); 153 | taskList.addAll(visit); 154 | //---------------------调度结束----------------------- 155 | 156 | int totalTime = 0; 157 | int prev = initPos; 158 | for (int i = 0; i < taskList.size(); i++) { 159 | Task task = taskList.get(i); 160 | int abs = Math.abs(task.from - prev); 161 | totalTime += abs; 162 | int d = Math.abs(task.from - task.to); 163 | totalTime += d; 164 | prev = task.to; 165 | System.out.format(" %d %s:%2d->%2d %2d\n", i, task.name, task.from, task.to, abs + d); 166 | } 167 | System.out.println("总移动距离: " + totalTime); 168 | double ave = totalTime / 1.0 / taskList.size(); 169 | System.out.format("平均每次服务的距离: %.1f\n", ave); 170 | } 171 | } 172 | ``` 173 | 174 | **点评**: 与FCFS算法相比,SSTF算法会先对请求队列进行排序,每次都会优先处理距离最近的请求。 175 | 176 | ![SSTF](./img/SSTF.png) 177 | 178 | ### 1.3 扫描算法(SCAN) 179 | 180 | 扫描算法(SCAN), 也被称为电梯调度算法,是一种按照楼层顺序依次服务请求,它让电梯在最底层和最顶层之间连续往返运行,在运行过程中响应处在于电梯运行方向相同的各楼层上的请求。 181 | 182 | **优点**: 183 | 184 | > 进行寻找楼层的优化,效率比较高。较好地解决了电梯移动的问题,在这个算法中,每个电梯响应乘客请求使乘客获得服务的次序是由其发出请求的乘客的位置与当前电梯位置之间的距离来决定的。 185 | 186 | **缺点**: 187 | 188 | > 扫描算法的平均响应时间比最短寻找楼层时间优先算法长。 189 | 190 | 扫描算法的响应时间方差比最短寻找楼层时间优先算法小,从统计学角度来讲,扫描算法要比最短寻找楼层时间优先算法稳定。 191 | 192 | **代码**: 193 | 194 | ```Java 195 | public class SCAN { 196 | System.out.println("3)扫描算法(SCAN):"); 197 | System.out.format("电梯当前位于第%s层, 对如下乘客进行服务:\n", initPos); 198 | for (Task task : taskList) { 199 | System.out.format("%d->%d ", task.from, task.to); 200 | } 201 | System.out.println("\n请求次序 服务乘客 电梯移动楼层数"); 202 | //---------------------调度开始----------------------- 203 | List visit = new ArrayList<>(taskList); 204 | visit.sort(new ScanComparator(initPos, direct)); 205 | taskList.clear(); 206 | taskList.addAll(visit); 207 | //---------------------调度结束----------------------- 208 | int totalTime = 0; 209 | for (int i = 0; i < taskList.size(); i++) { 210 | Task task = taskList.get(i); 211 | int d = Math.abs(task.from - task.to); 212 | totalTime += d; 213 | System.out.format(" %d %s:%2d->%2d -\n", i, task.name, task.from, task.to); 214 | } 215 | totalTime = (max - min) * 2; 216 | System.out.println("总移动距离: " + totalTime); 217 | double ave = totalTime / 1.0 / taskList.size(); 218 | System.out.format("平均每次服务的距离: %.1f\n", ave); 219 | } 220 | ``` 221 | 222 | ```Java 223 | /** 224 | * SCAN算法任务排序(调度)比较器 225 | */ 226 | public class ScanComparator implements Comparator { 227 | private final int initPos; 228 | private final Direct direct; 229 | 230 | public ScanComparator(int initPos, Direct direct) { 231 | this.initPos = initPos; 232 | this.direct = direct; 233 | } 234 | 235 | @Override 236 | public int compare(Task o1, Task o2) { 237 | int i = ifInitDirectIsUp(o1, o2); 238 | if (direct == Direct.UP) { 239 | return i; 240 | } else { 241 | return -i; 242 | } 243 | } 244 | 245 | public int ifInitDirectIsUp(Task o1, Task o2) { 246 | int i = biggerOrSmaller(o1, o2); 247 | Direct d1 = o1.getDirect(); 248 | Direct d2 = o2.getDirect(); 249 | if (d1 == d2) { 250 | if (d1 == Direct.UP) { 251 | if (o1.from > initPos) { 252 | return i; 253 | } else { 254 | return 1; 255 | } 256 | } else { 257 | if (o1.from > initPos) { 258 | return -i; 259 | } else { 260 | return 1; 261 | } 262 | } 263 | } else { 264 | if (d1 == Direct.UP) { 265 | if (o1.from > initPos) { 266 | return -1; 267 | } else { 268 | return 1; 269 | } 270 | } else { 271 | if (o1.from > initPos) { 272 | return 1; 273 | } else { 274 | return -1; 275 | } 276 | } 277 | } 278 | } 279 | 280 | 281 | public int biggerOrSmaller(Task o1, Task o2) { 282 | if (o1.from > o2.from) { 283 | return 1; 284 | } else if (o1.from < o2.from) { 285 | return -1; 286 | } else { 287 | return 0; 288 | } 289 | } 290 | } 291 | ``` 292 | 293 | ![SCAN](./img/SCAN.png) 294 | 295 | ### 总结 296 | 297 | 文章还介绍了其他两种非实时算法——**LOOK算法**和**SATF算法**。LOOK算法是对SCAN算法的改进,当判定继续往*上/下*走已经没有请求的楼层,便不会继续前行而是转向,而SCAN算法会继续运行到*顶/底*层再转向;SATF(Shortest Access Time First)算法与 SSTF 算法的思想类似,唯一的区别就是 SATF 算法将 SSTF 算法中的寻找楼层时间改成了访问时间。 298 | 299 | 文章还介绍了几种实时电梯调度算法。基本上是基于前面介绍的几种非实时调度算法的优化和改进。读者如有兴趣,可以对其进行深入研究,细细思考算法的精妙,还颇有趣味。 300 | 301 | 最后借用精读文章内的一句话来结束此文: 302 | 303 | > 哪个算法都不是一个最佳方案,只是它确实解决了一定情况的问题。但是对一个优秀的程序员而言,研究各种算法是无比快乐的。 -------------------------------------------------------------------------------- /dispatching_algorithm.iml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /img/FCFS.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/relish-wang/dispatching_algorithm/7810621c78bff346ec988e7b83afe3299f4e60d5/img/FCFS.png -------------------------------------------------------------------------------- /img/SCAN.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/relish-wang/dispatching_algorithm/7810621c78bff346ec988e7b83afe3299f4e60d5/img/SCAN.png -------------------------------------------------------------------------------- /img/SSTF.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/relish-wang/dispatching_algorithm/7810621c78bff346ec988e7b83afe3299f4e60d5/img/SSTF.png -------------------------------------------------------------------------------- /src/wang/relish/dispatching/Main.java: -------------------------------------------------------------------------------- 1 | package wang.relish.dispatching; 2 | 3 | import wang.relish.dispatching.algorithm.Executor; 4 | import wang.relish.dispatching.algorithm.FCFS; 5 | import wang.relish.dispatching.algorithm.SCAN; 6 | import wang.relish.dispatching.algorithm.SSTF; 7 | import wang.relish.dispatching.bean.Task; 8 | import wang.relish.dispatching.common.Direct; 9 | import wang.relish.dispatching.common.Type; 10 | 11 | import java.util.Collections; 12 | import java.util.LinkedList; 13 | import java.util.List; 14 | 15 | /** 16 | * 简便起见: 17 | * 0 电梯默认初始状态在1层 18 | * 1 所有楼层都是正整数 19 | * 2 每层调度所需时间为1s 20 | * 21 | * @author relish 22 | * @since 2018/08/21 23 | */ 24 | public class Main { 25 | /** 26 | * 电梯初始位置 27 | */ 28 | private static final int INIT_POS = 1; 29 | /** 30 | * 最底层 31 | */ 32 | private static final int MIN_FLOOR = 1; 33 | /** 34 | * 最高层 35 | */ 36 | private static final int MAX_FLOOR = 20; 37 | /** 38 | * 电梯初始前进方向 39 | */ 40 | private static final Direct INIT_DIRECT = Direct.UP; 41 | /** 42 | * 请求队列 43 | */ 44 | private static final List TASKS = Collections.unmodifiableList(new LinkedList() { 45 | { 46 | add(new Task("乘客1", 4, 7)); 47 | add(new Task("乘客2", 8, 10)); 48 | add(new Task("乘客3", 7, 8)); 49 | add(new Task("乘客4", 9, 2)); 50 | add(new Task("乘客5", 10, 7)); 51 | add(new Task("乘客6", 3, 5)); 52 | 53 | } 54 | }); 55 | 56 | public static class ExecutorFactory { 57 | public static Executor create(Type type) { 58 | switch (type) { 59 | case FCFS: 60 | return new FCFS(TASKS, INIT_POS); 61 | case SSTF: 62 | return new SSTF(TASKS, INIT_POS); 63 | case SCAN: 64 | return new SCAN(TASKS, INIT_POS, INIT_DIRECT, MIN_FLOOR, MAX_FLOOR); 65 | default: 66 | throw new IllegalArgumentException("不存在这样的调度的算法"); 67 | } 68 | } 69 | } 70 | 71 | public static void main(String[] args) { 72 | Executor fcfs = ExecutorFactory.create(Type.FCFS); 73 | fcfs.exec(); 74 | 75 | System.out.println("-----------------------------------------------"); 76 | 77 | Executor sstf = ExecutorFactory.create(Type.SSTF); 78 | sstf.exec(); 79 | 80 | System.out.println("-----------------------------------------------"); 81 | 82 | 83 | Executor scan = ExecutorFactory.create(Type.SCAN); 84 | scan.exec(); 85 | } 86 | } 87 | -------------------------------------------------------------------------------- /src/wang/relish/dispatching/algorithm/Executor.java: -------------------------------------------------------------------------------- 1 | package wang.relish.dispatching.algorithm; 2 | 3 | import wang.relish.dispatching.bean.Task; 4 | 5 | import java.util.ArrayList; 6 | import java.util.List; 7 | 8 | /** 9 | * @author relish 10 | * @since 2018/08/21 11 | */ 12 | public abstract class Executor { 13 | protected final List taskList; 14 | protected final int initPos; 15 | 16 | public Executor(List tasks, int initPos) { 17 | this.taskList = new ArrayList<>(tasks); 18 | this.initPos = initPos; 19 | } 20 | 21 | /** 22 | * 进行调度(排序) 23 | */ 24 | protected abstract void dispatching(); 25 | 26 | /** 27 | * 调度算法名称 28 | * 29 | * @return eg. FCFS,SSTF 30 | */ 31 | protected abstract String algorithmName(); 32 | 33 | public void exec() { 34 | System.out.println(algorithmName()); 35 | System.out.format("电梯当前位于第%s层, 对如下乘客进行服务:\n", initPos); 36 | for (Task task : taskList) { 37 | System.out.format("%d->%d ", task.from, task.to); 38 | } 39 | System.out.println("\n请求次序 服务乘客 电梯移动楼层数"); 40 | 41 | dispatching(); 42 | 43 | int totalTime = 0; 44 | int prev = initPos; 45 | for (int i = 0; i < taskList.size(); i++) { 46 | Task task = taskList.get(i); 47 | int abs = Math.abs(task.from - prev); 48 | totalTime += abs; 49 | int d = Math.abs(task.from - task.to); 50 | totalTime += d; 51 | prev = task.to; 52 | System.out.format(" %d %s:%2d->%2d %2d\n", i, task.name, task.from, task.to, abs + d); 53 | } 54 | System.out.println("总移动距离: " + totalTime); 55 | double ave = totalTime / 1.0 / taskList.size(); 56 | System.out.format("平均每次服务的距离: %.1f\n", ave); 57 | } 58 | } 59 | -------------------------------------------------------------------------------- /src/wang/relish/dispatching/algorithm/FCFS.java: -------------------------------------------------------------------------------- 1 | package wang.relish.dispatching.algorithm; 2 | 3 | 4 | import wang.relish.dispatching.bean.Task; 5 | 6 | import java.util.List; 7 | 8 | /** 9 | * @author relish 10 | * @since 2018/08/21 11 | */ 12 | 13 | public class FCFS extends Executor { 14 | 15 | public FCFS(List tasks, int initPos) { 16 | super(tasks, initPos); 17 | } 18 | 19 | @Override 20 | protected void dispatching() { 21 | 22 | } 23 | 24 | @Override 25 | protected String algorithmName() { 26 | return "1)先来先服务算法(FCFS):"; 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /src/wang/relish/dispatching/algorithm/SCAN.java: -------------------------------------------------------------------------------- 1 | package wang.relish.dispatching.algorithm; 2 | 3 | import wang.relish.dispatching.bean.Task; 4 | import wang.relish.dispatching.common.Direct; 5 | import wang.relish.dispatching.comparator.ScanComparator; 6 | 7 | import java.util.ArrayList; 8 | import java.util.List; 9 | 10 | /** 11 | * @author relish 12 | * @since 2018/08/22 13 | */ 14 | public class SCAN extends Executor { 15 | 16 | private Direct direct; 17 | private int min; 18 | private int max; 19 | 20 | public SCAN(List tasks, int initPos, Direct direct, int min, int max) { 21 | super(tasks, initPos); 22 | this.direct = direct; 23 | this.min = min; 24 | this.max = max; 25 | } 26 | 27 | @Override 28 | protected void dispatching() { 29 | List visit = new ArrayList<>(taskList); 30 | visit.sort(new ScanComparator(initPos, direct)); 31 | taskList.clear(); 32 | taskList.addAll(visit); 33 | } 34 | 35 | @Override 36 | protected String algorithmName() { 37 | return "3)扫描算法(SCAN):"; 38 | } 39 | 40 | @Override 41 | public void exec() { 42 | System.out.println(algorithmName()); 43 | System.out.format("电梯当前位于第%s层, 对如下乘客进行服务:\n", initPos); 44 | for (Task task : taskList) { 45 | System.out.format("%d->%d ", task.from, task.to); 46 | } 47 | System.out.println("\n请求次序 服务乘客 电梯移动楼层数"); 48 | 49 | this.dispatching(); 50 | 51 | int totalTime = 0; 52 | for (int i = 0; i < taskList.size(); i++) { 53 | Task task = taskList.get(i); 54 | int d = Math.abs(task.from - task.to); 55 | totalTime += d; 56 | System.out.format(" %d %s:%2d->%2d -\n", i, task.name, task.from, task.to); 57 | } 58 | totalTime = (max - min) * 2; 59 | System.out.println("总移动距离: " + totalTime); 60 | double ave = totalTime / 1.0 / taskList.size(); 61 | System.out.format("平均每次服务的距离: %.1f\n", ave); 62 | } 63 | } 64 | -------------------------------------------------------------------------------- /src/wang/relish/dispatching/algorithm/SSTF.java: -------------------------------------------------------------------------------- 1 | package wang.relish.dispatching.algorithm; 2 | 3 | import wang.relish.dispatching.bean.Task; 4 | 5 | import java.util.ArrayList; 6 | import java.util.List; 7 | 8 | /** 9 | * @author relish 10 | * @since 2018/08/21 11 | */ 12 | public class SSTF extends Executor { 13 | 14 | 15 | public SSTF(List tasks, int initPos) { 16 | super(tasks, initPos); 17 | } 18 | 19 | @Override 20 | protected void dispatching() { 21 | int prev = initPos; 22 | List visit = new ArrayList<>(); 23 | for (int i = 0; i < taskList.size(); i++) { 24 | int min = Integer.MAX_VALUE; 25 | int shortIndex = 0; 26 | for (int j = 0; j < taskList.size(); j++) { 27 | Task task = taskList.get(j); 28 | if (task == null) continue; 29 | int curr = Math.abs(task.from - prev); 30 | if (min > curr) { 31 | min = curr; 32 | shortIndex = j; 33 | } 34 | } 35 | Task e = taskList.get(shortIndex); 36 | visit.add(e); 37 | taskList.set(shortIndex, null); 38 | prev = e.to; 39 | } 40 | taskList.clear(); 41 | taskList.addAll(visit); 42 | } 43 | 44 | @Override 45 | protected String algorithmName() { 46 | return "2)最短寻找楼层时间优先算法(SSTF):"; 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /src/wang/relish/dispatching/bean/Task.java: -------------------------------------------------------------------------------- 1 | package wang.relish.dispatching.bean; 2 | 3 | import wang.relish.dispatching.common.Direct; 4 | 5 | /** 6 | * 一次任务请求 7 | * 8 | * @author relish 9 | * @since 2018/08/21 10 | */ 11 | public class Task { 12 | 13 | public String name; 14 | /** 15 | * 请求所在楼层 16 | */ 17 | public int from; 18 | /** 19 | * 请求去往楼层 20 | */ 21 | public int to; 22 | 23 | public Task(String name, int from, int to) { 24 | this.name = name; 25 | this.from = from; 26 | this.to = to; 27 | } 28 | 29 | public Direct getDirect() { 30 | return from - to > 0 ? Direct.DOWN : Direct.UP; 31 | } 32 | 33 | 34 | @Override 35 | public String toString() { 36 | return String.format("%s %d->%d", name, from, to); 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /src/wang/relish/dispatching/common/Direct.java: -------------------------------------------------------------------------------- 1 | package wang.relish.dispatching.common; 2 | 3 | /** 4 | * @author relish 5 | * @since 2018/08/22 6 | */ 7 | public enum Direct { 8 | UP, 9 | DOWN 10 | } 11 | -------------------------------------------------------------------------------- /src/wang/relish/dispatching/common/Type.java: -------------------------------------------------------------------------------- 1 | package wang.relish.dispatching.common; 2 | 3 | /** 4 | * @author relish 5 | * @since 2018/08/22 6 | */ 7 | public enum Type { 8 | FCFS, 9 | SSTF, 10 | SCAN 11 | } 12 | -------------------------------------------------------------------------------- /src/wang/relish/dispatching/comparator/ScanComparator.java: -------------------------------------------------------------------------------- 1 | package wang.relish.dispatching.comparator; 2 | 3 | import wang.relish.dispatching.bean.Task; 4 | import wang.relish.dispatching.common.Direct; 5 | 6 | import java.util.Comparator; 7 | 8 | /** 9 | * @author relish 10 | * @since 2018/08/22 11 | */ 12 | public class ScanComparator implements Comparator { 13 | private final int initPos; 14 | private final Direct direct; 15 | 16 | public ScanComparator(int initPos, Direct direct) { 17 | this.initPos = initPos; 18 | this.direct = direct; 19 | } 20 | 21 | @Override 22 | public int compare(Task o1, Task o2) { 23 | int i = ifInitDirectIsUp(o1, o2); 24 | if (direct == Direct.UP) { 25 | return i; 26 | } else { 27 | return -i; 28 | } 29 | } 30 | 31 | public int ifInitDirectIsUp(Task o1, Task o2) { 32 | int i = biggerOrSmaller(o1, o2); 33 | Direct d1 = o1.getDirect(); 34 | Direct d2 = o2.getDirect(); 35 | if (d1 == d2) { 36 | if (d1 == Direct.UP) { 37 | if (o1.from > initPos) { 38 | return i; 39 | } else { 40 | return 1; 41 | } 42 | } else { 43 | if (o1.from > initPos) { 44 | return -i; 45 | } else { 46 | return 1; 47 | } 48 | } 49 | } else { 50 | if (d1 == Direct.UP) { 51 | if (o1.from > initPos) { 52 | return -1; 53 | } else { 54 | return 1; 55 | } 56 | } else { 57 | if (o1.from > initPos) { 58 | return 1; 59 | } else { 60 | return -1; 61 | } 62 | } 63 | } 64 | } 65 | 66 | 67 | public int biggerOrSmaller(Task o1, Task o2) { 68 | if (o1.from > o2.from) { 69 | return 1; 70 | } else if (o1.from < o2.from) { 71 | return -1; 72 | } else { 73 | return 0; 74 | } 75 | } 76 | } 77 | --------------------------------------------------------------------------------