不论是用链表实现还是用数组实现,栈只需要1个指针。
不论是链表实现还是用数组实现,队列需要2个指针。
Stack 栈
用链表实现栈 ✅
用链表实现的栈,添加和删除一个结点都是在队列头完成的,即:队列头为栈顶,队列尾为栈底。
内部类Node
Node作为一个内部私有类被包含在栈的实现中
public class LinkedStackOfStrings
{
private Node first = null; // 首结点
private class Node // 内部类,一个Node对象即为一个结点
{
String item;
Node next;
}
public boolean isEmpty()
{ return first == null; }
public void push(String item)
{ /* code is below */ }
public String pop()
{ /* code is below */ }
Pop操作实现
public String pop()
{
String item = first.item;
first = first.next;
return item;
}
Push操作实现
public void push(string item) {
Node oldfirst = first;
first = new Node();
first.item = item;
first.next = oldfirst;
}
链表实现栈的性质:
用数组实现栈
容量N:指向数组中第一个空元素null
drawback
- 因为必须事先声明数组的长度,则用数组实现的栈的容量在被创建时就被确定了,如果栈的元素数量大于栈的容量会发生溢出,这个问题需要解决
- 还要考虑Java中会出现的对象游离(loitering),即在栈的数组中有对象的引用,而我们并未真正使用它,如果不做操作修正,Java的垃圾回收器不会启动【下图附解决方法,把数组中要被去除的元素对应的项设置为null,这样就不会剩下旧元素的引用,因为不存在引用了,垃圾回收器就能回收这部分内存】
对drawback 1的解决
方案1:每次数组的大小只添加/减少1(not prefer,因为可能会出现抖动)
抖动:一次添加一个元素,旧数组大小为N-1,旧数组元素要被全部复制到新数组中(N-1次访问),再把新元素复制到新数组队尾(1次访问)。
所以对前N次元素的添加,复杂度为 1+2+3=…+N ~ N^2/2
方案2:数组满时,数组大小double;数组pop到1/4时,数组大小减半
能有效防止方案1中的抖动情况
Queue 队列
头 first/head:元素进入队列的位置
尾 last/tail: 元素出队列的位置
用链表实现
data structure
- 一个指向队头的first指针
- 一个指向队尾的last指针
implementation
- dequeue:take from the beginning 删除队头的元素(边界:删到没有元素,null赋值给last)
- enqueue:add to the end 在队尾添加元素(边界:链表添加前为空,last赋值给first)
用数组实现
。。。
背包 ✅
= 没有pop操作的栈 / 没有dequeue操作的队列
Genetics 泛型 ✅已写完笔记
在创建一个有泛型的类时,是无法直接创建一个Item[]数组的,而必须先声明一个Object[]数组,然后强制类型转换成Item[](lecturer说强制类型转换是ugly的,在其他代码编写中要尽量避免),这样会不可避免有一个warning,但这是Java语言本身的问题,这不可避免
❌错误的写法⬇️
✅正确的写法⬇️
不可避免的warning⬇️
Autoboxing
不能用基础类型作为泛型,必须使用其对应的封装类wrapper object type作为参数传进泛型
基础类型 Primitive Type | 封装类 Wrapper Object Type |
---|---|
boolean | Boolean |
byte | Byte |
char | Character |
short | Short |
int | Integer |
long | Long |
float | Float |
double | Double |
Autoboxing. Automatica cast between a primitive type and its wrapper.
autoboxing:自动地在基础类型和封装类型进行互相转换。
interface Iterable “has a” Iterator
⬇️from ADVANCED JAVA.pdf
Stack<String> stack = new Stack<>();
...
for (String s : stack) {
...
}
↕️等于
Stack<String> stack = new Stack<>();
...
Iterator<String> iterator = stack.iterator();
while (iterator.hasNext() {
String s = iterator.next();
...
}
- interface Iterable需要实现方法Iterator iterator()和一个实现借口interface Iterator的内部类。
⬇️ - Iterator需要实现的变量和方法:
- private Node current;
- public boolean hasNext() // 判断是否还有下一个节点
- public Item next() // 将current(当前节点)移动到下一个节点
- (public void remove() // optional(本课程不实现))
import java.util.Iterator;
public class Stack<Item> implements Iterable<Item>
{
...
public Iterator<Item> iterator() { return new ListIterator(); }
private class ListIterator implements Iterator<Item>
{
private Node current = first;
public boolean hasNext() { return current != null; }
public Item next()
{
Item item = current.item;
current = current.next;
return item;
}
public void remove() { /* optional, not supported */ }
}
}
Modifier and Type | Method and Description |
---|---|
Iterator | iterator() : Returns an iterator over elements of type T. |