●queue 是一种数据结构,该数据结构允许在队头添加节点,然后在队尾删除一个项,以实现先进先出(FIFO)。
●在这个实验中,我们将创建一个更通用的数据结构,称为 deque,是双端队列的缩写。
●在一个 deque 中,您可以添加和删除两端的项(无论是其前端还是后端)。
○在本实验室,您将完成包括添加和删除在内的许多方法。
●此外,您必须使用通用类型,以便可以实例化 deque 来存储任何类型的对象。
我们将使用链表实现一个 deque,特别是循环链表。
●完成空的 deque 构造函数 public LLDeque()
●它创造了一个空的 deque
●完成方法 void addFirst(T item)。
●它将一个 T 型 item 添加到 deque 的前部。
●不得使用任何循环或递归。
●每次操作必须持续时间,即不取决于 deque 的 size。
提示:
●我们需要创建一个新节点,并将其立即放置在哨兵旁边
使用输入项创建一个新节点,其上一个点指向哨兵,下一个点指向哨兵之后的旧节点
●设置哨兵后旧节点的 prev 指向新节点
●设置下一个哨兵指向新节点
●增大 size
●完成方法 void printDeque()
●它将 deque 中的项目从头到尾 print 出来,用空格隔开,以新行结束。
提示:
●我们需要检查每一项并 print 出来
●项目从哨兵旁边开始,因此设置一个指针 p 指向它
●当 p 不返回哨兵时 ○使用 Print(非 println)print p 所指节点内的 item ○添加 spacebar ○移动 p 以指向下一个节点
●使用 println 添加新行
●迭代完成方法 T iterGet(int index)。
●它返回给定索引处的项,其中索引 0 是前端。如果不存在此类项,则返回 null。
●它必须使用循环,而不是递归。
●不得使 deque 突变。
提示:
●如果 deque 为空,或者索引无效(负数、大于或等于),则返回 null
●创建一个从哨兵的下一个开始的节点指针 p
●使用 for/while 移动指向 index-th 节点的指针
●返回 p 所指节点内的 item
●完成方法 void addLast(T item)。
●它在 deque 后面添加了一个 T 类型的 item。
●它不能使用任何循环或递归。
●每次操作必须持续时间,即不取决于 deque 的大小。
●完成方法 T delFirst()。
●删除并返回 deque 前面的项,如果不存在,则返回空。
●不得使用任何循环或递归。
●每次操作必须持续一段时间,即不取决于 deque 的大小。
●完成方法 T delLast()。
●删除并返回 deque 后面的项,如果不存在,则返回空。
●不得使用任何循环或递归。
●每次操作必须持续时间,即不取决于 deque 的大小。
●递归地完成方法 T recGet(int index)。
●它返回给定索引处的项,其中索引 0 是前端。如果不存在此类项,则返回 null。
●不得使用循环。
●不得使 deque 突变。
public class LLDeque {
private class Node {
Node prev;
T item;
Node next;
Node(Node p, T i, Node n) {
prev = p;
item = i;
next = n;
}
}
private Node sentinel;
private int size;
/**
* @return the number of items in the deque.
*/
public int size() {
return size;
}
/**
* @return true if deque is empty, false otherwise.
*/
public boolean isEmpty() {
return size == 0;
}
/*
***************************
* DO NOT MODIFY CODE ABOVE
***************************
*/
// EXERCISE 8.1 EMPTY CONSTRUCTOR
/**
* Creates an empty deque.
*/
public LLDeque() {
this.size = 0;
Node head = new Node(null, null, null);
head.prev = head;
head.next = head;
this.sentinel = head.next;
}
// EXERCISE 8.2 ADD TO FRONT
/**
* Adds an item of type T to the front of the deque.
* @param item is a type T object added to the deque.
*/
public void addFirst(T item) {
Node newNode = new Node(null, item, null);
newNode.prev = this.sentinel;
newNode.next = this.sentinel.next;
this.sentinel.prev = newNode.next;
this.sentinel.next = newNode;
this.size += 1;
}
// EXERCISE 8.3 PRINT ITEMS
/**
* Prints the items in the deque from first to last,
* separated by a space, ended with a new line.
*/
public void printDeque() {
Node p = this.sentinel.next;
while(p!=this.sentinel) {
System.out.print(p.item);
if(p.next!=this.sentinel) System.out.print(" ");
p = p.next;
}
System.out.print("\n");
}
// EXERCISE 8.4 ITERATIVE GET ITEM
/**
* Gets the item at the given index.
* If no such item exists, returns null.
* Does not mutate the deque.
* @param index is an index where 0 is the front.
* @return the ith item of the deque, null if it does not exist.
*/
public T iterGet(int index) {
if(this.sentinel==null||this.size<=0||index<0||index>=this.size) return null;
Node p = this.sentinel.next;
for(int i=0;i<=index;i++) {
if(index==i) return p.item;
p = p.next;
}
return null;
}
// ASSIGNMENT 8.1 ADD TO BACK
/**
* Adds an item of type T to the back of the deque.
* @param item is a type T object added to the deque.
*/
public void addLast(T item) {
Node newNode = new Node(null, item, null);
newNode.prev = this.sentinel.prev;
this.sentinel.prev.next = newNode;
this.sentinel.prev = newNode;
newNode.next = this.sentinel;
this.size += 1;
}
// ASSIGNMENT 8.2 DELETE FRONT
/**
* Deletes and returns the item at the front of the deque.
* If no such item exists, returns null.
* @return the first item of the deque, null if it does not exist.
*/
public T delFirst() {
if(this.sentinel==null||this.size<=0) {
return null;
}
T target = this.sentinel.next.item;
Node f1rst = this.sentinel.next;
Node next = this.sentinel.next.next;
next.prev = this.sentinel;
this.sentinel.next = next;
f1rst.next = null;
f1rst.prev = null;
this.size -= 1;
return target;
}
// ASSIGNMENT 8.3 DELETE BACK
/**
* Deletes and returns the item at the back of the deque.
* If no such item exists, returns null.
* @return the last item of the deque, null if it does not exist.
*/
public T delLast() {
if(this.sentinel==null||this.size<=0) {
return null;
}
Node last2Node = this.sentinel.prev.prev;
Node targetNode = this.sentinel.prev;
T target = targetNode.item;
last2Node.next = this.sentinel;
this.sentinel.prev = last2Node;
targetNode.next = null;
targetNode.prev = null;
return target;
}
// ASSIGNMENT 8.4 RECURSIVE GET ITEM
/**
* Gets the item at the given index.
* If no such item exists, returns null.
* Does not mutate the deque.
* @param index is an index where 0 is the front.
* @return the ith item of the deque, null if it does not exist.
*/
public T recGet(int index) {
return recHelper(index, 0, this.sentinel.next);
}
private T recHelper(int index,int now,Node n) {
if(this.sentinel==null||this.size<=0||index<0||index>=this.size) return null;
if(now==index) return n.item;
return recHelper(index, now+1, n.next);
}
public static void main(String[] args) {
LLDeque deque = new LLDeque<>();
deque.addFirst("b");
deque.addFirst("a");
deque.printDeque();
}
}