Your country

Tools that support it use your country for local currency, number formats, units and paper size. Your choice is saved only in this browser.

Type a name or a two-letter code. Use the up and down arrow keys to move through the countries, Enter to choose one and Escape to close.

Data Structures & Algorithms (DSA) Module 1 – Foundations: problems, correctness and complexity

The DSA toolkit in Python, JS, Java, C++ and Go

Map stacks, queues, hash maps, ordered maps and heaps to the standard libraries of Python, JavaScript, Java, C++ and Go, with documented costs and traps.

  • Beginner
  • 30 minutes
  • Examples run with Python 3.14.8, Pyodide 314.0.7, Node.js 24.21.0 and quickjs 0.32.0
  • By MySmartCoPilot

What you will learn

  • Map each abstract data type to its standard-library type in five languages
  • State the documented cost of the core operations
  • Avoid the version-specific traps of each standard library

Before you start

On this page

Most of the algorithms in this track are built from a handful of abstract data types: a stack, a queue, a hash map or set, an ordered map and a priority queue. Every language’s standard library implements some of them, under different names, with different defaults and with different promises about speed. This lesson maps them across the five languages the track uses, lists the costs their documentation actually promises, and collects the traps that catch people when they switch languages or versions.

One program in two languages

This program uses all five abstract data types once each. The Python and JavaScript versions do the same work and print the same lines; choose a tab to compare them:

A stack, a queue, a map, sorted keys and a heap

Python · toolkit/toolkit.py

import bisect
import heapq
from collections import deque

# Stack: a list, pushing and popping at the end.
history = []
for page in ["home", "search", "results"]:
    history.append(page)
print(f"stack: back from {history.pop()} to {history[-1]}")

# Queue: collections.deque, adding at the back and taking from the front.
line = deque(["asha", "ben", "chen"])
line.append("dev")
print(f"queue: serve {line.popleft()}, then {line[0]} is first")

# Hash map: dict, counting words (keys stay in the order they were first added).
counts = {}
for word in "to be or not to be".split():
    counts[word] = counts.get(word, 0) + 1
print("map:", " ".join(f"{word}={n}" for word, n in counts.items()))

# Ordered keys: no tree map in the standard library, so a sorted list and binary search.
scores = []
for score in [70, 45, 90, 60]:
    bisect.insort(scores, score)
first = scores[bisect.bisect_left(scores, 65)]
print(f"sorted: {', '.join(map(str, scores))}; first score >= 65: {first}")

# Priority queue: heapq keeps a min-heap in a list; (priority, task) pairs pop lowest first.
tasks = []
for priority, task in [(3, "email"), (1, "fix bug"), (2, "review")]:
    heapq.heappush(tasks, (priority, task))
print("heap:", ", ".join(heapq.heappop(tasks)[1] for _ in range(len(tasks))))

Output

stack: back from results to search
queue: serve asha, then ben is first
map: to=2 be=2 or=1 not=1
sorted: 45, 60, 70, 90; first score >= 65: 70
heap: fix bug, review, email

Recorded with Python 3.14.8 on macOS 26 arm64. To run it yourself: mise exec python@3.14.8 -- python3 toolkit.py

JavaScript · toolkit/toolkit.mjs

// Stack: an array, pushing and popping at the end.
const history = [];
for (const page of ['home', 'search', 'results']) history.push(page);
console.log(`stack: back from ${history.pop()} to ${history.at(-1)}`);

// Queue: there is no deque, and shift() moves every element, so keep the index of the front instead.
const line = ['asha', 'ben', 'chen'];
let front = 0;
line.push('dev');
console.log(`queue: serve ${line[front++]}, then ${line[front]} is first`);

// Hash map: Map, counting words (keys stay in the order they were first added).
const counts = new Map();
for (const word of 'to be or not to be'.split(' ')) counts.set(word, (counts.get(word) ?? 0) + 1);
console.log(`map: ${[...counts].map(([word, n]) => `${word}=${n}`).join(' ')}`);

// Ordered keys: no tree map either, so a sorted array and a binary search written by hand.
function lowerBound(sorted, x) {
  let low = 0;
  let high = sorted.length;
  while (low < high) {
    const middle = (low + high) >>> 1;
    if (sorted[middle] < x) low = middle + 1;
    else high = middle;
  }
  return low;
}
const scores = [];
for (const score of [70, 45, 90, 60]) scores.splice(lowerBound(scores, score), 0, score);
console.log(`sorted: ${scores.join(', ')}; first score >= 65: ${scores[lowerBound(scores, 65)]}`);

// Priority queue: no heap in JavaScript, so a small binary min-heap of [priority, task] pairs.
const before = (a, b) => a[0] < b[0] || (a[0] === b[0] && a[1] < b[1]);
class MinHeap {
  items = [];
  push(item) {
    const a = this.items;
    a.push(item);
    for (let i = a.length - 1; i > 0 && before(a[i], a[(i - 1) >> 1]); i = (i - 1) >> 1) {
      [a[i], a[(i - 1) >> 1]] = [a[(i - 1) >> 1], a[i]];
    }
  }
  pop() {
    const a = this.items;
    const top = a[0];
    const last = a.pop();
    if (a.length) {
      a[0] = last;
      for (let i = 0; ; ) {
        const left = 2 * i + 1;
        const right = left + 1;
        let smallest = i;
        if (left < a.length && before(a[left], a[smallest])) smallest = left;
        if (right < a.length && before(a[right], a[smallest])) smallest = right;
        if (smallest === i) break;
        [a[i], a[smallest]] = [a[smallest], a[i]];
        i = smallest;
      }
    }
    return top;
  }
  get size() {
    return this.items.length;
  }
}
const tasks = new MinHeap();
for (const pair of [[3, 'email'], [1, 'fix bug'], [2, 'review']]) tasks.push(pair);
const order = [];
while (tasks.size) order.push(tasks.pop()[1]);
console.log(`heap: ${order.join(', ')}`);

Output

stack: back from results to search
queue: serve asha, then ben is first
map: to=2 be=2 or=1 not=1
sorted: 45, 60, 70, 90; first score >= 65: 70
heap: fix bug, review, email

Recorded with Node.js 24.21.0 on macOS 26 arm64. To run it yourself: mise exec node@24.21.0 -- node toolkit.mjs

Python has every structure it needs in the standard library: a list as the stack, collections.deque as the queue, a dict, bisect for the sorted list and heapq for the priority queue. The JavaScript version had to supply three of its own: a front index instead of a deque, a binary search instead of a sorted-container type, and a short binary heap.

The sections below take one language each: which type to use for each abstract data type, the costs its documentation promises, and its traps. Java, C++ and Go programs are not run on this page; what it says about them comes from each language’s own documentation and specification, listed under References.

Python 3.14

  • Dynamic array and stack: list, with append() and pop() at the end.
  • Queue or deque: collections.deque.
  • Hash map and set: dict and set.
  • Ordered map: none in the standard library. Keep a sorted list and search it with bisect.
  • Priority queue: heapq, functions that keep a min-heap inside an ordinary list.
  • Graphs: graphlib.TopologicalSorter sorts a dependency graph (from Python 3.9).

Python documents the costs of its built-in types on one page of its documentation, plus the pages of deque, heapq and bisect:

Python 3.14: documented costs
Operation Time Extra space
list.append(x), list.pop() O(1) O(1)
list.pop(0), list.insert(0, x) O(n) O(1)
x in list O(n) O(1)
deque: append, appendleft, pop, popleft O(1) O(1)
dict and set: get, set, delete, in O(1) O(1)
heapq.heapify(list) O(n) O(1)
heapq.heappush, heapq.heappop O(log n) O(1)
bisect.bisect_left O(log n) O(1)
bisect.insort O(n) O(1)

The list costs at the end of the list are amortised: an occasional append copies the whole list into more room. pop(0) and insert(0, x) move every later element. The dict and set costs are averages; when many keys collide, an operation can take O(n). Indexing the middle of a deque is O(n), and insort is O(n) because inserting moves elements even though the search is fast. The heapq page states the linear heapify and, in its section on the theory, that taking out the smallest item is logarithmic; a push climbs the same tree at most one level per step, so it is logarithmic too.

The max-heap functions of heapq (heapify_max, heappush_max, heappop_max and two more) are new in Python 3.14; before that, the usual workaround was to push negated values. bisect takes a key= argument only from 3.10. Two limits catch algorithm code in every recent version: recursion stops at about 1,000 nested calls by default, and converting an integer of more than 4,300 decimal digits to a string raises ValueError (a protection against very slow conversions). A program can ask its interpreter directly:

What this Python has Python · features.py
import bisect
import heapq
import inspect
import itertools
import sys


def has(found):
    return "yes" if found else "no "


try:
    graphlib = __import__("graphlib")
except ImportError:
    graphlib = None

print(f"Python {sys.version_info.major}.{sys.version_info.minor}")
print(f"{has(hasattr(heapq, 'heapify_max'))} heapq max-heap functions (3.14)")
print(f"{has(hasattr(itertools, 'batched'))} itertools.batched (3.12)")
print(f"{has('key' in inspect.signature(bisect.bisect_left).parameters)} bisect with key= (3.10)")
print(f"{has(hasattr(itertools, 'pairwise'))} itertools.pairwise (3.10)")
print(f"{has(graphlib is not None)} graphlib.TopologicalSorter (3.9)")
print(f"recursion limit: {sys.getrecursionlimit()}")
print(f"digits allowed in str(int): {sys.get_int_max_str_digits()}")
try:
    str(10**5000)
except ValueError as error:
    print(f"str(10**5000) raises {type(error).__name__}: the number has 5,001 digits")

Output

Python 3.14
yes heapq max-heap functions (3.14)
yes itertools.batched (3.12)
yes bisect with key= (3.10)
yes itertools.pairwise (3.10)
yes graphlib.TopologicalSorter (3.9)
recursion limit: 1000
digits allowed in str(int): 4300
str(10**5000) raises ValueError: the number has 5,001 digits

Recorded with Python 3.14.8 on macOS 26 arm64. To run it yourself: mise exec python@3.14.8 -- python3 features.py

Pyodide, the Python of this site’s Run buttons, is CPython 3.14.2 and prints the same lines.

JavaScript (ECMAScript 2026)

  • Dynamic array and stack: Array, with push() and pop().
  • Queue or deque: none. Use an Array and an index of its front, as the toolkit program does.
  • Hash map and set: Map and Set.
  • Ordered map: none.
  • Priority queue: none. Write a binary heap, as the toolkit program does.

The ECMAScript standard promises less than the other languages’ documentation. It requires Map and Set to be implemented with hash tables or other mechanisms whose access time is, on average, less than linear in the number of elements, and it defines iteration in insertion order. It states no cost for array methods. Its algorithm for shift() moves every remaining element down by one place, which is why the toolkit program keeps a front index instead.

Engines add new ECMAScript features at different times, so the same file can work in one and fail in another. structuredClone() is not ECMAScript at all but a web platform function that browsers and Node.js provide. Test for a feature before relying on it:

What this JavaScript engine has JavaScript · features.mjs
// Which optional features does this JavaScript engine have? Test for a feature before you rely on it.
const has = (found) => (found ? 'yes' : 'no ');
const engine = typeof process === 'object' ? `Node.js ${process.versions.node} (V8 ${process.versions.v8})` : 'not Node.js';

console.log(`engine: ${engine}`);
console.log(`${has(typeof Set.prototype.union === 'function')} Set.prototype.union and friends (ES2025)`);
console.log(`${has(typeof globalThis.Iterator?.prototype?.map === 'function')} iterator helpers such as Iterator.prototype.map (ES2025)`);
console.log(`${has(typeof Math.sumPrecise === 'function')} Math.sumPrecise (ES2026)`);
console.log(`${has(typeof Map.prototype.getOrInsert === 'function')} Map.prototype.getOrInsert (ES2026)`);
console.log(`${has(typeof Array.fromAsync === 'function')} Array.fromAsync (ES2026)`);
console.log(`${has(typeof structuredClone === 'function')} structuredClone (a web platform function, not ECMAScript)`);
console.log(`Number.MAX_SAFE_INTEGER: ${Number.MAX_SAFE_INTEGER}`);
console.log(`2 ** 53 + 1 as a Number: ${2 ** 53 + 1}, as a BigInt: ${2n ** 53n + 1n}`);

Output

engine: Node.js 24.21.0 (V8 13.6.233.17-node.53)
yes Set.prototype.union and friends (ES2025)
yes iterator helpers such as Iterator.prototype.map (ES2025)
no  Math.sumPrecise (ES2026)
no  Map.prototype.getOrInsert (ES2026)
yes Array.fromAsync (ES2026)
yes structuredClone (a web platform function, not ECMAScript)
Number.MAX_SAFE_INTEGER: 9007199254740991
2 ** 53 + 1 as a Number: 9007199254740992, as a BigInt: 9007199254740993

Recorded with Node.js 24.21.0 on macOS 26 arm64. To run it yourself: mise exec node@24.21.0 -- node features.mjs

Version note

In your browser, this file runs in QuickJS (quickjs-emscripten 0.32.0). That engine has two ES2026 features that Node.js 24 lacks, Math.sumPrecise and Map.prototype.getOrInsert, but not Array.fromAsync, and it has no structuredClone, because that comes from the web platform, not from the language.

In your browser, QuickJS (quickjs-emscripten 0.32.0) prints:

engine: not Node.js
yes Set.prototype.union and friends (ES2025)
yes iterator helpers such as Iterator.prototype.map (ES2025)
yes Math.sumPrecise (ES2026)
yes Map.prototype.getOrInsert (ES2026)
no  Array.fromAsync (ES2026)
no  structuredClone (a web platform function, not ECMAScript)
Number.MAX_SAFE_INTEGER: 9007199254740991
2 ** 53 + 1 as a Number: 9007199254740992, as a BigInt: 9007199254740993

Two more traps are in the language itself. Above Number.MAX_SAFE_INTEGER, 2⁵³ − 1, a Number can no longer hold every integer: neighbouring integers share one value, so 2 ** 53 + 1 comes out as 2⁵³, as the last line of the probe shows. Use BigInt for integers that large. And Array.prototype.sort() without a compare function compares elements as strings, so [10, 9, 1].sort() gives [1, 10, 9]; pass (a, b) => a - b to sort numbers.

Java 25

  • Dynamic array: ArrayList.
  • Stack, queue and deque: ArrayDeque. Its documentation says it is likely to be faster than Stack used as a stack and faster than LinkedList used as a queue, and the documentation of Stack recommends Deque implementations in its place.
  • Hash map and set: HashMap and HashSet.
  • Ordered map and set: TreeMap and TreeSet, red-black trees.
  • Priority queue: PriorityQueue, smallest element first.
  • Sorting and binary search: List.sort and Collections.binarySearch.
Java 25: documented costs
Operation Time Extra space
ArrayList.add O(1) O(1)
ArrayList.get, set O(1) O(1)
ArrayDeque: push, pop, offer, poll O(1) O(1)
HashMap.get, put O(1) O(1)
TreeMap: containsKey, get, put, remove O(log n) O(1)
PriorityQueue: offer, poll O(log n) O(1)
PriorityQueue.peek O(1) O(1)

ArrayList.add and the ArrayDeque operations are amortised, and contains and remove(Object) on an ArrayDeque or a PriorityQueue are O(n). HashMap promises constant time only if the hash function spreads the keys well among its buckets, while TreeMap guarantees its log n.

JDK 25 makes compact source files standard (JEP 512): a file may contain just void main() { IO.println("hi"); }, with no class around it. JDK 21 to 24 had only previews of the feature, switched on with --enable-preview, and they differ from the final version (in the last preview the IO class was still in java.io, not java.lang), so write such files for JDK 25 or later. Two older traps matter more for algorithms:

  • == on boxed numbers. Integer values are objects, and == compares whether two references are the same object. The Java Language Specification guarantees shared objects only for small constant values (-128 to 127), so compare Integer values with equals(), or unbox them to int.
  • Comparators that subtract. (x, y) -> x - y overflows when the values are far apart, because int arithmetic wraps around, and the sort then puts large values in the wrong place. Use Integer.compare(x, y) or Comparator.naturalOrder().

C++23

  • Dynamic array: std::vector.
  • Stack and queue: std::stack and std::queue, adaptors over std::deque by default.
  • Hash map and set: std::unordered_map and std::unordered_set.
  • Ordered map and set: std::map and std::set; from C++23 also std::flat_map.
  • Priority queue: std::priority_queue, largest element first.
  • Sorting and binary search: std::sort and std::lower_bound.
C++23: costs the standard requires
Operation Time Extra space
vector::push_back O(1) O(1)
unordered_map: find, insert O(1) O(1)
map and set: find, insert O(log n) O(1)
priority_queue::push O(log n) O(1)
priority_queue::top O(1) O(1)

push_back is amortised constant. The unordered containers are O(1) on average and O(n) in the worst case, and priority_queue::push makes at most log n comparisons.

  • std::priority_queue is a max-heap. It compares with std::less, so the largest element is on top, the opposite of Python, Java and Go. Use std::greater<T> as the third template argument for a min-heap.
  • Comparators must be a strict weak ordering. The standard requires it of every comparison passed to a sorting algorithm, and <= is not one: a strict ordering never says that an element comes before itself, but x <= x is true. When a program breaks a requirement like this, the standard places no requirements on what happens (undefined behaviour), so the result may be a wrong order or a crash.
  • map[key] inserts. Reading a missing key with operator[] adds it with a default value; use find() or contains() to look without changing the map.
  • std::flat_map needs C++23. It keeps its keys sorted in a sequence container, so lookups are binary searches, but the standard makes inserting or erasing one element linear in the size of the map.

Go 1.27

  • Dynamic array and stack: a slice, with append and s[:len(s)-1].
  • Queue: none. Use a slice and an index of its front, or container/list, a doubly linked list.
  • Hash map and set: the built-in map; for a set, Effective Go suggests a map with bool values.
  • Ordered map: none. Sort the keys with slices.Sort when you need them in order.
  • Priority queue: container/heap, smallest first, on a type you write.
  • Sorting and binary search: slices.Sort and slices.BinarySearch.
Go 1.27: documented costs
Operation Time Extra space
heap.Init O(n) O(1)
heap.Push, heap.Pop O(log n) O(1)
slices.Insert(s, i, v) O(n) O(1)

The specification states no cost for the built-in map; the Go team describes the runtime’s map as a hash table, built since Go 1.24 on a design called Swiss Tables. slices.Insert is documented as O(len(s) + len(v)): every element after the insertion point moves.

The best-known trap is the order of a map. The specification says it in one sentence:

The iteration order over maps is not specified and is not guaranteed to be the same from one iteration to the next.

So sort the keys first whenever output must be repeatable. Two more traps:

  • container/heap needs your type. You write Len, Less, Swap, Push and Pop for your slice type, then call heap.Push and heap.Pop from the package; the documentation notes that the Push and Pop methods are for the package to call, not for you.
  • Generic methods are new in Go 1.27: a method may now declare its own type parameters. Code that uses them does not compile with Go 1.26 or earlier.

GATE CS

The Programming and Data Structures section of the GATE 2027 syllabus for Computer Science and Information Technology begins with “Programming in C” and goes on to list arrays, stacks, queues, linked lists, trees, binary search trees, binary heaps and graphs. C has arrays, but its standard library has none of the containers in this lesson, so for GATE you study how each structure is built and what its operations cost, not a library’s names for them.

Port it yourself

The exercise below asks you to port this small task board from Python to JavaScript. It uses four of the structures: a queue for the order of tasks, a hash map for owners, a min-heap of deadlines and a stack for undo. A task that has started or been undone is only marked as gone in a set; the queue, the heap and the stack drop it when it comes up next, instead of digging it out of the middle:

A task board in Python Python · task_board.py
import heapq
from collections import deque


def run_task_board(commands):
    """Run the commands of a small task board and return the lines it prints."""
    waiting = deque()  # queue: tasks in the order they were added
    owners = {}  # hash map: task -> owner
    deadlines = []  # min-heap of (day, task): the earliest day first, then the task's name
    added = []  # stack: the tasks in the order they were added, for undo
    gone = set()  # tasks that have started or been undone
    lines = []
    for command in commands:
        name, *args = command.split()
        if name == "add":
            task, owner, day = args[0], args[1], int(args[2])
            waiting.append(task)
            owners[task] = owner
            heapq.heappush(deadlines, (day, task))
            added.append(task)
            lines.append(f"added {task} for {owner}, due on day {day}")
        elif name == "next":
            while waiting and waiting[0] in gone:
                waiting.popleft()
            if waiting:
                task = waiting.popleft()
                gone.add(task)
                lines.append(f"{owners[task]} starts {task}")
            else:
                lines.append("no task is waiting")
        elif name == "urgent":
            while deadlines and deadlines[0][1] in gone:
                heapq.heappop(deadlines)
            if deadlines:
                day, task = deadlines[0]
                lines.append(f"most urgent: {task}, due on day {day}")
            else:
                lines.append("nothing is urgent")
        elif name == "undo":
            while added and added[-1] in gone:
                added.pop()
            if added:
                task = added.pop()
                gone.add(task)
                lines.append(f"undid {task}")
            else:
                lines.append("nothing to undo")
    return lines


DEMO = [
    "add slides asha 5",
    "add report ben 3",
    "add invoice chen 3",
    "urgent",
    "next",
    "undo",
    "urgent",
    "next",
    "next",
]
for line in run_task_board(DEMO):
    print(line)

Output

added slides for asha, due on day 5
added report for ben, due on day 3
added invoice for chen, due on day 3
most urgent: invoice, due on day 3
asha starts slides
undid invoice
most urgent: report, due on day 3
ben starts report
no task is waiting

Recorded with Python 3.14.8 on macOS 26 arm64. To run it yourself: mise exec python@3.14.8 -- python3 task_board.py

Text Diff Compare your JavaScript port's output with the Python output above, line by line.

Key takeaways

  • Python’s standard library covers stacks, queues, hash maps and heaps but has no ordered map. JavaScript has arrays, Map and Set only. Java and C++ include balanced-tree maps; Go has slices, maps and container/heap.
  • Rely on documented costs: deque and ArrayDeque for queues, hash maps for average O(1) lookups, tree maps for guaranteed O(log n), heaps for O(log n) push and pop. list.pop(0), x in list and JavaScript’s shift() are linear.
  • Know the defaults: C++’s priority queue gives the largest element first, the others the smallest; Go’s map order is unspecified; JavaScript sorts as strings unless you pass a compare function.
  • Check versions: heapq max-heaps need Python 3.14, compact Java source files need JDK 25, std::flat_map needs C++23, generic methods need Go 1.27, and each JavaScript engine has its own set of the newest features.

Exercise

Exercise · Medium · JavaScript

Port the task board from Python to JavaScript

Port the lesson's task_board.py to JavaScript. Write runTaskBoard(commands): it takes an array of command strings and returns an array of the lines the Python version prints for them, word for word. The commands are:

- add TASK OWNER DAY: add a task, its owner and the day it is due. Prints added TASK for OWNER, due on day DAY. - next: the owner starts the task that has waited longest. Prints OWNER starts TASK, or no task is waiting. - urgent: names the waiting task with the earliest day; on equal days, the task whose name comes first. Prints most urgent: TASK, due on day DAY, or nothing is urgent. - undo: removes the most recently added task that has not started. Prints undid TASK, or nothing to undo.

A task that has started or been undone is gone: next, urgent and undo skip it. Task names are never repeated.

JavaScript has no deque and no heap, so choose a replacement for each: an array with an index of its front for the queue, and a small binary heap, or another way to find the earliest deadline, for urgent. The tests only compare the lines your function returns.

Starter code · task_board.mjs

/**
 * Runs the commands of the task board and returns the lines it prints, exactly like run_task_board in the lesson's
 * task_board.py: "add TASK OWNER DAY", "next", "urgent" and "undo".
 */
export function runTaskBoard(commands) {
  const lines = [];
  // A queue, a Map of owners, the deadlines, a stack of added tasks and a Set of tasks that are gone.
  return lines;
}
The sample tests · task_board.test.mjs
import { test, assert } from 'toolverse:test';
import { runTaskBoard } from './task_board.mjs';

test('prints what task_board.py prints for its demo', () =>
  assert.deepEqual(runTaskBoard(['add slides asha 5', 'add report ben 3', 'add invoice chen 3', 'urgent', 'next', 'undo', 'urgent', 'next', 'next']), [
    'added slides for asha, due on day 5',
    'added report for ben, due on day 3',
    'added invoice for chen, due on day 3',
    'most urgent: invoice, due on day 3',
    'asha starts slides',
    'undid invoice',
    'most urgent: report, due on day 3',
    'ben starts report',
    'no task is waiting',
  ]));

test('says so when the board is empty', () =>
  assert.deepEqual(runTaskBoard(['next', 'urgent', 'undo']), ['no task is waiting', 'nothing is urgent', 'nothing to undo']));

test('serves tasks first in, first out', () =>
  assert.deepEqual(runTaskBoard(['add a ann 9', 'add b bob 1', 'add c cy 5', 'next', 'next', 'next']), [
    'added a for ann, due on day 9',
    'added b for bob, due on day 1',
    'added c for cy, due on day 5',
    'ann starts a',
    'bob starts b',
    'cy starts c',
  ]));

test('picks the earliest day, then the first name, and skips tasks that are gone', () =>
  assert.deepEqual(runTaskBoard(['add zeta zoe 2', 'add alpha al 2', 'add mid mo 10', 'add early ed 1', 'urgent', 'undo', 'urgent', 'next', 'next', 'urgent']), [
    'added zeta for zoe, due on day 2',
    'added alpha for al, due on day 2',
    'added mid for mo, due on day 10',
    'added early for ed, due on day 1',
    'most urgent: early, due on day 1',
    'undid early',
    'most urgent: alpha, due on day 2',
    'zoe starts zeta',
    'al starts alpha',
    'most urgent: mid, due on day 10',
  ]));

test('undo skips tasks that have started and stops when nothing is left', () =>
  assert.deepEqual(runTaskBoard(['add x xi 3', 'add y yu 4', 'next', 'next', 'undo', 'add z zed 7', 'undo', 'undo', 'urgent']), [
    'added x for xi, due on day 3',
    'added y for yu, due on day 4',
    'xi starts x',
    'yu starts y',
    'nothing to undo',
    'added z for zed, due on day 7',
    'undid z',
    'nothing to undo',
    'nothing is urgent',
  ]));

test('compares days as numbers, not as text', () =>
  assert.deepEqual(runTaskBoard(['add big bo 10', 'add small sam 9', 'urgent']), [
    'added big for bo, due on day 10',
    'added small for sam, due on day 9',
    'most urgent: small, due on day 9',
  ]));
A hint

Keep the same five structures as the Python version: an array and a front index for the queue, a Map of owners, the deadlines, an array used as a stack for undo, and a Set of tasks that are gone. Python compares (day, task) tuples item by item; in JavaScript compare the days first and the names only when the days are equal.

The sample tests run on this device, in your browser (QuickJS): nothing is sent to mysmartcopilot.com. The first run downloads JavaScript (about 0.6 MB), which is kept for the next runs. A check in your browser is feedback for you, not proof that the code is right for every input.

Check yourself

6 questions about this lesson. Every answer and why it is right is on the page, behind “Show the answer”. Your score stays in this browser.

  1. Question 1 of 6 Which of these priority queues gives you the largest element first by default?

    Choose one answer.

    Show the answer to question 1

    Answer: C++ std::priority_queue

    std::priority_queue compares with std::less and keeps the largest element on top; use std::greater for the smallest. heapq, PriorityQueue and container/heap all put the smallest element first.

  2. Question 2 of 6 Which standard libraries include a balanced search tree, an ordered map with logarithmic lookups?

    Choose every answer that is right.

    Show the answer to question 2

    Answer:

    • Java (TreeMap)
    • C++ (std::map)

    Java's TreeMap is a red-black tree with guaranteed log(n) lookups and updates, and the C++ standard requires logarithmic find and insert for std::map. Python, JavaScript and Go have none; a sorted list with binary search, or sorting the keys when you need them in order, is the usual stand-in.

  3. Question 3 of 6 In Python 3.14, which call turns a list into a max-heap in place?

    Choose one answer.

    Show the answer to question 3

    Answer: heapq.heapify_max(items)

    The max-heap functions (heapify_max, heappush_max, heappop_max and two more) are new in Python 3.14. Negating the values also works on older versions, but it builds a new list of negated values rather than a max-heap of the original ones.

  4. Question 4 of 6 A Go program prints a map with a for-range loop twice. What does the language specification promise about the order?

    Choose one answer.

    Show the answer to question 4

    Answer: Nothing; it can differ from one loop to the next, so sort the keys first if the order matters

    The Go specification says the iteration order over maps is not specified and is not guaranteed to be the same from one iteration to the next. Python dicts and JavaScript Maps, by contrast, keep insertion order.

  5. Question 5 of 6 What does [10, 9, 1].sort() give in JavaScript?

    Choose one answer.

    Show the answer to question 5

    Answer: [1, 10, 9]

    Without a compare function, Array.prototype.sort compares the elements as strings, and "10" comes before "9". Pass a compare function, such as (a, b) => a - b, to sort numbers by value.

  6. Question 6 of 6 In Java, Integer a = 128, b = 128. Why should you write a.equals(b) instead of a == b?

    Choose one answer.

    Show the answer to question 6

    Answer: == compares whether the two Integer objects are the same object, which is only guaranteed for small values such as -128 to 127

    For boxed values, == compares references. The Java Language Specification guarantees shared objects only for constant values from -128 to 127, so two Integer objects holding 128 may well be different objects and a == b false. equals() compares the values.

References

Related tools

Report a problem with this lesson

Quick answers and tool search

Type to search tools or to get a quick answer, for example 18% of 2500. Use the up and down arrow keys to move through the results, Enter to choose, and Escape to close.