先进先出队列-《算法》(第四版)学习笔记
在1.3节有关“背包、队列和栈”的学习中发现了算法1.3代码中有两行略微费解,而书中对此并无明确解释:
import edu.princeton.cs.algs4.StdOut; public class Queue<T> { private int N; private Node first; private Node last; private class Node{ T item; Node next; } public boolean isEmpty(){ return N==0; } public int size(){ return N; } public void enqueue(T item){ Node oldlast=last; last=new Node(); last.item=item; if (isEmpty()) first=last; //① else oldlast.next=last; N++; } public T pop(){ T item=first.item; first=first.next; if (isEmpty()) last=null;//② N--; return item; } public static void main (String[] args){ Queue<String> q=new Queue<>(); q.enqueue("hello"); q.enqueue("hell"); StdOut.println(q.pop()); StdOut.println(q.pop()); StdOut.println(q.last.item); } }
在后续的测试中我发现,①与②的判断逻辑是紧密关联的。先说enqueue方法:
由于first和last的默认值都是null,当last被初始化后,first的值仍然是null,此时first中item为空,next亦无指向。若不加上isEmpty判断的话,第一次调用enqueue方法后立即调用pop方法会引发NullPointerException。显然在节点中已经赋予一个有效值的情况下出现这种状况既不符合逻辑,更不是我们想要的。由pop方法的调用,我们看到是first值为null造成的,既然此时节点中已经有一个值(这个值被赋予了last)了,那自然是first=last;
而对于②,测试代码的最后一行显示,在队列弹出最后一个元素是,由于first=first.next, first.next的指向null(这没问题),但是first为空了,表明队列中已经没有元素了,可是此时last仍然持有原有的引用,依然可以用last.item访问到内容。这是不应该的,故而当判断isEmty为真后,last=null;是必须的。
另外再吐槽一下80页Dijkstra双栈算术表达式求值法,作者使用这个算法为例也许是为了让读者更好地理解栈的运用。不过这个示例本身有两点缺陷:1、只能用来计算非常严格的带有括号的表达式的值,这里的严格指的是(1+2+3)这样的表达式是计算不出来的,只能写成(1+(2+3))。2、在控制台输入表达式的时候必须加空格,比如(1+(2+3))这样是计算不出来的,只能写成( 1 + ( 2 + 3 ) )。