CS61B Proj1: Dqeue Data Structures
介绍
Proj1 主要分为两个部分:
- 数据结构部分
创建LinkedListDeque.java 和 ArrayDeque.java 文件. 对应两种不同的实现.
并且使用Lab3中学到的测试方法验证其正确性.
当本部分完成之后, 可以使用Proj0 CheckPoint 检查其正确性.
- 应用程序部分
创建MaxArrayDeque.java, 并实现能够播放Guitar Hero的声音合成器.
Packages
概念:
包是Java类的集合, 用于协同实现一个目标. 诸如, org.Junit是一个包. Assert是一个类, 其中的assert方法是里面的方法.
方法:
- 创建包时, 我们只需要在文件顶部制定代码是包的一部分即可.
package deque;
- 使用包时, 只需要引用包即可. 包本质上知识计算机中的某个文件夹.
import deque;
The Deque API
概念:
Deqeue: doubled-ended queue. 双端队列.
双端队列是一个具有动态大小的容器, 可以在其两端收缩或者扩展.
我们需要实现的方法:
-
public void addFirst(T item)
-
public void addLast(T item)
-
public boolean isEmpty()
-
public int size()
-
public void printDeque()
-
public T removeFirst()
-
public T removeLast()
-
public T get(int index)
-
public Iterator iterator()
-
public boolean equals(Object o)
要求:
-
我们不应该让Deque接口实现Iterable, 而应该让其子类实现
-
我们需要编写两种不同的子类:
- 链表
- 可以调整大小的数组
-
我们编写的子类, 应该接受任何泛型类型.
Project Tasks
Linked List Deque 链表双端队列
要求:
-
添加操作和删除操作不能使用递归, 单个操作花费的时间是恒定的.
-
get使用迭代, 而不能使用递归
-
size花费的时间也是恒定时间
-
for-each循环 花费时间和数量成正比
-
不要维护不存在于双端队列中的items的结点的引用, 即使用的内存量和项目数成正比.
-
不能使用导入数据结构
额外需要实现的方法:
- public LinkedListDeque()
- public T getRecursive(int index)
参考内容:
- 双向链表
方法实现:
首先, 建立一个链表.
回忆Lecture中学到的内容:
- 引用最后一个结点, addLast时间恒定
- 对于每一个结点, 引用前一个结点, removeLast时间恒定.
所以我们需要建立的是一个DDList(双向链表) + 且记录头尾结点. 同时使用的是循环链表(即prev指向最后的元素)
又因为size的花费时间也要求恒定, 所以我们建立一个size变量, 用于记录链表的长度.
public class LinkedListDeque<T> {
private int size;
private Node sentinel;
private static class Node<T> {
private Node prev;
private Node next;
private T item;
public Node(Node p, T i, Node n) {
prev = p;
item = i;
next = n;
}
}
}
1. LinkedListDeque()
首先我们准备完成的任务是构造函数.
public LinkedListDeque() {
sentinel = new Node(null, null, null);
sentinel.prev = sentinel;
sentinel.next = sentinel;
size = 0;
}
2. size()
其次则是size(), 用于返回链表的长度. 该方法直接返回记录了数据长度的size即可.
同时因为数据抽象, 我们将size设置为private私有属性.
public int size() {
return size;
}
3. isEmpty()
第三个是isEmpty(), 直接使用size判断就可以了.
public boolean isEmpty() {
return size == 0;
}
4, addFirst()
第四个实现的是增加第一个元素
public void addFirst(T item) {
// 后指的是第一个元素
Node add_node = new Node(sentinel, item, sentinel.next);
sentinel.next = add_node;
add_node.next.prev = add_node;
size += 1;
}
步骤:
- 建立新结点, 存储数据. 并建立和链表的关系
- 前面是sentinel
- 后面是第一个结点
- 重新设定链表结点间的关系
- sentinel后面的是该结点
- 原本第一个结点前面的是新建立的结点
- 链表的长度+1
5. addLast()
第五个方法是增加后一个元素
public void addLast(T item) {
// 前指的是第一个元素
Node new_node = new Node(sentinel.prev, item, sentinel);
sentinel.prev = new_node;
new_node.prev.next = new_node;
size += 1;
}
6. removeFirst()
第六个实现的是删除第一个元素
public T removeFirst() {
if (size == 0) {
return null;
}
Node removed_node = sentinel.next;
removed_node.next.prev = sentinel;
sentinel.next = removed_node.next;
size -= 1;
return (T) removed_node.item;
}
7. removeLast()
第7个实现的是删除最后一个元素
public T removeLast() {
if (size == 0) {
return null;
}
Node removed_node = sentinel.prev;
removed_node.prev.next = removed_node.next;
removed_node.next.prev = removed_node.prev;
size -= 1;
return (T) removed_node.item;
}
8. get
public T get(int i) {
if (i < 0 || i >= size) {
return null;
}
Node node = this.sentinel;
for (int j = 0; j <= i; j += 1) {
node = node.next;
}
return (T) node.item;
}
9. getRecursion()
public T getRecursive(int index) {
if (index < 0 || index >= size) {
return null;
}
return getRecursive_helper(index, sentinel.next);
}
public T getRecursive_helper(int index, Node node) {
if (index == 0) {
return (T) node.item;
}
return getRecursive_helper(index - 1, (Node) node.next);
}
10. iterator()
public Iterator<T> iterator() {
return new LinkedListDequeIterator<>();
}
public class LinkedListDequeIterator<T> implements Iterator<T> {
private int index;
private Node node;
public LinkedListDequeIterator() {
index = 0;
node = sentinel.next;
}
public boolean hasNext() {
return index < size;
}
public T next() {
T item = (T) node.item;
node = node.next;
index += 1;
return item;
}
}
11. printDeque()
public void printDeque() {
if (size == 0) {
return;
}
StringBuilder res = new StringBuilder("");
for (T e: this) {
res.append(e + " ");
}
System.out.println(res);
System.out.println("");
}
12. equals
public boolean equals(Object o) {
if (o.getClass() != this.getClass()) {
return false;
}
if (o == this) {
return true;
}
// 一个新的问题
LinkedListDeque linko = (LinkedListDeque) o;
if (linko.size() != size) {
return false;
}
for(int i = 0; i < size; i += 1) {
if (!get(i).equals(linko.get(i))) {
return false;
}
}
return true;
}