From 2ace81487936655e49f90d16a6c221a0ae5b7ada Mon Sep 17 00:00:00 2001 From: Viscaria233 Date: Sat, 4 Mar 2017 15:50:53 +0800 Subject: [PATCH 01/11] Create week2.md --- group01/895457260/journal/week2.md | 48 ++++++++++++++++++++++++++++++ 1 file changed, 48 insertions(+) create mode 100644 group01/895457260/journal/week2.md diff --git a/group01/895457260/journal/week2.md b/group01/895457260/journal/week2.md new file mode 100644 index 0000000000..2085496dc6 --- /dev/null +++ b/group01/895457260/journal/week2.md @@ -0,0 +1,48 @@ +组装一个简单的类似cpu的机器 +------------------------- +>接到学校布置的任务,要用仿真软件画一个简单的能运行的cpu,要求8位字长,给定14种指令。 +这一下难倒了不少同学,我也花了10天左右来完成这个任务。这篇文章就记录一下我是如何从头开始组装这个cpu(或者说类似cpu的机器)的。 + +打开仿真软件,空空如也不知从何下手,总之先把印象中的“cpu数据通路图”画出来。 +需要一个ALU,RAM,PC,IR,AR,两个ALU的DR,以及若干通用寄存器,这里我用了3个通用寄存器。 + +RAM同时保存指令和数据(本质相同,都是二进制数),PC从0开始不停地增加1,这样RAM里的比特就会被一个一个读出来放到数据总线上(也有不经过PC的情况), +之后这些比特如果被IR从总线上读走,那么它们就是指令,否则就是数据。机器会按一定的顺序让IR或其他东西从总线上读比特, +比如IR先读一次,其他东西再读,其他东西读完之后,又轮到IR读一次。我们只要配合这个顺序,把相应的比特存进RAM,就能让机器按我们的想法运行。 + +现在RAM里全是0,机器能从头到尾读一遍RAM,然后按自己的顺序把这些0交给IR或别的东西。 +把比特交出去之后怎么办呢?PC应该暂停下来,先让这次的指令或数据被处理完,然后PC再从RAM里读下一串比特。 +这就意味着:包括PC,RAM,IR,寄存器等等在内的所有东西,除了它们的数据输入端以外,别的输入端都应该由机器来控制, +而不是直接接电源或接地,或接上一个频率恒定的时钟。 + +这大概就是控制信号,用来控制这些部件如何工作。 +要完成一个动作可能需要好几组控制信号,比如从RAM里取出比特,送给IR: +(我没能理解T1,T2,T3,T4具体是如何工作的,只好自己想了个看上去容易实现的方法) +>对照“数据通路图”看这个过程。 +>第1组、所有控制信号复位(置为无效,高有效的置0,低有效的置1) +>第2组、PC的值放到总线(PC的输出三态门控制端置有效,别的信号同上复位状态) +>3、AR从总线上取值,送到RAM地址端,PC三态门关上,RAM准备读操作(AR的时钟跳一个上升沿,PC三态门置无效,RAM读操作控制端置有效,别的信号同上) +>4、RAM读出值放到总线(AR时钟复位,RAM片选信号置有效,别的信号同上) +>5、IR拿走总线上的值,RAM关上(IR时钟一个上升沿,RAM片选信号置无效,别的信号同上) +>6、所有信号复位 + +上面的过程就是“取指”,“译码”。很明显这些控制信号是按顺序送出的,要实现这一点,则需要另一个计数器,不断加1,按顺序从ROM里读出控制信号, +然后直接送给PC,RAM等部件。像这样把取指译码和所有指令所需要的控制信号序列,存进一块ROM里(编个号,叫ROM1),每当取指译码完成,IR送来指令, +就把计数器置数为这条指令的第1组控制信号所在的地址,然后就会自动按顺序送出控制信号,这就是“执行”。 + +除了停机指令HALT之外,一条指令执行完成后,紧接着又应该取指译码,简单起见,我直接在除HALT之外的每条指令的控制信号之后,又重复了一遍取指译码的控制信号。 + +至于如何根据指令获得第1组控制信号的地址,还是简单起见,我又拿了一块ROM(编号叫ROM2),直接把8位指令当做地址,控制信号的地址当做内容,存进去。 +比如:MOV R0,R1这条指令是10000001,其第一组控制信号位于ROM1的00001001地址处,那就把00001001写入ROM2的10000001地址处。 +这样,把8位指令直接送入ROM2的地址端,出来的就是第一组控制信号所在的地址,再用它给计数器置数,然后就会从这个地址开始自动按顺序送出控制信号。 + +把一个时钟接到计数器上,基本上大功告成了。还有一个问题:遇到HALT时,其后虽没有取指译码的控制信号,但计数器仍然会不断加1,而之后的地址处全是0, +于是送出了一堆0作为控制信号,这是不正确的。 +我用D型触发器和几个逻辑门做了一个小电路,当8位指令是HALT时,让计数器控制端无效并锁存这个无效状态,不会再加1,这样就实现了停机。 + +还有一个问题:所有控制信号应该同时送出。为此我把控制信号都先接在了锁存器上,锁存器会在下一个时钟上升沿同时送出所有控制信号。 + +然后,写几个小程序,读取EXCEL里的控制信号序列,存到ROM1里,并把ROM2也调整好。 +读取记事本里的汇编代码,生成对应的机器指令,存到RAM里。 + +运行一下,结果正确。至此,这个类似cpu的机器完成了。 From 550f0fd2fb2e74dae0db0badc7c54a9b50381d20 Mon Sep 17 00:00:00 2001 From: Viscaria233 Date: Sat, 4 Mar 2017 15:52:49 +0800 Subject: [PATCH 02/11] Update week2.md --- group01/895457260/journal/week2.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/group01/895457260/journal/week2.md b/group01/895457260/journal/week2.md index 2085496dc6..e7b09d9d4e 100644 --- a/group01/895457260/journal/week2.md +++ b/group01/895457260/journal/week2.md @@ -1,7 +1,7 @@ 组装一个简单的类似cpu的机器 ------------------------- >接到学校布置的任务,要用仿真软件画一个简单的能运行的cpu,要求8位字长,给定14种指令。 -这一下难倒了不少同学,我也花了10天左右来完成这个任务。这篇文章就记录一下我是如何从头开始组装这个cpu(或者说类似cpu的机器)的。 +我花了10天左右来完成这个任务。这篇文章就记录一下我是如何从头开始组装这个cpu(或者说类似cpu的机器)的。 打开仿真软件,空空如也不知从何下手,总之先把印象中的“cpu数据通路图”画出来。 需要一个ALU,RAM,PC,IR,AR,两个ALU的DR,以及若干通用寄存器,这里我用了3个通用寄存器。 From 1022c1e13f42b327d208238657dccadbcb12e15f Mon Sep 17 00:00:00 2001 From: Viscaria233 Date: Sat, 4 Mar 2017 15:53:17 +0800 Subject: [PATCH 03/11] Update week2.md --- group01/895457260/journal/week2.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/group01/895457260/journal/week2.md b/group01/895457260/journal/week2.md index e7b09d9d4e..5d66f6dfc0 100644 --- a/group01/895457260/journal/week2.md +++ b/group01/895457260/journal/week2.md @@ -45,4 +45,4 @@ RAM同时保存指令和数据(本质相同,都是二进制数),PC从0 然后,写几个小程序,读取EXCEL里的控制信号序列,存到ROM1里,并把ROM2也调整好。 读取记事本里的汇编代码,生成对应的机器指令,存到RAM里。 -运行一下,结果正确。至此,这个类似cpu的机器完成了。 +写一段汇编,运行,结果正确。至此,这个类似cpu的机器完成了。 From 3ba074729cbcac97a23a13e6fec129ea2b4fc367 Mon Sep 17 00:00:00 2001 From: Viscaria233 Date: Sat, 4 Mar 2017 16:07:23 +0800 Subject: [PATCH 04/11] Update week2.md --- group01/895457260/journal/week2.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/group01/895457260/journal/week2.md b/group01/895457260/journal/week2.md index 5d66f6dfc0..0516617b90 100644 --- a/group01/895457260/journal/week2.md +++ b/group01/895457260/journal/week2.md @@ -1,7 +1,7 @@ -组装一个简单的类似cpu的机器 +仿真一个简单的类似cpu的机器 ------------------------- >接到学校布置的任务,要用仿真软件画一个简单的能运行的cpu,要求8位字长,给定14种指令。 -我花了10天左右来完成这个任务。这篇文章就记录一下我是如何从头开始组装这个cpu(或者说类似cpu的机器)的。 +我花了10天左右来完成这个任务。这篇文章就记录一下我是如何从头开始画这个cpu(或者说类似cpu的机器)的。 打开仿真软件,空空如也不知从何下手,总之先把印象中的“cpu数据通路图”画出来。 需要一个ALU,RAM,PC,IR,AR,两个ALU的DR,以及若干通用寄存器,这里我用了3个通用寄存器。 From a81401d150d9e5fe1c35b9aa7bb5e7fb7f8c8c30 Mon Sep 17 00:00:00 2001 From: Viscaria233 Date: Sat, 4 Mar 2017 16:07:48 +0800 Subject: [PATCH 05/11] Update week2.md --- group01/895457260/journal/week2.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/group01/895457260/journal/week2.md b/group01/895457260/journal/week2.md index 0516617b90..ee03c6667f 100644 --- a/group01/895457260/journal/week2.md +++ b/group01/895457260/journal/week2.md @@ -42,7 +42,7 @@ RAM同时保存指令和数据(本质相同,都是二进制数),PC从0 还有一个问题:所有控制信号应该同时送出。为此我把控制信号都先接在了锁存器上,锁存器会在下一个时钟上升沿同时送出所有控制信号。 -然后,写几个小程序,读取EXCEL里的控制信号序列,存到ROM1里,并把ROM2也调整好。 +最后,写几个小程序,读取EXCEL里的控制信号序列,存到ROM1里,并把ROM2也调整好。 读取记事本里的汇编代码,生成对应的机器指令,存到RAM里。 -写一段汇编,运行,结果正确。至此,这个类似cpu的机器完成了。 +打开记事本写一段汇编,运行,结果正确。至此,这个类似cpu的机器完成了。 From 85203ebc30490781280fd312d530c082df84ac9e Mon Sep 17 00:00:00 2001 From: Haochen Date: Mon, 6 Mar 2017 15:27:48 +0800 Subject: [PATCH 06/11] add linkedlist algorithm --- .../src/datastructure/basic/LinkedList.java | 176 ++++++++++++++++++ 1 file changed, 176 insertions(+) diff --git a/group01/895457260/code/src/datastructure/basic/LinkedList.java b/group01/895457260/code/src/datastructure/basic/LinkedList.java index 174044c546..b59e72c90a 100644 --- a/group01/895457260/code/src/datastructure/basic/LinkedList.java +++ b/group01/895457260/code/src/datastructure/basic/LinkedList.java @@ -1,6 +1,9 @@ package datastructure.basic; import datastructure.exception.EmptyListException; +import javafx.util.Pair; + +import java.util.Objects; public class LinkedList implements List { @@ -129,4 +132,177 @@ private void removeNode(Node node, Node pre) { node.next = null; size--; } + + //清空整条链,返回链中结点数量 + private int clearLink(Node start) { + int count = 0; + while (start != null) { + Node node = start; + start = start.next; + node.data = null; + node.next = null; + count++; + } + return count; + } + + /** + * 把该链表逆置 + * 例如链表为 3->7->10 , 逆置后变为 10->7->3 + */ + public void reverse(){ + Stack stack = new Stack(); + for (Node node = head.next; node != null; node = node.next) { + stack.push(node); + } + head.next = (Node) stack.peek(); + while (stack.size() > 1) { + Node top = (Node) stack.pop(); + top.next = (Node) stack.peek(); + } + ((Node) stack.peek()).next = null; + } + + /** + * 删除一个单链表的前半部分 + * 例如:list = 2->5->7->8 , 删除以后的值为 7->8 + * 如果list = 2->5->7->8->10 ,删除以后的值为7,8,10 + + */ + public void removeFirstHalf(){ + int half = size() / 2; + if (half > 1) { + Node first = head.next; + + Node preHalf = findNode(half - 1); + head.next = preHalf.next; + preHalf.next = null; + size -= clearLink(first); + } + } + + /** + * 从第i个元素开始, 删除length 个元素 , 注意i从0开始 + * @param i + * @param length + */ + public void remove(int i, int length){ + Node preI = findNode(i - 1); + Node removeTo = findNode(i + length - 1); + head.next = removeTo.next; + removeTo.next = null; + size -= clearLink(preI); + } + /** + * 假定当前链表和list均包含已升序排列的整数 + * 从当前链表中取出那些list所指定的元素 + * 例如当前链表 = 11->101->201->301->401->501->601->701 + * listB = 1->3->4->6 + * 返回的结果应该是[101,301,401,601] + * @param list + */ + public Object[] getElements(LinkedList list){ + Object[] result = new Object[list.size()]; + int count = 0; + + + Node nodeI = head.next; + Node nodeJ = list.head.next; + for (int i = 0; i < size() && count < result.length; ++i) { + if (i == (int) nodeJ.data) { + result[count] = nodeI; + count++; + nodeI = nodeI.next; + nodeJ = nodeJ.next; + } else { + nodeI = nodeI.next; + } + } + return result; + } + + /** + * 已知链表中的元素以值递增有序排列,并以单链表作存储结构。 + * 从当前链表中中删除在list中出现的元素 + + * @param list + */ + + public void subtract(LinkedList list){ + Node pre = head; + Node node = list.head.next; + while (pre.next != null && node != null) { + if ((int) pre.next.data < (int) node.data) { + pre = pre.next; + } else if ((int) pre.next.data > (int) node.data) { + node = node.next; + } else { + removeNode(pre.next, pre); + } + } + } + + /** + * 已知当前链表中的元素以值递增有序排列,并以单链表作存储结构。 + * 删除表中所有值相同的多余元素(使得操作后的线性表中所有元素的值均不相同) + */ + public void removeDuplicateValues(){ + Node node = head; + while (node.next != null) { + if (Objects.equals(node.data, node.next.data)) { + removeNode(node.next, node); + } else { + node = node.next; + } + } + } + + /** + * 已知链表中的元素以值递增有序排列,并以单链表作存储结构。 + * 试写一高效的算法,删除表中所有值大于min且小于max的元素(若表中存在这样的元素) + * @param min + * @param max + */ + public void removeRange(int min, int max){ + Node node = head; + while (node.next != null) { + int value = (int) node.next.data; + if (value <= min) { // 还未进入范围 + node = node.next; + } else if (value >= max) { // 超出范围,停止遍历 + break; + } else { // 在范围内,删除之 + removeNode(node.next, node); + } + } + } + + /** + * 假设当前链表和参数list指定的链表均以元素依值递增有序排列(同一表中的元素值各不相同) + * 现要求生成新链表C,其元素为当前链表和list中元素的交集,且表C中的元素有依值递增有序排列 + * @param list + */ + public LinkedList intersection(LinkedList list){ + LinkedList result = new LinkedList(); + Node inThis = head.next; + Node node = list.head.next; + int[] temp = new int[Math.min(size(), list.size())]; + int count = 0; + while (inThis != null && node != null) { + int compare = (int) inThis.data - (int) node.data; + if (compare < 0) { + inThis = inThis.next; + } else if (compare > 0) { + node = node.next; + } else { + temp[count++] = (int) node.data; + inThis = inThis.next; + node = node.next; + } + } + for (int i = count; i >= 0; --i) { + result.addFirst(temp[i]); + } + return result; + } } From 80d95a46b671ab5162714a5aa25b3d41beeb2329 Mon Sep 17 00:00:00 2001 From: Haochen Date: Mon, 6 Mar 2017 19:08:53 +0800 Subject: [PATCH 07/11] add multi-thread downloading --- .../895457260/code/src/download/Config.java | 12 ++ .../code/src/download/DownloadThread.java | 99 ++++++++++ .../code/src/download/FileDownloader.java | 180 ++++++++++++++++++ .../code/src/download/FileDownloaderTest.java | 61 ++++++ .../code/src/download/api/Connection.java | 23 +++ .../src/download/api/ConnectionException.java | 3 + .../src/download/api/ConnectionManager.java | 10 + .../src/download/api/DownloadException.java | 7 + .../src/download/api/DownloadListener.java | 5 + .../src/download/impl/ConnectionImpl.java | 48 +++++ .../download/impl/ConnectionManagerImpl.java | 12 ++ 11 files changed, 460 insertions(+) create mode 100644 group01/895457260/code/src/download/Config.java create mode 100644 group01/895457260/code/src/download/DownloadThread.java create mode 100644 group01/895457260/code/src/download/FileDownloader.java create mode 100644 group01/895457260/code/src/download/FileDownloaderTest.java create mode 100644 group01/895457260/code/src/download/api/Connection.java create mode 100644 group01/895457260/code/src/download/api/ConnectionException.java create mode 100644 group01/895457260/code/src/download/api/ConnectionManager.java create mode 100644 group01/895457260/code/src/download/api/DownloadException.java create mode 100644 group01/895457260/code/src/download/api/DownloadListener.java create mode 100644 group01/895457260/code/src/download/impl/ConnectionImpl.java create mode 100644 group01/895457260/code/src/download/impl/ConnectionManagerImpl.java diff --git a/group01/895457260/code/src/download/Config.java b/group01/895457260/code/src/download/Config.java new file mode 100644 index 0000000000..adbf32f40f --- /dev/null +++ b/group01/895457260/code/src/download/Config.java @@ -0,0 +1,12 @@ +package download; + +import java.io.File; + +/** + * Created by Haochen on 2017/3/6. + * TODO: + */ +public class Config { + public static File targetDirectory = new File("download/"); + public static File tempDirectory = new File(targetDirectory, "temp/"); +} diff --git a/group01/895457260/code/src/download/DownloadThread.java b/group01/895457260/code/src/download/DownloadThread.java new file mode 100644 index 0000000000..2ec27810d7 --- /dev/null +++ b/group01/895457260/code/src/download/DownloadThread.java @@ -0,0 +1,99 @@ +package download; + +import download.api.Connection; + +import java.io.File; +import java.io.FileNotFoundException; +import java.io.FileOutputStream; +import java.io.IOException; + +public class DownloadThread extends Thread { + Connection conn; + int startPos; + int endPos; + + File targetFile; + OnCompleteListener onComplete; + OnFailListener onFail; + + public DownloadThread(Connection conn, int startPos, int endPos, File targetFile, + OnCompleteListener onComplete, OnFailListener onFail) { + this.conn = conn; + this.startPos = startPos; + this.endPos = endPos; + this.targetFile = targetFile; + this.onComplete = onComplete; + this.onFail = onFail; + } + + @Override + public void run() { + boolean success = false; + int maxFailCount = 5; + int failCount = 0; + while (!success) { + FileOutputStream fos = null; + try { + fos = new FileOutputStream(targetFile); + tryDownload(fos); + success = true; + } catch (FileNotFoundException e) { + e.printStackTrace(); + } catch (IOException e) { + if (failCount < maxFailCount) { + failCount++; + try { + recreateFile(fos, targetFile); + } catch (IOException e1) { + e1.printStackTrace(); + } + } else { + break; + } + } finally { + if (fos != null) { + try { + fos.close(); + } catch (IOException e) { + e.printStackTrace(); + } + } + } + } + + if (onComplete != null) { + if (success) { + onComplete.onComplete(); + } else { + onFail.onFail(); + } + } + } + + private void recreateFile(FileOutputStream old, File file) throws IOException { + if (old != null) { + old.close(); + } + file.delete(); + file.createNewFile(); + } + + private void tryDownload(FileOutputStream fos) throws IOException { + int bufSize = 1024; + int from = startPos; + while (from < endPos) { + int to = Math.min(from + bufSize, endPos); + byte[] buf = conn.read(from, to); + from = to; + fos.write(buf); + fos.flush(); + } + } + + public interface OnCompleteListener { + void onComplete(); + } + public interface OnFailListener { + void onFail(); + } +} diff --git a/group01/895457260/code/src/download/FileDownloader.java b/group01/895457260/code/src/download/FileDownloader.java new file mode 100644 index 0000000000..38a1b6940b --- /dev/null +++ b/group01/895457260/code/src/download/FileDownloader.java @@ -0,0 +1,180 @@ +package download; + +import download.api.*; + +import java.io.*; +import java.net.MalformedURLException; +import java.net.URL; +import java.net.URLConnection; +import java.util.Date; + + +public class FileDownloader { + String url; + DownloadListener listener; + ConnectionManager manager; + + public FileDownloader(String url) { + this.url = url; + } + + public void execute() { + // 在这里实现你的代码, 注意: 需要用多线程实现下载 + // 这个类依赖于其他几个接口, 你需要写这几个接口的实现代码 + // (1) ConnectionManager , 可以打开一个连接,通过Connection可以读取其中的一段(用startPos, endPos来指定) + // (2) DownloadListener, 由于是多线程下载, 调用这个类的客户端不知道什么时候结束,所以你需要实现当所有 + // 线程都执行完以后, 调用listener的notifiedFinished方法, 这样客户端就能收到通知。 + // 具体的实现思路: + // 1. 需要调用ConnectionManager的open方法打开连接, 然后通过Connection.getContentLength方法获得文件的长度 + // 2. 至少启动3个线程下载, 注意每个线程需要先调用ConnectionManager的open方法 + // 然后调用read方法, read方法中有读取文件的开始位置和结束位置的参数, 返回值是byte[]数组 + // 3. 把byte数组写入到文件中 + // 4. 所有的线程都下载完成以后, 需要调用listener的notifiedFinished方法 + + // 下面的代码是示例代码, 也就是说只有一个线程, 你需要改造成多线程的。 + if (!Config.targetDirectory.exists()) { + Config.targetDirectory.mkdir(); + } + if (!Config.tempDirectory.exists()) { + Config.tempDirectory.mkdir(); + } + + int threadCount = 4; + File[] tempFiles = new File[threadCount]; + Connection[] connections = new Connection[threadCount]; + boolean[] threadComplete = new boolean[threadCount]; + for (int i = 0; i < threadCount; ++i) { + File targetFile = new File(Config.tempDirectory, + new Date().getTime() + "_" + i); + tempFiles[i] = targetFile; + + Connection conn = null; + try { + conn = manager.open(this.url); + } catch (ConnectionException e) { + e.printStackTrace(); + } + + if (conn != null) { + connections[i] = conn; + int length = conn.getContentLength(); + int startPos = (int) (1.0 * length / threadCount * i); + int endPos = i == threadCount - 1 ? length : (int) (1.0 * length / threadCount * (i + 1)); + System.out.println(i + " start: " + startPos + " end: " + endPos); + final int index = i; + new DownloadThread(conn, startPos, endPos, targetFile, + () -> threadComplete[index] = true, () -> { + try { + downloadError(connections); + } catch (DownloadException e) { + e.printStackTrace(); + } + }).start(); + } + } + + // 等待下载完成 + while (true) { + boolean complete = true; + for (boolean b : threadComplete) { + complete = complete && b; + } + if (complete) { + break; + } else { + try { + Thread.sleep(1000); + } catch (InterruptedException e) { + e.printStackTrace(); + } + } + } + + // 合并临时文件 + String[] split = url.replaceAll("/+", "/").split("/"); + File saveFile = new File(Config.targetDirectory, split[split.length - 1]); + FileOutputStream fos = null; + try { + fos = new FileOutputStream(saveFile); + for (File tempFile : tempFiles) { + write(tempFile, fos); + tempFile.delete(); + } + } catch (FileNotFoundException e) { + e.printStackTrace(); + } finally { + if (fos != null) { + try { + fos.close(); + } catch (IOException e) { + e.printStackTrace(); + } + } + for (Connection c : connections) { + if (c != null) { + c.close(); + } + } + } + + if (listener != null) { + listener.notifyFinished(); + } + } + + + private void downloadError(Connection[] connections) throws DownloadException { + for (Connection c : connections) { + c.close(); + } + throw new DownloadException(); + } + + private void write(File inputFile, OutputStream os) { + FileInputStream fis = null; + int bufSize = 1024; + byte[] buf = new byte[bufSize]; + int n; + try { + fis = new FileInputStream(inputFile); + while ((n = fis.read(buf)) != -1) { + os.write(buf, 0, n); + os.flush(); + } + } catch (IOException e) { + e.printStackTrace(); + } finally { + if (fis != null) { + try { + fis.close(); + } catch (IOException e) { + e.printStackTrace(); + } + } + } + } + + public void setListener(DownloadListener listener) { + this.listener = listener; + } + + public void setConnectionManager(ConnectionManager manager){ + this.manager = manager; + } + + public DownloadListener getListener(){ + return this.listener; + } + + public static void main(String[] args) { + try { + URL url = new URL("file:///E:/Video/download/88993.mp4"); + System.out.println(url.getProtocol() + " " + url.getHost() + " " + url.getPort() + + " " + url.getPath() + " " + url.getFile()); + URLConnection c = url.openConnection(); + System.out.println(c.getContentLength()); + } catch (IOException e) { + e.printStackTrace(); + } + } +} diff --git a/group01/895457260/code/src/download/FileDownloaderTest.java b/group01/895457260/code/src/download/FileDownloaderTest.java new file mode 100644 index 0000000000..f8a715ac2a --- /dev/null +++ b/group01/895457260/code/src/download/FileDownloaderTest.java @@ -0,0 +1,61 @@ +package download; + +import download.FileDownloader; +import org.junit.After; +import org.junit.Before; +import org.junit.Test; + +import download.api.ConnectionManager; +import download.api.DownloadListener; +import download.impl.ConnectionManagerImpl; + +public class FileDownloaderTest { + boolean downloadFinished = false; + @Before + public void setUp() throws Exception { + } + + @After + public void tearDown() throws Exception { + } + + @Test + public void testDownload() { + +// String url = "http://localhost:8080/test.jpg"; + String url = "file:///E:/Video/download/88993.mp4"; + + FileDownloader downloader = new FileDownloader(url); + + + ConnectionManager cm = new ConnectionManagerImpl(); + downloader.setConnectionManager(cm); + + downloader.setListener(new DownloadListener() { + @Override + public void notifyFinished() { + downloadFinished = true; + } + + }); + + + downloader.execute(); + + // 等待多线程下载程序执行完毕 + while (!downloadFinished) { + try { + System.out.println("还没有下载完成,休眠五秒"); + //休眠5秒 + Thread.sleep(5000); + } catch (InterruptedException e) { + e.printStackTrace(); + } + } + System.out.println("下载完成!"); + + + + } + +} diff --git a/group01/895457260/code/src/download/api/Connection.java b/group01/895457260/code/src/download/api/Connection.java new file mode 100644 index 0000000000..48f6946eb5 --- /dev/null +++ b/group01/895457260/code/src/download/api/Connection.java @@ -0,0 +1,23 @@ +package download.api; + +import java.io.IOException; + +public interface Connection { + /** + * 给定开始和结束位置, 读取数据, 返回值是字节数组 + * @param startPos 开始位置, 从0开始 + * @param endPos 结束位置 + * @return + */ + byte[] read(int startPos,int endPos) throws IOException; + /** + * 得到数据内容的长度 + * @return + */ + int getContentLength(); + + /** + * 关闭连接 + */ + void close(); +} diff --git a/group01/895457260/code/src/download/api/ConnectionException.java b/group01/895457260/code/src/download/api/ConnectionException.java new file mode 100644 index 0000000000..c0454093fe --- /dev/null +++ b/group01/895457260/code/src/download/api/ConnectionException.java @@ -0,0 +1,3 @@ +package download.api; + +public class ConnectionException extends Exception {} diff --git a/group01/895457260/code/src/download/api/ConnectionManager.java b/group01/895457260/code/src/download/api/ConnectionManager.java new file mode 100644 index 0000000000..e8ef315639 --- /dev/null +++ b/group01/895457260/code/src/download/api/ConnectionManager.java @@ -0,0 +1,10 @@ +package download.api; + +public interface ConnectionManager { + /** + * 给定一个url , 打开一个连接 + * @param url + * @return + */ + Connection open(String url) throws ConnectionException; +} diff --git a/group01/895457260/code/src/download/api/DownloadException.java b/group01/895457260/code/src/download/api/DownloadException.java new file mode 100644 index 0000000000..ed5ad90782 --- /dev/null +++ b/group01/895457260/code/src/download/api/DownloadException.java @@ -0,0 +1,7 @@ +package download.api; + +/** + * Created by Haochen on 2017/3/6. + * TODO: + */ +public class DownloadException extends Exception {} diff --git a/group01/895457260/code/src/download/api/DownloadListener.java b/group01/895457260/code/src/download/api/DownloadListener.java new file mode 100644 index 0000000000..ed81e70b7c --- /dev/null +++ b/group01/895457260/code/src/download/api/DownloadListener.java @@ -0,0 +1,5 @@ +package download.api; + +public interface DownloadListener { + void notifyFinished(); +} diff --git a/group01/895457260/code/src/download/impl/ConnectionImpl.java b/group01/895457260/code/src/download/impl/ConnectionImpl.java new file mode 100644 index 0000000000..78ca55198a --- /dev/null +++ b/group01/895457260/code/src/download/impl/ConnectionImpl.java @@ -0,0 +1,48 @@ +package download.impl; + +import java.io.*; +import java.net.URL; +import java.net.URLConnection; + +import download.api.Connection; +import download.api.ConnectionException; + +public class ConnectionImpl implements Connection { + private URLConnection connection; + private InputStream inputStream; + + ConnectionImpl(String url) throws ConnectionException { + try { + connection = new URL(url).openConnection(); + inputStream = connection.getInputStream(); + inputStream.mark(connection.getContentLength()); + } catch (IOException e) { + e.printStackTrace(); + } + } + + @Override + public byte[] read(int startPos, int endPos) throws IOException { + inputStream.reset(); + inputStream.skip(startPos); + byte[] bytes = new byte[endPos - startPos]; + int n = inputStream.read(bytes); + return n == -1 ? new byte[0] : bytes; + } + + @Override + public int getContentLength() { + return connection.getContentLength(); + } + + @Override + public void close() { + if (inputStream != null) { + try { + inputStream.close(); + } catch (IOException e) { + e.printStackTrace(); + } + } + } +} diff --git a/group01/895457260/code/src/download/impl/ConnectionManagerImpl.java b/group01/895457260/code/src/download/impl/ConnectionManagerImpl.java new file mode 100644 index 0000000000..be17fa9110 --- /dev/null +++ b/group01/895457260/code/src/download/impl/ConnectionManagerImpl.java @@ -0,0 +1,12 @@ +package download.impl; + +import download.api.Connection; +import download.api.ConnectionException; +import download.api.ConnectionManager; + +public class ConnectionManagerImpl implements ConnectionManager { + @Override + public Connection open(String url) throws ConnectionException { + return new ConnectionImpl(url); + } +} From 4107c274e39e7c6ef379493bd90eeddb5369211f Mon Sep 17 00:00:00 2001 From: Haochen Date: Wed, 8 Mar 2017 00:16:46 +0800 Subject: [PATCH 08/11] refactor multi-thread downloading --- .../code/src/download/DownloadThread.java | 74 +++++---- .../code/src/download/FileDownloader.java | 152 +++++++++--------- .../code/src/download/FileDownloaderTest.java | 10 +- .../src/download/impl/ConnectionImpl.java | 17 +- 4 files changed, 144 insertions(+), 109 deletions(-) diff --git a/group01/895457260/code/src/download/DownloadThread.java b/group01/895457260/code/src/download/DownloadThread.java index 2ec27810d7..3f132c3518 100644 --- a/group01/895457260/code/src/download/DownloadThread.java +++ b/group01/895457260/code/src/download/DownloadThread.java @@ -1,6 +1,7 @@ package download; import download.api.Connection; +import download.api.DownloadException; import java.io.File; import java.io.FileNotFoundException; @@ -12,55 +13,42 @@ public class DownloadThread extends Thread { int startPos; int endPos; - File targetFile; + File tempFile; OnCompleteListener onComplete; OnFailListener onFail; - public DownloadThread(Connection conn, int startPos, int endPos, File targetFile, + + public DownloadThread(Connection conn, int startPos, int endPos, File tempFile, OnCompleteListener onComplete, OnFailListener onFail) { this.conn = conn; this.startPos = startPos; this.endPos = endPos; - this.targetFile = targetFile; + this.tempFile = tempFile; this.onComplete = onComplete; this.onFail = onFail; } @Override public void run() { - boolean success = false; int maxFailCount = 5; int failCount = 0; + boolean success = false; while (!success) { - FileOutputStream fos = null; try { - fos = new FileOutputStream(targetFile); - tryDownload(fos); - success = true; - } catch (FileNotFoundException e) { - e.printStackTrace(); - } catch (IOException e) { + success = tryDownload(); + } catch (DownloadException e) { if (failCount < maxFailCount) { failCount++; - try { - recreateFile(fos, targetFile); - } catch (IOException e1) { - e1.printStackTrace(); - } + retry(); } else { break; } - } finally { - if (fos != null) { - try { - fos.close(); - } catch (IOException e) { - e.printStackTrace(); - } - } } } + callback(success); + } + private void callback(boolean success) { if (onComplete != null) { if (success) { onComplete.onComplete(); @@ -70,15 +58,42 @@ public void run() { } } - private void recreateFile(FileOutputStream old, File file) throws IOException { - if (old != null) { - old.close(); - } + private boolean tryDownload() throws DownloadException { + FileOutputStream fos = null; + try { + fos = new FileOutputStream(tempFile); + download(fos); + return true; + } catch (FileNotFoundException e) { + e.printStackTrace(); + } catch (IOException e) { + throw new DownloadException(); + } finally { + if (fos != null) { + try { + fos.close(); + } catch (IOException e) { + e.printStackTrace(); + } + } + } + return false; + } + + private void retry() { + try { + recreateFile(tempFile); + } catch (IOException e1) { + e1.printStackTrace(); + } + } + + private void recreateFile(File file) throws IOException { file.delete(); file.createNewFile(); } - private void tryDownload(FileOutputStream fos) throws IOException { + private void download(FileOutputStream fos) throws IOException { int bufSize = 1024; int from = startPos; while (from < endPos) { @@ -93,6 +108,7 @@ private void tryDownload(FileOutputStream fos) throws IOException { public interface OnCompleteListener { void onComplete(); } + public interface OnFailListener { void onFail(); } diff --git a/group01/895457260/code/src/download/FileDownloader.java b/group01/895457260/code/src/download/FileDownloader.java index 38a1b6940b..d9b1c4f0f7 100644 --- a/group01/895457260/code/src/download/FileDownloader.java +++ b/group01/895457260/code/src/download/FileDownloader.java @@ -3,9 +3,6 @@ import download.api.*; import java.io.*; -import java.net.MalformedURLException; -import java.net.URL; -import java.net.URLConnection; import java.util.Date; @@ -14,6 +11,8 @@ public class FileDownloader { DownloadListener listener; ConnectionManager manager; + private final int[] completedThreadCount = new int[1]; + public FileDownloader(String url) { this.url = url; } @@ -32,65 +31,29 @@ public void execute() { // 4. 所有的线程都下载完成以后, 需要调用listener的notifiedFinished方法 // 下面的代码是示例代码, 也就是说只有一个线程, 你需要改造成多线程的。 - if (!Config.targetDirectory.exists()) { - Config.targetDirectory.mkdir(); - } - if (!Config.tempDirectory.exists()) { - Config.tempDirectory.mkdir(); - } - - int threadCount = 4; - File[] tempFiles = new File[threadCount]; - Connection[] connections = new Connection[threadCount]; - boolean[] threadComplete = new boolean[threadCount]; - for (int i = 0; i < threadCount; ++i) { - File targetFile = new File(Config.tempDirectory, - new Date().getTime() + "_" + i); - tempFiles[i] = targetFile; + new Thread(() -> { + initDirectories(); - Connection conn = null; - try { - conn = manager.open(this.url); - } catch (ConnectionException e) { - e.printStackTrace(); - } + int threadCount = 4; + File[] tempFiles = new File[threadCount]; + Connection[] connections = new Connection[threadCount]; + createMultiThread(threadCount, tempFiles, connections); - if (conn != null) { - connections[i] = conn; - int length = conn.getContentLength(); - int startPos = (int) (1.0 * length / threadCount * i); - int endPos = i == threadCount - 1 ? length : (int) (1.0 * length / threadCount * (i + 1)); - System.out.println(i + " start: " + startPos + " end: " + endPos); - final int index = i; - new DownloadThread(conn, startPos, endPos, targetFile, - () -> threadComplete[index] = true, () -> { - try { - downloadError(connections); - } catch (DownloadException e) { - e.printStackTrace(); - } - }).start(); - } - } + waitForComplete(threadCount); + mergeTempFiles(tempFiles); - // 等待下载完成 - while (true) { - boolean complete = true; - for (boolean b : threadComplete) { - complete = complete && b; - } - if (complete) { - break; - } else { - try { - Thread.sleep(1000); - } catch (InterruptedException e) { - e.printStackTrace(); + for (Connection c : connections) { + if (c != null) { + c.close(); } } - } + if (listener != null) { + listener.notifyFinished(); + } + }).start(); + } - // 合并临时文件 + private void mergeTempFiles(File[] tempFiles) { String[] split = url.replaceAll("/+", "/").split("/"); File saveFile = new File(Config.targetDirectory, split[split.length - 1]); FileOutputStream fos = null; @@ -98,7 +61,7 @@ public void execute() { fos = new FileOutputStream(saveFile); for (File tempFile : tempFiles) { write(tempFile, fos); - tempFile.delete(); + tempFile.delete(); // 只删除临时文件,不删除临时目录 } } catch (FileNotFoundException e) { e.printStackTrace(); @@ -110,20 +73,71 @@ public void execute() { e.printStackTrace(); } } - for (Connection c : connections) { - if (c != null) { - c.close(); + } + } + + private void waitForComplete(int threadCount) { + while (completedThreadCount[0] < threadCount) { + synchronized (completedThreadCount) { + if (completedThreadCount[0] < threadCount) { + try { + completedThreadCount.wait(); + } catch (InterruptedException e) { + e.printStackTrace(); + } } } } + } + + private void createMultiThread(int threadCount, File[] tempFiles, Connection[] connections) { + for (int i = 0; i < threadCount; ++i) { + File targetFile = new File(Config.tempDirectory, + new Date().getTime() + "_" + i); + tempFiles[i] = targetFile; - if (listener != null) { - listener.notifyFinished(); + Connection connection = connect(); + if (connection != null) { + connections[i] = connection; + int length = connection.getContentLength(); + int startPos = (int) (1.0 * length / threadCount * i); + int endPos = i == threadCount - 1 ? length : (int) (1.0 * length / threadCount * (i + 1)); + new DownloadThread(connection, startPos, endPos, targetFile, () -> { + synchronized (completedThreadCount) { + completedThreadCount[0]++; + completedThreadCount.notifyAll(); + } + }, () -> { + try { + downloadFailed(connections); + } catch (DownloadException e) { + e.printStackTrace(); + } + }).start(); + } } } + private Connection connect() { + Connection conn = null; + try { + conn = manager.open(this.url); + } catch (ConnectionException e) { + e.printStackTrace(); + } + return conn; + } - private void downloadError(Connection[] connections) throws DownloadException { + private void initDirectories() { + if (!Config.targetDirectory.exists()) { + Config.targetDirectory.mkdir(); + } + if (!Config.tempDirectory.exists()) { + Config.tempDirectory.mkdir(); + } + } + + private void downloadFailed(Connection[] connections) throws DownloadException { for (Connection c : connections) { c.close(); } @@ -165,16 +179,4 @@ public void setConnectionManager(ConnectionManager manager){ public DownloadListener getListener(){ return this.listener; } - - public static void main(String[] args) { - try { - URL url = new URL("file:///E:/Video/download/88993.mp4"); - System.out.println(url.getProtocol() + " " + url.getHost() + " " + url.getPort() - + " " + url.getPath() + " " + url.getFile()); - URLConnection c = url.openConnection(); - System.out.println(c.getContentLength()); - } catch (IOException e) { - e.printStackTrace(); - } - } } diff --git a/group01/895457260/code/src/download/FileDownloaderTest.java b/group01/895457260/code/src/download/FileDownloaderTest.java index f8a715ac2a..0615c47702 100644 --- a/group01/895457260/code/src/download/FileDownloaderTest.java +++ b/group01/895457260/code/src/download/FileDownloaderTest.java @@ -2,6 +2,7 @@ import download.FileDownloader; import org.junit.After; +import org.junit.Assert; import org.junit.Before; import org.junit.Test; @@ -9,6 +10,11 @@ import download.api.DownloadListener; import download.impl.ConnectionManagerImpl; +import java.io.*; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; + public class FileDownloaderTest { boolean downloadFinished = false; @Before @@ -23,7 +29,8 @@ public void tearDown() throws Exception { public void testDownload() { // String url = "http://localhost:8080/test.jpg"; - String url = "file:///E:/Video/download/88993.mp4"; +// String url = "file:///E:/Video/download/88993.mp4"; + String url = "file:///E:/Pictures/Clannad/Clannad高清图片/38.jpg"; FileDownloader downloader = new FileDownloader(url); @@ -57,5 +64,4 @@ public void notifyFinished() { } - } diff --git a/group01/895457260/code/src/download/impl/ConnectionImpl.java b/group01/895457260/code/src/download/impl/ConnectionImpl.java index 78ca55198a..74f3d169d7 100644 --- a/group01/895457260/code/src/download/impl/ConnectionImpl.java +++ b/group01/895457260/code/src/download/impl/ConnectionImpl.java @@ -12,10 +12,14 @@ public class ConnectionImpl implements Connection { private InputStream inputStream; ConnectionImpl(String url) throws ConnectionException { + init(url); + } + + private void init(String url) { try { connection = new URL(url).openConnection(); inputStream = connection.getInputStream(); - inputStream.mark(connection.getContentLength()); + inputStream.mark(connection.getContentLength()); // 标记在开头 } catch (IOException e) { e.printStackTrace(); } @@ -23,8 +27,8 @@ public class ConnectionImpl implements Connection { @Override public byte[] read(int startPos, int endPos) throws IOException { - inputStream.reset(); - inputStream.skip(startPos); + inputStream.reset(); // reset回到标记处 + skipBytes(startPos); byte[] bytes = new byte[endPos - startPos]; int n = inputStream.read(bytes); return n == -1 ? new byte[0] : bytes; @@ -45,4 +49,11 @@ public void close() { } } } + + // InputStream.skip(long)实际跳过的字节数经常小于参数值,但不会大于参数值 + private void skipBytes(long n) throws IOException { + while (n > 0) { + n -= inputStream.skip(n); + } + } } From 1ed4c71f5c05af0c0a9d81edae66fef5bfff7e28 Mon Sep 17 00:00:00 2001 From: Haochen Date: Wed, 8 Mar 2017 16:49:23 +0800 Subject: [PATCH 09/11] delete unused codes --- .../src/datastructure/basic/ArrayList.java | 52 ------------------- 1 file changed, 52 deletions(-) diff --git a/group01/895457260/code/src/datastructure/basic/ArrayList.java b/group01/895457260/code/src/datastructure/basic/ArrayList.java index 28eb439c1b..82c6ac6b1c 100644 --- a/group01/895457260/code/src/datastructure/basic/ArrayList.java +++ b/group01/895457260/code/src/datastructure/basic/ArrayList.java @@ -81,56 +81,4 @@ private void checkIndex(int index) { private String indexOutOfBoundMessage(int index) { return "index: " + index + ", size: " + size(); } - - public static void main(String[] args) { - ArrayList list = new ArrayList(); - for (int i = 0; i < 10; ++i) { - list.add(i); - list.add(10 - i); - } - System.out.println("------------------size"); - System.out.println("size: " + list.size()); - - System.out.println("------------------for(int i)"); - for (int i = 0; i < list.size(); ++i) { - System.out.print(list.get(i) + " "); - } - - System.out.println("\n-----------------iterator"); - Iterator iterator = list.iterator(); - while (iterator.hasNext()) { - System.out.print(iterator.next() + " "); - } - - System.out.println("\n-----------------add at index 0 100~104"); - for (int i = 100; i < 105; ++i) { - list.add(0, i); - } - list.print(); - System.out.println("-----------------add at last 200~204"); - for (int i = 200; i < 205; ++i) { - list.add(list.size(), i); - } - list.print(); - - System.out.println("-----------------removeFirst x4"); - for (int i = 0; i < 4; ++i) { - list.remove(0); - } - list.print(); - - System.out.println("\n-----------------removeLast x4"); - for (int i = 0; i < 4; ++i) { - list.remove(list.size() - 1); - } - list.print(); - } - - public void print() { - Iterator iterator = iterator(); - while (iterator.hasNext()) { - System.out.print(iterator.next() + " "); - } - System.out.println("\nsize: " + size()); - } } From b43a17d1c6b5818be0ee16b5384ca7229d2ecca4 Mon Sep 17 00:00:00 2001 From: Haochen Date: Wed, 8 Mar 2017 17:21:05 +0800 Subject: [PATCH 10/11] add linkedlist algorithm & test --- .../src/datastructure/basic/LinkedList.java | 27 ++-- .../datastructure/test/LinkedListTest.java | 121 ++++++++++++++++++ 2 files changed, 138 insertions(+), 10 deletions(-) diff --git a/group01/895457260/code/src/datastructure/basic/LinkedList.java b/group01/895457260/code/src/datastructure/basic/LinkedList.java index b59e72c90a..f99ee4dd67 100644 --- a/group01/895457260/code/src/datastructure/basic/LinkedList.java +++ b/group01/895457260/code/src/datastructure/basic/LinkedList.java @@ -189,9 +189,10 @@ public void removeFirstHalf(){ public void remove(int i, int length){ Node preI = findNode(i - 1); Node removeTo = findNode(i + length - 1); - head.next = removeTo.next; + Node removeFrom = preI.next; + preI.next = removeTo.next; removeTo.next = null; - size -= clearLink(preI); + size -= clearLink(removeFrom); } /** * 假定当前链表和list均包含已升序排列的整数 @@ -205,20 +206,25 @@ public Object[] getElements(LinkedList list){ Object[] result = new Object[list.size()]; int count = 0; - Node nodeI = head.next; Node nodeJ = list.head.next; - for (int i = 0; i < size() && count < result.length; ++i) { - if (i == (int) nodeJ.data) { - result[count] = nodeI; + for (int i = 0; nodeI != null && nodeJ != null; ++i) { + int compare = i - (int) nodeJ.data; + if (compare == 0) { + result[count] = nodeI.data; count++; nodeI = nodeI.next; nodeJ = nodeJ.next; - } else { + } else if (compare < 0) { nodeI = nodeI.next; + } else { + nodeJ = nodeJ.next; + i--; } } - return result; + Object[] trueResult = new Object[count]; + System.arraycopy(result, 0, trueResult, 0, count); + return trueResult; } /** @@ -295,12 +301,13 @@ public LinkedList intersection(LinkedList list){ } else if (compare > 0) { node = node.next; } else { - temp[count++] = (int) node.data; + temp[count] = (int) node.data; + count++; inThis = inThis.next; node = node.next; } } - for (int i = count; i >= 0; --i) { + for (int i = count - 1; i >= 0; --i) { result.addFirst(temp[i]); } return result; diff --git a/group01/895457260/code/src/datastructure/test/LinkedListTest.java b/group01/895457260/code/src/datastructure/test/LinkedListTest.java index 43e080258c..f4517dd3b9 100644 --- a/group01/895457260/code/src/datastructure/test/LinkedListTest.java +++ b/group01/895457260/code/src/datastructure/test/LinkedListTest.java @@ -85,4 +85,125 @@ public void testRemoveLast() throws Exception { Assert.assertArrayEquals(exceptions, new boolean[]{false, false, false, false, false, true, true}); Assert.assertArrayEquals(toArray(list), new Object[0]); } + + /** + * + * Method: reverse() + * + */ + @Test + public void testReverse() throws Exception { +//TODO: Test goes here... + LinkedList list = (LinkedList) getList(); + list.reverse(); + Assert.assertArrayEquals(toArray(list), new Object[] {5, 4, 3, 2, 1}); + } + + /** + * + * Method: removeFirstHalf() + * + */ + @Test + public void testRemoveFirstHalf() throws Exception { +//TODO: Test goes here... + LinkedList list = (LinkedList) getList(); + list.removeFirstHalf(); + Assert.assertArrayEquals(toArray(list), new Object[] {3, 4, 5}); + } + + /** + * + * Method: remove(int i, int length) + * + */ + @Test + public void testRemoveForILength() throws Exception { +//TODO: Test goes here... + LinkedList list = (LinkedList) getList(); + list.remove(1, 3); + Assert.assertArrayEquals(toArray(list), new Object[] {1, 5}); + } + + /** + * + * Method: getElements(LinkedList list) + * + */ + @Test + public void testGetElements() throws Exception { +//TODO: Test goes here... + LinkedList list = (LinkedList) getList(); + LinkedList indexList = new LinkedList(); + for (int i = 0; i < 3; ++i) { + indexList.add(2 * i); + } + Object[] elements = list.getElements(indexList); + Assert.assertArrayEquals(elements, new Object[] {1, 3, 5}); + } + + /** + * + * Method: subtract(LinkedList list) + * + */ + @Test + public void testSubtract() throws Exception { +//TODO: Test goes here... + LinkedList list = (LinkedList) getList(); + LinkedList removeList = new LinkedList(); + for (int i = 0; i < 3; ++i) { + removeList.add(2 * i); + } + list.subtract(removeList); + Assert.assertArrayEquals(toArray(list), new Object[] {1, 3, 5}); + } + + /** + * + * Method: removeDuplicateValues() + * + */ + @Test + public void testRemoveDuplicateValues() throws Exception { +//TODO: Test goes here... + LinkedList list = (LinkedList) getList(); + list.add(5); + list.add(6); + list.add(8); + list.add(8); + list.add(9); + list.removeDuplicateValues(); + Assert.assertArrayEquals(toArray(list), new Object[] {1, 2, 3, 4, 5, 6, 8, 9}); + } + + /** + * + * Method: removeRange(int min, int max) + * + */ + @Test + public void testRemoveRange() throws Exception { +//TODO: Test goes here... + LinkedList list = (LinkedList) getList(); + list.removeRange(2, 5); + Assert.assertArrayEquals(toArray(list), new Object[] {1, 2, 5}); + } + + /** + * + * Method: intersection(LinkedList list) + * + */ + @Test + public void testIntersection() throws Exception { +//TODO: Test goes here... + LinkedList list = (LinkedList) getList(); + LinkedList list1 = new LinkedList(); + for (int i = 0; i < 4; ++i) { + list1.add(2 * i); + } + LinkedList result = list.intersection(list1); + Assert.assertArrayEquals(toArray(result), new Object[] {2, 4}); + } } From 58d3631218cac356057f3fdd59d7c4d04f032a05 Mon Sep 17 00:00:00 2001 From: Haochen Date: Wed, 8 Mar 2017 17:37:57 +0800 Subject: [PATCH 11/11] add linkedlist algorithm test --- .../src/datastructure/basic/LinkedList.java | 6 ++- .../datastructure/test/LinkedListTest.java | 43 +++++++++++++++++++ 2 files changed, 47 insertions(+), 2 deletions(-) diff --git a/group01/895457260/code/src/datastructure/basic/LinkedList.java b/group01/895457260/code/src/datastructure/basic/LinkedList.java index f99ee4dd67..5dfa11fcb4 100644 --- a/group01/895457260/code/src/datastructure/basic/LinkedList.java +++ b/group01/895457260/code/src/datastructure/basic/LinkedList.java @@ -1,7 +1,6 @@ package datastructure.basic; import datastructure.exception.EmptyListException; -import javafx.util.Pair; import java.util.Objects; @@ -186,7 +185,10 @@ public void removeFirstHalf(){ * @param i * @param length */ - public void remove(int i, int length){ + public void remove(int i, int length) { + if (length <= 0) { + return; + } Node preI = findNode(i - 1); Node removeTo = findNode(i + length - 1); Node removeFrom = preI.next; diff --git a/group01/895457260/code/src/datastructure/test/LinkedListTest.java b/group01/895457260/code/src/datastructure/test/LinkedListTest.java index f4517dd3b9..d82cfa6ed5 100644 --- a/group01/895457260/code/src/datastructure/test/LinkedListTest.java +++ b/group01/895457260/code/src/datastructure/test/LinkedListTest.java @@ -206,4 +206,47 @@ public void testIntersection() throws Exception { LinkedList result = list.intersection(list1); Assert.assertArrayEquals(toArray(result), new Object[] {2, 4}); } + + @Test + public void testMultiMethod() throws Exception { + LinkedList list = (LinkedList) getList(); + LinkedList subtractList = new LinkedList(); + for (int i = 0; i < 3; ++i) { + subtractList.add(2 * i); + } + LinkedList intersectionList = new LinkedList(); + for (int i = 0; i < 4; ++i) { + intersectionList.add(2 * i); + } + + list.reverse(); + list.subtract(subtractList); + Assert.assertArrayEquals(toArray(list), new Object[] {5, 4, 3, 2, 1}); + LinkedList intersection = list.intersection(intersectionList); + Assert.assertArrayEquals(toArray(intersection), new Object[] {}); + list.reverse(); + list.add(6); + list.add(6); + list.add(6); + list.add(7); + list.add(7); + list.add(8); + list.add(9); + list.add(9); + list.add(9); + list.add(10); + list.add(11); + list.removeDuplicateValues(); + Assert.assertArrayEquals(toArray(list), new Object[] {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11}); + list.remove(0, 0); + list.remove(0, 2); + Assert.assertArrayEquals(toArray(list), new Object[] {3, 4, 5, 6, 7, 8, 9, 10, 11}); + list.removeRange(0, 3); + list.removeRange(11, 13); + list.removeRange(11, 8); + list.removeRange(8, 11); + Assert.assertArrayEquals(toArray(list), new Object[] {3, 4, 5, 6, 7, 8, 11}); + list.removeFirstHalf(); + Assert.assertArrayEquals(toArray(list), new Object[] {6, 7, 8, 11}); + } }