I’m a fan of pseudocode, and in this post, I’ll try to illustrate why.1
Pseudocode is more widely accessible.
Let’s say you’re trying to solve some programming problem in Java, and you’d like to implement an algorithm that you found in some research paper. Now suppose the paper uses Python, and you haven’t seen any Python in a while. In this situation, you’ll probably need to look up various idiosyncrasies. For example, what exactly does “for i in range(10):” mean? Does it include 0? Does it include 10? Resolving questions like these requires that you spend additional time and energy on tasks only tangentially related to the main problem, and this detour would be even costlier if you’ve never seen any Python in your life. On the other hand, if the paper states, “for i = 0, 1, …, 9,” you can translate that into Java much more easily. (Perhaps ideally, the research paper includes both pseudocode and executable code — Steven Skiena’s textbook does this.)
This might sound like a superficial advantage of pseudocode, but I believe there’s a deeper phenomenon here. Pseudocode is not just a time-saving device; it helps us grasp the essence of an algorithm by eliminating clutter and highlighting its core ideas. In other words:
Pseudocode better expresses algorithmic ideas.
Here’s an algorithm, similar to Breadth-First Search, implemented straightforwardly in Python. Note that Python is already more pseudocode-like than most programming languages, yet it still provides an illustrative example:
And here’s the same algorithm in pseudocode:
At a glance, we can see that the Python version (1) is longer and denser, (2) assumes that the graph is given as an adjacency matrix, and (3) requires the reader to know (or look up) Pythonic quirks such as “len(G)” and “[False] * n”. These mental hurdles obstruct the path toward understanding the algorithm (i.e., what it’s really doing) by submerging its description in the details of one particular implementation.
More generally, Python demands conformity to a rigid syntax, while the flexibility of pseudocode allows us to directly express the core ideas. For example, “for u in range(n): for v in range(n): if G[u][v] == 1” is a long-winded way of saying “find an edge (u,v).” Similarly, “marked[v] = True” is dry and technical, while “mark v” conjures a vivid image of an action that the reader can visualize themselves doing (e.g., placing a green checkmark on a circle).2 In fact, a picture might sometimes be even better than pseudocode:
Compressing ideas in this manner (executable code to pseudocode and/or picture) frees up space in our mental “working memory,” which is especially helpful when we’re dealing with new information (see, e.g., here and here). It’s like substituting “sodium chloride” with “salt” — the former is more appropriate if we’re concerned about a chemical reaction in a science experiment, but the latter is better for everyday cooking purposes. Similarly, executable code is essential if we want to modify the output of a computer program, but if we’re reasoning about algorithms at a higher level, pseudocode is generally more fitting.
It’s not just me: to the best of my knowledge, most popular textbooks on algorithms (e.g., [CLRS]) primarily or exclusively rely on pseudocode.
The advantage of using “mark v” over “marked[v] = True” is akin to the advantage of using active voice over passive voice.