Loading...
Implement the stack contract with preallocated storage and an explicit item count. Treat capacity, stored None values and rejected operations as separate concerns.
What you'll be able to do
A stack removes the most recently added item first: last in, first out. A fixed-capacity implementation reserves a list of a specified length rather than calling append indefinitely. In this version, count is the number of active items; active indices are 0 through count−1. The next insertion position is count, and the top item is at count−1 when the stack is nonempty.
The invariant is 0≤count≤capacity and len(storage)=capacity. Empty means count=0; full means count=capacity. Do not infer emptiness from a stored value of None, because None can itself be a legitimate data item. The representation’s count tells us which slots are active, while unused slots merely hold a clearing value.
push checks full before writing. On success it stores the new value at storage[count] and increments count. pop checks empty before changing the count, decrements count, retrieves the old top and clears that unused slot. peek returns the same top value without changing count or order. The empty check must precede an access at count−1, or Python’s negative indexing could accidentally read the final physical slot.
Overflow raises OverflowError and underflow raises IndexError in this teaching API. These are interface choices that callers can handle deliberately. A failed push must not overwrite the existing top; a failed pop must not make count negative. Validate that initial capacity is a positive integer and reject bool, which otherwise passes many simple integer checks in Python.
With capacity two, pushing red then blue makes blue the top. peek returns blue while leaving both items present. Two pops return blue then red. A third pop raises underflow, and the stack stays empty. An independent full test should attempt a third push while red and blue are still present and confirm that both remain in the same order after rejection.
Each ordinary operation uses O(1) indexed work and count updates under the list model, with O(capacity) reserved storage. Clearing a popped slot releases this structure’s reference to the item; it does not forcibly delete the object everywhere else. Treat the list and count as implementation details behind the methods. A later refactor can change the internal representation while preserving the documented operation behaviour.
class FixedStack:
def __init__(self, capacity):
if type(capacity) is not int or capacity <= 0:
raise ValueError('Capacity must be a positive integer')
self.storage = [None] * capacity
self.count = 0
def is_empty(self):
return self.count == 0
def is_full(self):
return self.count == len(self.storage)
def push(self, value):
if self.is_full():
raise OverflowError('Stack full')
self.storage[self.count] = value
self.count += 1
def pop(self):
if self.is_empty():
raise IndexError('Stack empty')
self.count -= 1
value = self.storage[self.count]
self.storage[self.count] = None
return value
def peek(self):
if self.is_empty():
raise IndexError('Stack empty')
return self.storage[self.count - 1]
def __len__(self):
return self.count
stack = FixedStack(2)
stack.push('red')
stack.push('blue')
print(stack.peek(), len(stack))
print(stack.pop(), stack.pop())
try:
stack.pop()
except IndexError:
print('empty')Scroll horizontally to see the full code or table.Attempt the task before opening its worked response. Record each change of state, explain the rule used, and check the result against the original requirements. Code examples labelled Python 3 use that language’s conventions; pseudocode states its own assumptions.
Common mistakes to avoid
Key takeaways
Test yourself
Answer a few questions, then review anything you missed.
Start with the quiz above to check the key ideas. You can also choose another topic from the practice library.