问题
Deque。一个双向队列(或者称为deque)和栈或队列类似,但它同时支持在两端添加或删除元素。Deque能够存储一组元素并支持如下API。
/** * ----------------------------------------------------- * public class Deque<Item> implements Iterable<Item> * ----------------------------------------------------- * Deque() 创建空双向队列 * boolean isEmpty() 双向队列是否为空 * int size() 双向队列中元素的数量 * void pushLeft(Item item) 向左端添加一个新元素 * void pushRight(Item item) 向右端添加一个新元素 * Item popLeft() 从左羰删除一个元素 * Item popRight() 从右羰删除一个元素 * ----------------------------------------------------- */编写一个使用双向链表实现这份API的Deque类。以及一个使用动态数据组调整实现这份API的ResizingArrayDeque类。
解决思路
该问题解决起来并不难。使用双向链表时需要注意每个结点的双向引用,不要只添加单向的引用或者只删除单向的引用。使用动态数组时注意,何时调整数组的大小以及将数组大小调整为多大。本实现添加元素时,只有在头部或者尾部没有空间时,才进行调整,调整为队列中元素的个数的3倍,前后各留队列中元素个数的长度。在删除元素,当元素的数量小于总长度的1/6时,进行调整,将长度调整为元素个数的3倍,同样前后各留元素个数的长度。注意最小不小于3。
代码
一共三个文件,分别为Deque类,ResizingArrayDeque类和测试文件E10333类。
Deque类。
package com.furzoom.lab.algs.ch103; import java.util.Iterator; /** * ----------------------------------------------------- * public class Deque<Item> implements Iterable<Item> * ----------------------------------------------------- * Deque() 创建空双向队列 * boolean isEmpty() 双向队列是否为空 * int size() 双向队列中元素的数量 * void pushLeft(Item item) 向左端添加一个新元素 * void pushRight(Item item) 向右端添加一个新元素 * Item popLeft() 从左羰删除一个元素 * Item popRight() 从右羰删除一个元素 * ----------------------------------------------------- */ public class Deque<Item> implements Iterable<Item> { private Node head = null; private Node tail = null; private int size = 0; private class Node { public Item item; public Node prev; public Node next; } public boolean isEmpty() { return head == null; } public int size() { return size; } public void pushLeft(Item item) { Node node = new Node(); node.item = item; node.prev = null; if (isEmpty()) { head = tail = node; node.next = null; } else { head.prev = node; node.next = head; head = node; } size++; } public void pushRight(Item item) { Node node = new Node(); node.item = item; node.next = null; if (isEmpty()) { head = tail = node; node.prev = null; } else { tail.next = node; node.prev = tail; tail = node; } size++; } public Item popLeft() { if (isEmpty()) { return null; } else { Item e = head.item; if (size() == 1) { head = tail = null; } else { head = head.next; head.prev.next = null; head.prev = null; } size--; return e; } } public Item popRight() { if (isEmpty()) { return null; } else { Item e = tail.item; if (size() == 1) { head = tail = null; } else { tail = tail.prev; tail.next.prev = null; tail.next = null; } size--; return e; } } @Override public Iterator<Item> iterator() { return new Iter(); } private class Iter implements Iterator<Item> { private Node current = head; @Override public boolean hasNext() { return current != null; } @Override public Item next() { Item e = current.item; current = current.next; return e; } } }
ResizingArrayDeque类。
package com.furzoom.lab.algs.ch103; import java.util.Iterator; public class ResizingArrayDeque<Item> implements Iterable<Item> { private int head; private int tail; private Item[] deque; @SuppressWarnings("unchecked") public ResizingArrayDeque() { deque = (Item[])new Object[3]; head = 1; tail = 1; } public boolean isEmpty() { return head == tail; } public int size() { return tail - head; } public void pushLeft(Item item) { if (head == 0) { resize(3 * size()); } deque[--head] = item; } public void pushRight(Item item) { if (tail == deque.length) { resize(3 * size()); } deque[tail++] = item; } public Item popLeft() { if (isEmpty()) { return null; } if (size() * 6 < deque.length) { resize(size() * 3); } return deque[head++]; } public Item popRight() { if (isEmpty()) { return null; } if (size() * 6 < deque.length) { resize(size() * 3); } return deque[--tail]; } @SuppressWarnings("unchecked") private void resize(int size) { if (size < 3) { size = 3; } Item tmp[] = (Item[])new Object[size]; int j = size / 3; for (int i = head; i < tail; i++) { tmp[j++] = deque[i]; } deque = tmp; head = size / 3; tail = j; } @Override public Iterator<Item> iterator() { return new Iter(); } private class Iter implements Iterator<Item> { private int current = head; @Override public boolean hasNext() { return current < tail; } @Override public Item next() { Item e = deque[current++]; return e; } } }
测试代码:
package com.furzoom.lab.algs.ch103; import java.util.Iterator; public class E10333 { public static void main(String[] args) { // Deque<String> deque = new Deque<String>(); ResizingArrayDeque<String> deque = new ResizingArrayDeque<String>(); deque.pushLeft("c"); deque.pushLeft("b"); deque.pushRight("d"); deque.pushRight("e"); System.out.println("deque size: " + deque.size()); Iterator<String> it = deque.iterator(); while (it.hasNext()) { System.out.println(it.next()); } System.out.println("Pop up from right: "); while (!deque.isEmpty()) { System.out.println(deque.popRight()); } deque.pushLeft("c"); deque.pushLeft("b"); deque.pushRight("d"); deque.pushRight("e"); System.out.println("Pop up from left: "); while (!deque.isEmpty()) { System.out.println(deque.popLeft()); } } }
结果
deque size: 4 b c d e Pop up from right: e d c b Pop up from left: b c d e