{"id":"linked-structures-stacks-queues","slug":"stacks-and-queues","title":"Stacks and queues on linked nodes","text":"Many programs don't need a list's `get(index)` at all. They only add and remove at the ends, and two ways of doing that have names of their own.\n\n### A stack: last in, first out\n\nA **stack** adds and removes at one end only, its **top**, like a pile of plates: the plate you put on last is the first you take off. Its operations are usually called `push` (put on top), `pop` (take the top one off and return it), `peek` (look at the top one without taking it) and `isEmpty`. The call stack (module 11, and module 55's recursion) is one: the newest call is on top, and it's the first to finish.\n\nOn linked nodes the top is the head: `push` is `addFirst`, and `pop` is `removeFirst`. Both take a few steps whatever the size. This stack of whole numbers gives back 1, 2, 3 and 4 in the opposite order:\n\n```java\npublic class Main {\n    public static void main(String[] args) {\n        NumberStack stack = new NumberStack();\n        for (int digit = 1; digit <= 4; digit++) {\n            stack.push(digit);\n        }\n        while (!stack.isEmpty()) {\n            System.out.print(stack.pop() + \" \");\n        }\n        System.out.println();\n    }\n}\n// ==== NumberStack.java ====\npublic class NumberStack {\n    private NumberNode top;\n\n    public void push(int value) {\n        this.top = new NumberNode(value, this.top);\n    }\n\n    public int pop() {\n        int value = this.top.value;\n        this.top = this.top.next;\n        return value;\n    }\n\n    public boolean isEmpty() {\n        return this.top == null;\n    }\n}\n// ==== NumberNode.java ====\npublic class NumberNode {\n    int value;\n    NumberNode next;\n\n    public NumberNode(int value, NumberNode next) {\n        this.value = value;\n        this.next = next;\n    }\n}\n```\n\n```output\n4 3 2 1\n```\n\nNumberStack has no constructor of its own, so Java gives it a default constructor that takes no parameters, and `top` starts as `null`, the default value of a reference variable. This `pop` crashes on an empty stack with a NullPointerException; a better one checks first and throws an exception with a clear message.\n\n### A queue: first in, first out\n\nA **queue** adds at one end, its back, and removes at the other, its front, like a line at a counter: whoever came first is served first. Its operations are often called `enqueue` (join at the back) and `dequeue` (leave from the front).\n\nOn linked nodes, the front is the head and the back is the tail, with the links pointing from front to back:\n\n```text\nhead                                   tail\n[report.pdf] --> [map.png] --> [menu.txt] --> null\n```\n\n- `enqueue` is step 2's `addLast`: link the new node after `tail`, and move `tail` to it.\n- `dequeue` is `removeFirst`: take the head's value, and move `head` to `head.next`. When the queue becomes empty, set `tail` to `null` as well.\n\nWhy not the other way round, adding at the head and removing at the tail? To remove the last node, a list must set the `next` of the node before it to `null`, and the only way to find that node is to walk from the head. With the links pointing front to back, both operations take a few steps.\n\n### Checking brackets with a stack\n\nBrackets in a formula must close in the opposite order to the one they opened in: `([])` is fine, `([)]` isn't. A stack checks this. Go through the characters one by one:\n\n- an opening bracket, `(`, `[` or `{`, is pushed;\n- a closing bracket must match the opening bracket on top of the stack, which is popped. If the stack is empty, or the top is the wrong kind, the brackets aren't balanced;\n- other characters are skipped.\n\nAt the end, the stack must be empty: anything left on it was never closed.\n","task":"An office keeps incoming letters in a tray, and the newest letter is always on top. In `InTray.java`, write a stack of Strings on linked nodes (the class `LetterNode` is ready), with:\n\n- `push(String letter)` puts a letter on top;\n- `pop()` takes the top letter off and returns it;\n- `peek()` returns the top letter without taking it off;\n- `isEmpty()` and `size()`.\n\n`pop` and `peek` on an empty tray throw an `IllegalStateException` with the message `The tray is empty`. The check runs:\n\n```java\nInTray tray = new InTray();\ntray.push(\"invoice\");\ntray.push(\"postcard\");\ntray.push(\"tax form\");\nSystem.out.println(tray.peek() + \", \" + tray.size() + \" letters\");\nSystem.out.println(tray.pop());\nSystem.out.println(tray.pop());\nSystem.out.println(tray.size() + \" \" + tray.isEmpty());\n```\n\nand expects:\n\n```\ntax form, 3 letters\ntax form\npostcard\n1 false\n```\n","kind":"code","seed":"// ==== InTray.java ====\npublic class InTray {\n\n}\n\n// ==== LetterNode.java ====\npublic class LetterNode {\n    String letter;\n    LetterNode next;\n\n    public LetterNode(String letter, LetterNode next) {\n        this.letter = letter;\n        this.next = next;\n    }\n}\n\n// ==== Main.java ====\npublic class Main {\n    public static void main(String[] args) {\n        InTray tray = new InTray();\n        tray.push(\"invoice\");\n        tray.push(\"postcard\");\n        tray.push(\"tax form\");\n        System.out.println(tray.peek() + \", \" + tray.size() + \" letters\");\n        System.out.println(tray.pop());\n        System.out.println(tray.pop());\n        System.out.println(tray.size() + \" \" + tray.isEmpty());\n    }\n}\n","solution":"// ==== InTray.java ====\npublic class InTray {\n    private LetterNode top;\n    private int size;\n\n    public InTray() {\n        this.top = null;\n        this.size = 0;\n    }\n\n    public void push(String letter) {\n        this.top = new LetterNode(letter, this.top);\n        this.size++;\n    }\n\n    public String pop() {\n        String letter = peek();\n        this.top = this.top.next;\n        this.size--;\n        return letter;\n    }\n\n    public String peek() {\n        if (this.top == null) {\n            throw new IllegalStateException(\"The tray is empty\");\n        }\n        return this.top.letter;\n    }\n\n    public boolean isEmpty() {\n        return this.top == null;\n    }\n\n    public int size() {\n        return this.size;\n    }\n}\n\n// ==== LetterNode.java ====\npublic class LetterNode {\n    String letter;\n    LetterNode next;\n\n    public LetterNode(String letter, LetterNode next) {\n        this.letter = letter;\n        this.next = next;\n    }\n}\n\n// ==== Main.java ====\npublic class Main {\n    public static void main(String[] args) {\n        InTray tray = new InTray();\n        tray.push(\"invoice\");\n        tray.push(\"postcard\");\n        tray.push(\"tax form\");\n        System.out.println(tray.peek() + \", \" + tray.size() + \" letters\");\n        System.out.println(tray.pop());\n        System.out.println(tray.pop());\n        System.out.println(tray.size() + \" \" + tray.isEmpty());\n    }\n}\n","hints":["Two instance variables: `private LetterNode top;` and `private int size;`. `push` is `this.top = new LetterNode(letter, this.top);` and one more in the size.","`peek` and `pop` both start with `if (this.top == null) { throw new IllegalStateException(\"The tray is empty\"); }`. `pop` then keeps `this.top.letter`, moves `top` to `this.top.next`, and lowers the size."],"tests":[{"name":"Test 1","stdin":"","call":"InTray tray = new InTray();\ntray.push(\"invoice\");\ntray.push(\"postcard\");\ntray.push(\"tax form\");\nSystem.out.println(tray.peek() + \", \" + tray.size() + \" letters\");\nSystem.out.println(tray.pop());\nSystem.out.println(tray.pop());\nSystem.out.println(tray.size() + \" \" + tray.isEmpty());\n","expect":"tax form, 3 letters\ntax form\npostcard\n1 false","hidden":false},{"name":"Test 2","stdin":"","call":"InTray tray = new InTray();\nSystem.out.println(tray.isEmpty() + \" \" + tray.size());\ntry {\n    tray.pop();\n} catch (IllegalStateException e) {\n    System.out.println(e.getMessage());\n}\ntry {\n    tray.peek();\n} catch (IllegalStateException e) {\n    System.out.println(e.getMessage());\n}\ntray.push(\"memo\");\nSystem.out.println(tray.pop() + \" \" + tray.isEmpty() + \" \" + tray.size());\ntray.push(\"bill\");\ntray.push(\"flyer\");\nSystem.out.println(tray.peek() + \" \" + tray.size());\n","expect":"true 0\nThe tray is empty\nThe tray is empty\nmemo true 0\nflyer 2","hidden":true}],"require":[{"pattern":"throw\\s+new\\s+IllegalStateException","message":"On an empty tray, throw an IllegalStateException: `throw new IllegalStateException(\"The tray is empty\");`."}],"forbid":[{"pattern":"\\b(ArrayList|LinkedList|ArrayDeque|Stack)\\b","message":"Build the stack on LetterNode objects, not on one of Java's collections."}],"more":[{"task":"An office printer prints documents in the order they were sent. In `PrintQueue.java`, write a queue of document names on linked nodes (`JobNode` is ready). Keep references to both the first node and the last one (`head` and `tail`), so that neither method walks through the queue:\n\n- `enqueue(String document)` adds a document at the back;\n- `dequeue()` removes the document at the front and returns it. On an empty queue it throws an `IllegalStateException` with the message `Nothing to print`;\n- `isEmpty()` and `size()`.\n\nThe check runs:\n\n```java\nPrintQueue queue = new PrintQueue();\nqueue.enqueue(\"report.pdf\");\nqueue.enqueue(\"map.png\");\nSystem.out.println(\"Printing \" + queue.dequeue());\nqueue.enqueue(\"menu.txt\");\nwhile (!queue.isEmpty()) {\n    System.out.println(\"Printing \" + queue.dequeue() + \", \" + queue.size() + \" left\");\n}\n```\n\nand expects:\n\n```\nPrinting report.pdf\nPrinting map.png, 1 left\nPrinting menu.txt, 0 left\n```\n","kind":"code","seed":"// ==== PrintQueue.java ====\npublic class PrintQueue {\n\n}\n\n// ==== JobNode.java ====\npublic class JobNode {\n    String document;\n    JobNode next;\n\n    public JobNode(String document) {\n        this.document = document;\n        this.next = null;\n    }\n}\n\n// ==== Main.java ====\npublic class Main {\n    public static void main(String[] args) {\n        PrintQueue queue = new PrintQueue();\n        queue.enqueue(\"report.pdf\");\n        queue.enqueue(\"map.png\");\n        System.out.println(\"Printing \" + queue.dequeue());\n        queue.enqueue(\"menu.txt\");\n        while (!queue.isEmpty()) {\n            System.out.println(\"Printing \" + queue.dequeue() + \", \" + queue.size() + \" left\");\n        }\n    }\n}\n","solution":"// ==== PrintQueue.java ====\npublic class PrintQueue {\n    private JobNode head;\n    private JobNode tail;\n    private int size;\n\n    public PrintQueue() {\n        this.head = null;\n        this.tail = null;\n        this.size = 0;\n    }\n\n    public void enqueue(String document) {\n        JobNode node = new JobNode(document);\n        if (this.tail == null) {\n            this.head = node;\n        } else {\n            this.tail.next = node;\n        }\n        this.tail = node;\n        this.size++;\n    }\n\n    public String dequeue() {\n        if (this.head == null) {\n            throw new IllegalStateException(\"Nothing to print\");\n        }\n        String document = this.head.document;\n        this.head = this.head.next;\n        if (this.head == null) {\n            this.tail = null;\n        }\n        this.size--;\n        return document;\n    }\n\n    public boolean isEmpty() {\n        return this.head == null;\n    }\n\n    public int size() {\n        return this.size;\n    }\n}\n\n// ==== JobNode.java ====\npublic class JobNode {\n    String document;\n    JobNode next;\n\n    public JobNode(String document) {\n        this.document = document;\n        this.next = null;\n    }\n}\n\n// ==== Main.java ====\npublic class Main {\n    public static void main(String[] args) {\n        PrintQueue queue = new PrintQueue();\n        queue.enqueue(\"report.pdf\");\n        queue.enqueue(\"map.png\");\n        System.out.println(\"Printing \" + queue.dequeue());\n        queue.enqueue(\"menu.txt\");\n        while (!queue.isEmpty()) {\n            System.out.println(\"Printing \" + queue.dequeue() + \", \" + queue.size() + \" left\");\n        }\n    }\n}\n","hints":["Three instance variables: `head`, `tail` (both JobNodes) and `size`. `enqueue` is step 2's `addLast`: on an empty queue the new node becomes the head, otherwise `this.tail.next = node;`, and then `this.tail = node;`.","`dequeue` is `removeFirst`: check for an empty queue, keep the head's document, move `head` on. If the queue is now empty, set `tail` to `null`, or the next `enqueue` would link the new node after a removed one."],"tests":[{"name":"Test 1","stdin":"","call":"PrintQueue queue = new PrintQueue();\nqueue.enqueue(\"report.pdf\");\nqueue.enqueue(\"map.png\");\nSystem.out.println(\"Printing \" + queue.dequeue());\nqueue.enqueue(\"menu.txt\");\nwhile (!queue.isEmpty()) {\n    System.out.println(\"Printing \" + queue.dequeue() + \", \" + queue.size() + \" left\");\n}\n","expect":"Printing report.pdf\nPrinting map.png, 1 left\nPrinting menu.txt, 0 left","hidden":false},{"name":"Test 2","stdin":"","call":"PrintQueue queue = new PrintQueue();\nSystem.out.println(queue.isEmpty() + \" \" + queue.size());\ntry {\n    queue.dequeue();\n} catch (IllegalStateException e) {\n    System.out.println(e.getMessage());\n}\nqueue.enqueue(\"a.txt\");\nSystem.out.println(queue.dequeue() + \" \" + queue.isEmpty());\nqueue.enqueue(\"b.txt\");\nqueue.enqueue(\"c.txt\");\nqueue.enqueue(\"d.txt\");\nSystem.out.println(queue.dequeue() + \" \" + queue.size());\nqueue.enqueue(\"e.txt\");\nwhile (!queue.isEmpty()) {\n    System.out.print(queue.dequeue() + \" \");\n}\nSystem.out.println(queue.size());\n","expect":"true 0\nNothing to print\na.txt true\nb.txt 2\nc.txt d.txt e.txt 0","hidden":true}],"require":[{"pattern":"JobNode\\s+tail\\b","message":"Keep the last node in an instance variable `tail`, so that `enqueue` doesn't walk the queue."},{"pattern":"throw\\s+new\\s+IllegalStateException","message":"On an empty queue, `dequeue` throws an IllegalStateException with the message `Nothing to print`."}],"forbid":[{"pattern":"\\b(ArrayList|LinkedList|ArrayDeque)\\b","message":"Build the queue on JobNode objects, not on one of Java's collections."}]},{"task":"A spreadsheet checks the brackets in a formula before it calculates anything. Write the method `balanced(String formula)` in `Main.java`. It returns `true` when every bracket, `(`, `[` and `{`, is closed by the matching `)`, `]` or `}` in the right order, and `false` otherwise. Other characters don't matter. Use the stack of characters in `CharStack.java` (it has `push`, `pop`, `peek` and `isEmpty`; `pop` and `peek` throw an exception on an empty stack, so check `isEmpty()` first), the way the lesson describes. The check runs:\n\n```java\nSystem.out.println(balanced(\"=SUM((A1+B2)*[C3])\"));\nSystem.out.println(balanced(\"=MAX(A1,{B2)}\"));\nSystem.out.println(balanced(\"=(A1+B2\"));\nSystem.out.println(balanced(\"=A1)\"));\n```\n\nand expects:\n\n```\ntrue\nfalse\nfalse\nfalse\n```\n","kind":"code","seed":"// ==== Main.java ====\npublic class Main {\n    public static void main(String[] args) {\n        System.out.println(balanced(\"=SUM((A1+B2)*[C3])\"));\n        System.out.println(balanced(\"=MAX(A1,{B2)}\"));\n        System.out.println(balanced(\"=(A1+B2\"));\n        System.out.println(balanced(\"=A1)\"));\n    }\n\n    public static boolean balanced(String formula) {\n        return true;\n    }\n}\n\n// ==== CharStack.java ====\npublic class CharStack {\n    private CharNode top;\n\n    public void push(char value) {\n        this.top = new CharNode(value, this.top);\n    }\n\n    public char pop() {\n        char value = peek();\n        this.top = this.top.next;\n        return value;\n    }\n\n    public char peek() {\n        if (this.top == null) {\n            throw new IllegalStateException(\"The stack is empty\");\n        }\n        return this.top.value;\n    }\n\n    public boolean isEmpty() {\n        return this.top == null;\n    }\n}\n\n// ==== CharNode.java ====\npublic class CharNode {\n    char value;\n    CharNode next;\n\n    public CharNode(char value, CharNode next) {\n        this.value = value;\n        this.next = next;\n    }\n}\n","solution":"// ==== Main.java ====\npublic class Main {\n    public static void main(String[] args) {\n        System.out.println(balanced(\"=SUM((A1+B2)*[C3])\"));\n        System.out.println(balanced(\"=MAX(A1,{B2)}\"));\n        System.out.println(balanced(\"=(A1+B2\"));\n        System.out.println(balanced(\"=A1)\"));\n    }\n\n    public static boolean balanced(String formula) {\n        CharStack open = new CharStack();\n        for (int i = 0; i < formula.length(); i++) {\n            char c = formula.charAt(i);\n            if (c == '(' || c == '[' || c == '{') {\n                open.push(c);\n            } else if (c == ')' || c == ']' || c == '}') {\n                if (open.isEmpty()) {\n                    return false;\n                }\n                char opening = open.pop();\n                if (c == ')' && opening != '(') {\n                    return false;\n                }\n                if (c == ']' && opening != '[') {\n                    return false;\n                }\n                if (c == '}' && opening != '{') {\n                    return false;\n                }\n            }\n        }\n        return open.isEmpty();\n    }\n}\n\n// ==== CharStack.java ====\npublic class CharStack {\n    private CharNode top;\n\n    public void push(char value) {\n        this.top = new CharNode(value, this.top);\n    }\n\n    public char pop() {\n        char value = peek();\n        this.top = this.top.next;\n        return value;\n    }\n\n    public char peek() {\n        if (this.top == null) {\n            throw new IllegalStateException(\"The stack is empty\");\n        }\n        return this.top.value;\n    }\n\n    public boolean isEmpty() {\n        return this.top == null;\n    }\n}\n\n// ==== CharNode.java ====\npublic class CharNode {\n    char value;\n    CharNode next;\n\n    public CharNode(char value, CharNode next) {\n        this.value = value;\n        this.next = next;\n    }\n}\n","hints":["Go through the formula with `charAt`. Push each opening bracket. For a closing bracket, return `false` at once if the stack is empty; otherwise pop and compare: a `)` needs a `(`, a `]` a `[`, and a `}` a `{`.","After the loop, every opening bracket must have been closed: `return open.isEmpty();`."],"tests":[{"name":"Test 1","stdin":"","call":"System.out.println(balanced(\"=SUM((A1+B2)*[C3])\"));\nSystem.out.println(balanced(\"=MAX(A1,{B2)}\"));\nSystem.out.println(balanced(\"=(A1+B2\"));\nSystem.out.println(balanced(\"=A1)\"));\n","expect":"true\nfalse\nfalse\nfalse","hidden":false},{"name":"Test 2","stdin":"","call":"System.out.println(balanced(\"\"));\nSystem.out.println(balanced(\"=A1*2\"));\nSystem.out.println(balanced(\"{[()()]}\"));\nSystem.out.println(balanced(\")(\"));\nSystem.out.println(balanced(\"(]\"));\nSystem.out.println(balanced(\"([)]\"));\nSystem.out.println(balanced(\"{{[[(())]]}}\"));\nSystem.out.println(balanced(\"(()\"));\n","expect":"true\ntrue\ntrue\nfalse\nfalse\nfalse\ntrue\nfalse","hidden":true}],"require":[{"pattern":"new\\s+CharStack\\s*\\(","message":"Keep the opening brackets on a `new CharStack()`."}],"forbid":[]}]}