Theory

Two operations, two structures

Two structures, one lesson. Both of them restrict an array down to two operations — and that restriction is exactly why they are useful.

A stack — last in, first out

You have viewed four albums and you press "back". You need the one you looked at most recently.

  push A   push B   push C        pop → C
  ┌───┐    ┌───┐    ┌───┐         ┌───┐
  │   │    │ B │    │ C │         │ B │
  │ A │    │ A │    │ B │         │ A │
  └───┘    └───┘    │ A │         └───┘
                    └───┘

Both operations touch only the top. A slice does that perfectly: append adds at the end, s[:len(s)-1] takes from the end. Nothing shifts, because the end is the one place an array is cheap to change.

Push and Pop are O(1). There is nothing to argue about here.

A queue — first in, first out

The playlist's "up next": you add at the back and take from the front.

And that is where the lesson starts. Adding at the back is cheap — it is the same append. But taking from the front of an array is precisely the operation lesson 2 called expensive.

Guess before you read on

Three ways to remove the first element of a []Item:

A. q = q[1:] — move the slice header forward. B. copy(q, q[1:]) and shorten — shift every element. C. a ring buffer — one array, two indices chasing each other around it.

Before the next step, write down: how many elements does each one move if you drain a 100,000-item queue completely?

Lesson 3 showed that the obvious guess can be wrong. So does this one.